Attackcanceller fixes and improvements (#7698)

This commit is contained in:
Alex 2025-09-16 18:00:30 +02:00 committed by GitHub
parent 4822d94667
commit 32f8464fec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 860 additions and 777 deletions

View File

@ -724,14 +724,12 @@
.byte \mode .byte \mode
.endm .endm
.macro trysetrest failInstr:req .macro trysetrest
.byte 0x81 .byte 0x81
.4byte \failInstr
.endm .endm
.macro jumpifnotfirstturn jumpInstr:req .macro unused_0x82
.byte 0x82 .byte 0x82
.4byte \jumpInstr
.endm .endm
.macro unused_0x83 .macro unused_0x83
@ -748,9 +746,8 @@
.byte \id .byte \id
.endm .endm
.macro stockpiletobasedamage failInstr:req .macro stockpiletobasedamage
.byte 0x86 .byte 0x86
.4byte \failInstr
.endm .endm
.macro stockpiletohpheal failInstr:req .macro stockpiletohpheal failInstr:req
@ -1045,9 +1042,8 @@
.byte 0xc2 .byte 0xc2
.endm .endm
.macro trysetfutureattack failInstr:req .macro setfutureattack
.byte 0xc3 .byte 0xc3
.4byte \failInstr
.endm .endm
.macro trydobeatup endInstr, failInstr .macro trydobeatup endInstr, failInstr
@ -1224,10 +1220,8 @@
.4byte \jumpInstr .4byte \jumpInstr
.endm .endm
.macro jumpifnotcurrentmoveargtype battler:req, failInstr:req .macro unused_0xE4
.byte 0xe4 .byte 0xe4
.byte \battler
.4byte \failInstr
.endm .endm
.macro pickup .macro pickup
@ -1378,12 +1372,6 @@
.4byte \failInstr .4byte \failInstr
.endm .endm
.macro jumpifcantfling battler:req, jumpInstr:req
callnative BS_JumpIfCantFling
.byte \battler
.4byte \jumpInstr
.endm
.macro itemstatchangeeffects battler:req .macro itemstatchangeeffects battler:req
callnative BS_RunStatChangeItems callnative BS_RunStatChangeItems
.byte \battler .byte \battler
@ -1438,10 +1426,6 @@
.4byte \failInstr .4byte \failInstr
.endm .endm
.macro setglaiverush
callnative BS_SetGlaiveRush
.endm
.macro setpledge jumpInstr:req .macro setpledge jumpInstr:req
callnative BS_SetPledge callnative BS_SetPledge
.4byte \jumpInstr .4byte \jumpInstr
@ -2179,11 +2163,6 @@
.4byte \failInstr .4byte \failInstr
.endm .endm
.macro suckerpunchcheck failInstr:req
callnative BS_SuckerPunchCheck
.4byte \failInstr
.endm
.macro setsimplebeam failInstr:req .macro setsimplebeam failInstr:req
callnative BS_SetSimpleBeam callnative BS_SetSimpleBeam
.4byte \failInstr .4byte \failInstr
@ -2218,11 +2197,6 @@
.byte \case_ .byte \case_
.endm .endm
.macro trylastresort failInstr:req
callnative BS_TryLastResort
.4byte \failInstr
.endm
.macro tryautotomize failInstr:req .macro tryautotomize failInstr:req
callnative BS_TryAutotomize callnative BS_TryAutotomize
.4byte \failInstr .4byte \failInstr
@ -2411,13 +2385,8 @@
.4byte \failInstr .4byte \failInstr
.endm .endm
.macro checkpoltergeist failInstr:req .macro setpoltergeistmessage failInstr:req
callnative BS_CheckPoltergeist callnative BS_SetPoltergeistMessage
.4byte \failInstr
.endm
.macro trynoretreat failInstr:req
callnative BS_TryNoRetreat
.4byte \failInstr .4byte \failInstr
.endm .endm

View File

@ -210,7 +210,7 @@ BattleScript_EffectDoodleMoveEnd:
BattleScript_EffectGlaiveRush:: BattleScript_EffectGlaiveRush::
call BattleScript_EffectHit_Ret call BattleScript_EffectHit_Ret
jumpifmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_TryFaintMon jumpifmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_TryFaintMon
setglaiverush setvolatile BS_ATTACKER, VOLATILE_GLAIVE_RUSH, 2
goto BattleScript_TryFaintMon goto BattleScript_TryFaintMon
BattleScript_SyrupBombActivates:: BattleScript_SyrupBombActivates::
@ -685,7 +685,6 @@ BattleScript_SkyDropFlyingAlreadyConfused:
BattleScript_EffectFling:: BattleScript_EffectFling::
attackcanceler attackcanceler
jumpifcantfling BS_ATTACKER, BattleScript_ButItFailed
setlastuseditem BS_ATTACKER setlastuseditem BS_ATTACKER
accuracycheck BattleScript_FlingMissed, ACC_CURR_MOVE accuracycheck BattleScript_FlingMissed, ACC_CURR_MOVE
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
@ -776,11 +775,6 @@ BattleScript_FlingMissed:
removeitem BS_ATTACKER removeitem BS_ATTACKER
goto BattleScript_MoveMissedPause 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:: BattleScript_EffectClangorousSoul::
attackcanceler attackcanceler
cutonethirdhpandraisestats BattleScript_ButItFailed cutonethirdhpandraisestats BattleScript_ButItFailed
@ -819,7 +813,7 @@ BattleScript_OctlockTurnDmgEnd:
BattleScript_EffectPoltergeist:: BattleScript_EffectPoltergeist::
attackcanceler attackcanceler
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
checkpoltergeist BattleScript_ButItFailed setpoltergeistmessage BattleScript_ButItFailed
printstring STRINGID_ABOUTTOUSEPOLTERGEIST printstring STRINGID_ABOUTTOUSEPOLTERGEIST
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
goto BattleScript_HitFromCritCalc goto BattleScript_HitFromCritCalc
@ -844,7 +838,8 @@ BattleScript_TryTarShot:
BattleScript_EffectNoRetreat:: BattleScript_EffectNoRetreat::
attackcanceler attackcanceler
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
trynoretreat BattleScript_ButItFailed jumpifvolatile BS_TARGET, VOLATILE_NO_RETREAT, BattleScript_ButItFailed
setvolatile BS_TARGET, VOLATILE_NO_RETREAT
attackanimation attackanimation
waitanimation waitanimation
call BattleScript_AllStatsUp call BattleScript_AllStatsUp
@ -901,7 +896,6 @@ BattleScript_MoveEffectLightScreen::
BattleScript_EffectStuffCheeks:: BattleScript_EffectStuffCheeks::
attackcanceler attackcanceler
jumpifnotberry BS_ATTACKER, BattleScript_ButItFailed
attackanimation attackanimation
waitanimation waitanimation
setbyte sBERRY_OVERRIDE, 1 setbyte sBERRY_OVERRIDE, 1
@ -1049,12 +1043,6 @@ BattleScript_EffectFairyLock::
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_FailIfNotArgType::
attackcanceler
jumpifnotcurrentmoveargtype BS_ATTACKER, BattleScript_ButItFailed
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
goto BattleScript_HitFromCritCalc
BattleScript_RemoveFireType:: BattleScript_RemoveFireType::
printstring STRINGID_ATTACKERLOSTFIRETYPE printstring STRINGID_ATTACKERLOSTFIRETYPE
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
@ -1747,12 +1735,6 @@ BattleScript_ShellSmashTrySpeed:
BattleScript_ShellSmashEnd: BattleScript_ShellSmashEnd:
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectLastResort::
attackcanceler
trylastresort BattleScript_ButItFailed
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
goto BattleScript_HitFromCritCalc
BattleScript_EffectGrowth:: BattleScript_EffectGrowth::
attackcanceler attackcanceler
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_GrowthDoMoveAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_GrowthDoMoveAnim
@ -2064,12 +2046,6 @@ BattleScript_EffectSimpleBeam::
tryendneutralizinggas tryendneutralizinggas
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectSuckerPunch::
attackcanceler
suckerpunchcheck BattleScript_ButItFailed
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
goto BattleScript_HitFromAtkString
BattleScript_EffectLuckyChant:: BattleScript_EffectLuckyChant::
attackcanceler attackcanceler
setluckychant BattleScript_ButItFailed setluckychant BattleScript_ButItFailed
@ -2577,7 +2553,7 @@ BattleScript_AbilityProtectsDoesntAffect::
setmoveresultflags MOVE_RESULT_FAILED setmoveresultflags MOVE_RESULT_FAILED
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_InsomniaProtects: BattleScript_InsomniaProtects::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
printstring STRINGID_PKMNSTAYEDAWAKEUSING printstring STRINGID_PKMNSTAYEDAWAKEUSING
@ -2866,16 +2842,10 @@ BattleScript_EffectLightScreen::
BattleScript_EffectRest:: BattleScript_EffectRest::
attackcanceler 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 .if B_LEAF_GUARD_PREVENTS_REST >= GEN_5
jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest
.endif .endif
trysetrest BattleScript_AlreadyAtFullHp trysetrest
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
printfromtable gRestUsedStringIds printfromtable gRestUsedStringIds
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
@ -3288,10 +3258,6 @@ BattleScript_EffectPainSplit::
BattleScript_EffectSnore:: BattleScript_EffectSnore::
attackcanceler 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 jumpifhalfword CMP_EQUAL, gChosenMove, MOVE_SLEEP_TALK, BattleScript_DoSnore
printstring STRINGID_PKMNFASTASLEEP printstring STRINGID_PKMNFASTASLEEP
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
@ -3331,7 +3297,7 @@ BattleScript_EffectSketch::
BattleScript_EffectDestinyBond:: BattleScript_EffectDestinyBond::
attackcanceler attackcanceler
trysetdestinybond BattleScript_ButItFailed setvolatile BS_ATTACKER, VOLATILE_DESTINY_BOND, 2
attackanimation attackanimation
waitanimation waitanimation
printstring STRINGID_PKMNTRYINGTOTAKEFOE printstring STRINGID_PKMNTRYINGTOTAKEFOE
@ -3463,15 +3429,9 @@ BattleScript_DoGhostCurse::
tryfaintmon BS_ATTACKER tryfaintmon BS_ATTACKER
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectMatBlock::
attackcanceler
jumpifnotfirstturn BattleScript_ButItFailed
goto BattleScript_ProtectLikeAttack
BattleScript_EffectProtect:: BattleScript_EffectProtect::
BattleScript_EffectEndure:: BattleScript_EffectEndure::
attackcanceler attackcanceler
BattleScript_ProtectLikeAttack:
setprotectlike setprotectlike
attackanimation attackanimation
waitanimation waitanimation
@ -3785,7 +3745,7 @@ BattleScript_EffectMirrorCoat::
BattleScript_EffectFutureSight:: BattleScript_EffectFutureSight::
attackcanceler attackcanceler
trysetfutureattack BattleScript_ButItFailed setfutureattack
attackanimation attackanimation
waitanimation waitanimation
printfromtable gFutureMoveUsedStringIds printfromtable gFutureMoveUsedStringIds
@ -3880,11 +3840,6 @@ BattleScript_AlreadyAtFullHp::
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectFirstTurnOnly::
attackcanceler
jumpifnotfirstturn BattleScript_ButItFailed
goto BattleScript_EffectHit
BattleScript_FailedFromAtkCanceler:: BattleScript_FailedFromAtkCanceler::
attackcanceler attackcanceler
BattleScript_ButItFailed:: BattleScript_ButItFailed::
@ -3920,7 +3875,7 @@ BattleScript_EffectStockpile::
stockpile 0 stockpile 0
attackanimation attackanimation
waitanimation waitanimation
printfromtable gStockpileUsedStringIds printstring STRINGID_PKMNSTOCKPILED
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
.if B_STOCKPILE_RAISES_DEFS < GEN_4 .if B_STOCKPILE_RAISES_DEFS < GEN_4
goto BattleScript_EffectStockpileEnd goto BattleScript_EffectStockpileEnd
@ -3965,29 +3920,22 @@ BattleScript_EffectSpitUp::
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
damagecalc damagecalc
adjustdamage adjustdamage
stockpiletobasedamage BattleScript_SpitUpFail stockpiletobasedamage
call BattleScript_Hit_RetFromAtkAnimation call BattleScript_Hit_RetFromAtkAnimation
tryfaintmon BS_TARGET tryfaintmon BS_TARGET
removestockpilecounters 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 goto BattleScript_MoveEnd
BattleScript_SpitUpFailProtect:: BattleScript_SpitUpFailProtect::
pause B_WAIT_TIME_LONG pause B_WAIT_TIME_LONG
stockpiletobasedamage BattleScript_SpitUpFail stockpiletobasedamage
resultmessage resultmessage
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectSwallow:: BattleScript_EffectSwallow::
attackcanceler attackcanceler
stockpiletohpheal BattleScript_SwallowFail stockpiletohpheal BattleScript_ButItFailed
attackanimation attackanimation
waitanimation waitanimation
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
@ -3998,13 +3946,6 @@ BattleScript_EffectSwallow::
removestockpilecounters removestockpilecounters
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_SwallowFail::
pause B_WAIT_TIME_SHORT
printfromtable gSwallowFailStringIds
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectHail:: BattleScript_EffectHail::
attackcanceler attackcanceler
call BattleScript_CheckPrimalWeather call BattleScript_CheckPrimalWeather
@ -4112,9 +4053,6 @@ BattleScript_EffectFocusPunch::
BattleScript_EffectFollowMe:: BattleScript_EffectFollowMe::
attackcanceler attackcanceler
.if B_UPDATED_MOVE_DATA >= GEN_8
jumpifnotbattletype BATTLE_TYPE_DOUBLE, BattleScript_ButItFailed
.endif
setforcedtarget setforcedtarget
attackanimation attackanimation
waitanimation waitanimation
@ -4324,7 +4262,8 @@ BattleScript_EffectRefresh::
BattleScript_EffectGrudge:: BattleScript_EffectGrudge::
attackcanceler attackcanceler
trysetvolatile BS_ATTACKER, VOLATILE_GRUDGE, BattleScript_ButItFailed jumpifvolatile BS_ATTACKER, VOLATILE_GRUDGE, BattleScript_ButItFailed
setvolatile BS_ATTACKER, VOLATILE_GRUDGE, 2
attackanimation attackanimation
waitanimation waitanimation
printstring STRINGID_PKMNWANTSGRUDGE printstring STRINGID_PKMNWANTSGRUDGE
@ -7246,8 +7185,10 @@ BattleScript_DazzlingProtected::
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_MoveUsedPsychicTerrainPrevents:: BattleScript_MoveUsedPsychicTerrainPrevents::
printstring STRINGID_POKEMONCANNOTUSEMOVE pause B_WAIT_TIME_SHORT
printstring STRINGID_PSYCHICTERRAINPREVENTS
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
setmoveresultflags MOVE_RESULT_NO_EFFECT
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_GrassyTerrainHeals:: BattleScript_GrassyTerrainHeals::
@ -8396,11 +8337,6 @@ BattleScript_TryFaint:
tryfaintmon BS_TARGET tryfaintmon BS_TARGET
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectSteelRoller::
attackcanceler
jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ButItFailed
goto BattleScript_HitFromAccCheck
BattleScript_RemoveTerrain:: BattleScript_RemoveTerrain::
removeterrain removeterrain
playanimation BS_ATTACKER, B_ANIM_RESTORE_BG playanimation BS_ATTACKER, B_ANIM_RESTORE_BG

View File

@ -93,14 +93,21 @@ Contains more fundamental functions that control the flow of the battle. Functio
### data/battle_scripts_1.s ### 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: 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 attackcanceler
jumpifnotfirstturn BattleScript_ButItFailed jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects
goto BattleScript_EffectHit 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. 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.

View File

@ -113,7 +113,6 @@ struct DisableStruct
u8 usedMoves:4; u8 usedMoves:4;
u8 truantCounter:1; u8 truantCounter:1;
u8 truantSwitchInHack:1; u8 truantSwitchInHack:1;
u8 noRetreat:1;
u8 tarShot:1; u8 tarShot:1;
u8 octolock:1; u8 octolock:1;
u8 cudChew:1; u8 cudChew:1;
@ -123,6 +122,7 @@ struct DisableStruct
u8 usedProteanLibero:1; u8 usedProteanLibero:1;
u8 flashFireBoosted:1; u8 flashFireBoosted:1;
u8 boosterEnergyActivated:1; u8 boosterEnergyActivated:1;
u8 padding1:1;
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching) u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
u8 roostActive:1; u8 roostActive:1;
u8 unburdenActive:1; u8 unburdenActive:1;
@ -130,9 +130,9 @@ struct DisableStruct
u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case 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 unnerveActivated:1; // Unnerve and As One (Unnerve part) activate only once per switch in
u8 hazardsDone:1; u8 hazardsDone:1;
u8 padding1:1; u8 padding2:1;
u8 octolockedBy:3; 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 // Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects

View File

@ -155,6 +155,7 @@ u32 CountPositiveStatStages(u32 battlerId);
u32 CountNegativeStatStages(u32 battlerId); u32 CountNegativeStatStages(u32 battlerId);
// move checks // move checks
bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData);
bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect); bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category); bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category);
enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo); enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);

View File

@ -11,7 +11,6 @@ u16 GetNonDynamaxHP(u32 battler);
u16 GetNonDynamaxMaxHP(u32 battler); u16 GetNonDynamaxMaxHP(u32 battler);
void UndoDynamax(u32 battler); void UndoDynamax(u32 battler);
bool32 IsMoveBlockedByMaxGuard(u32 move); bool32 IsMoveBlockedByMaxGuard(u32 move);
bool32 IsMoveBlockedByDynamax(u32 move);
u16 GetMaxMove(u32 battler, u32 baseMove); u16 GetMaxMove(u32 battler, u32 baseMove);
u32 GetMaxMovePower(u32 move); u32 GetMaxMovePower(u32 move);

View File

@ -332,7 +332,6 @@ extern const u8 BattleScript_MistySurgeActivates[];
extern const u8 BattleScript_ElectricSurgeActivates[]; extern const u8 BattleScript_ElectricSurgeActivates[];
extern const u8 BattleScript_EffectSpectralThief[]; extern const u8 BattleScript_EffectSpectralThief[];
extern const u8 BattleScript_EffectLifeDew[]; extern const u8 BattleScript_EffectLifeDew[];
extern const u8 BattleScript_EffectSteelRoller[];
extern const u8 BattleScript_AbilityRaisesDefenderStat[]; extern const u8 BattleScript_AbilityRaisesDefenderStat[];
extern const u8 BattleScript_PowderMoveNoEffect[]; extern const u8 BattleScript_PowderMoveNoEffect[];
extern const u8 BattleScript_GrassyTerrainHeals[]; extern const u8 BattleScript_GrassyTerrainHeals[];
@ -597,6 +596,8 @@ extern const u8 BattleScript_EffectConversion[];
extern const u8 BattleScript_EffectRestoreHp[]; extern const u8 BattleScript_EffectRestoreHp[];
extern const u8 BattleScript_EffectLightScreen[]; extern const u8 BattleScript_EffectLightScreen[];
extern const u8 BattleScript_EffectRest[]; extern const u8 BattleScript_EffectRest[];
extern const u8 BattleScript_RestIsAlreadyAsleep[];
extern const u8 BattleScript_InsomniaProtects[];
extern const u8 BattleScript_EffectOHKO[]; extern const u8 BattleScript_EffectOHKO[];
extern const u8 BattleScript_EffectHealBlock[]; extern const u8 BattleScript_EffectHealBlock[];
extern const u8 BattleScript_RecoilIfMiss[]; extern const u8 BattleScript_RecoilIfMiss[];
@ -677,7 +678,6 @@ extern const u8 BattleScript_EffectBeatUp[];
extern const u8 BattleScript_EffectSemiInvulnerable[]; extern const u8 BattleScript_EffectSemiInvulnerable[];
extern const u8 BattleScript_EffectDefenseCurl[]; extern const u8 BattleScript_EffectDefenseCurl[];
extern const u8 BattleScript_EffectSoftboiled[]; extern const u8 BattleScript_EffectSoftboiled[];
extern const u8 BattleScript_EffectFirstTurnOnly[];
extern const u8 BattleScript_EffectStockpile[]; extern const u8 BattleScript_EffectStockpile[];
extern const u8 BattleScript_EffectSpitUp[]; extern const u8 BattleScript_EffectSpitUp[];
extern const u8 BattleScript_EffectSwallow[]; extern const u8 BattleScript_EffectSwallow[];
@ -742,7 +742,6 @@ extern const u8 BattleScript_EffectGuardSplit[];
extern const u8 BattleScript_EffectStickyWeb[]; extern const u8 BattleScript_EffectStickyWeb[];
extern const u8 BattleScript_EffectMetalBurst[]; extern const u8 BattleScript_EffectMetalBurst[];
extern const u8 BattleScript_EffectLuckyChant[]; extern const u8 BattleScript_EffectLuckyChant[];
extern const u8 BattleScript_EffectSuckerPunch[];
extern const u8 BattleScript_EffectSimpleBeam[]; extern const u8 BattleScript_EffectSimpleBeam[];
extern const u8 BattleScript_EffectEntrainment[]; extern const u8 BattleScript_EffectEntrainment[];
extern const u8 BattleScript_EffectHealPulse[]; extern const u8 BattleScript_EffectHealPulse[];
@ -761,7 +760,6 @@ extern const u8 BattleScript_EffectElectrify[];
extern const u8 BattleScript_EffectReflectType[]; extern const u8 BattleScript_EffectReflectType[];
extern const u8 BattleScript_EffectSoak[]; extern const u8 BattleScript_EffectSoak[];
extern const u8 BattleScript_EffectGrowth[]; extern const u8 BattleScript_EffectGrowth[];
extern const u8 BattleScript_EffectLastResort[];
extern const u8 BattleScript_EffectShellSmash[]; extern const u8 BattleScript_EffectShellSmash[];
extern const u8 BattleScript_EffectShiftGear[]; extern const u8 BattleScript_EffectShiftGear[];
extern const u8 BattleScript_EffectDefenseUp3[]; extern const u8 BattleScript_EffectDefenseUp3[];
@ -790,14 +788,12 @@ extern const u8 BattleScript_EffectAcupressure[];
extern const u8 BattleScript_EffectAromaticMist[]; extern const u8 BattleScript_EffectAromaticMist[];
extern const u8 BattleScript_EffectPowder[]; extern const u8 BattleScript_EffectPowder[];
extern const u8 BattleScript_EffectPartingShot[]; extern const u8 BattleScript_EffectPartingShot[];
extern const u8 BattleScript_EffectMatBlock[];
extern const u8 BattleScript_EffectInstruct[]; extern const u8 BattleScript_EffectInstruct[];
extern const u8 BattleScript_EffectLaserFocus[]; extern const u8 BattleScript_EffectLaserFocus[];
extern const u8 BattleScript_EffectMagneticFlux[]; extern const u8 BattleScript_EffectMagneticFlux[];
extern const u8 BattleScript_EffectGearUp[]; extern const u8 BattleScript_EffectGearUp[];
extern const u8 BattleScript_EffectStrengthSap[]; extern const u8 BattleScript_EffectStrengthSap[];
extern const u8 BattleScript_EffectPurify[]; extern const u8 BattleScript_EffectPurify[];
extern const u8 BattleScript_FailIfNotArgType[];
extern const u8 BattleScript_EffectShoreUp[]; extern const u8 BattleScript_EffectShoreUp[];
extern const u8 BattleScript_EffectGeomancy[]; extern const u8 BattleScript_EffectGeomancy[];
extern const u8 BattleScript_EffectFairyLock[]; extern const u8 BattleScript_EffectFairyLock[];
@ -814,7 +810,6 @@ extern const u8 BattleScript_MoveEffectLeechSeed[];
extern const u8 BattleScript_MoveEffectHaze[]; extern const u8 BattleScript_MoveEffectHaze[];
extern const u8 BattleScript_MoveEffectIonDeluge[]; extern const u8 BattleScript_MoveEffectIonDeluge[];
extern const u8 BattleScript_EffectHyperspaceFury[]; extern const u8 BattleScript_EffectHyperspaceFury[];
extern const u8 BattleScript_EffectAuraWheel[];
extern const u8 BattleScript_EffectNoRetreat[]; extern const u8 BattleScript_EffectNoRetreat[];
extern const u8 BattleScript_EffectTarShot[]; extern const u8 BattleScript_EffectTarShot[];
extern const u8 BattleScript_EffectPoltergeist[]; extern const u8 BattleScript_EffectPoltergeist[];
@ -855,5 +850,6 @@ extern const u8 BattleScript_SubmoveAttackstring[];
extern const u8 BattleScript_MetronomeAttackstring[]; extern const u8 BattleScript_MetronomeAttackstring[];
extern const u8 BattleScript_SleepTalkAttackstring[]; extern const u8 BattleScript_SleepTalkAttackstring[];
extern const u8 BattleScript_NaturePowerAttackstring[]; extern const u8 BattleScript_NaturePowerAttackstring[];
extern const u8 BattleScript_PokemonCantUseTheMove[];
#endif // GUARD_BATTLE_SCRIPTS_H #endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -7,7 +7,7 @@ bool32 CanTerastallize(u32 battler);
u32 GetBattlerTeraType(u32 battler); u32 GetBattlerTeraType(u32 battler);
void ExpendTypeStellarBoost(u32 battler, u32 type); void ExpendTypeStellarBoost(u32 battler, u32 type);
bool32 IsTypeStellarBoosted(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); u16 GetTeraTypeRGB(u32 type);

View File

@ -105,7 +105,7 @@ struct TypePower
enum MoveSuccessOrder enum MoveSuccessOrder
{ {
CANCELLER_FLAGS, CANCELLER_CLEAR_FLAGS,
CANCELLER_STANCE_CHANGE_1, CANCELLER_STANCE_CHANGE_1,
CANCELLER_SKY_DROP, CANCELLER_SKY_DROP,
CANCELLER_RECHARGE, CANCELLER_RECHARGE,
@ -130,10 +130,10 @@ enum MoveSuccessOrder
CANCELLER_ATTACKSTRING, CANCELLER_ATTACKSTRING,
CANCELLER_PPDEDUCTION, CANCELLER_PPDEDUCTION,
CANCELLER_WEATHER_PRIMAL, CANCELLER_WEATHER_PRIMAL,
CANCELLER_DYNAMAX_BLOCKED, CANCELLER_MOVE_FAILURE,
CANCELLER_POWDER_STATUS, CANCELLER_POWDER_STATUS,
CANCELLER_PRIORITY_BLOCK,
CANCELLER_PROTEAN, CANCELLER_PROTEAN,
CANCELLER_PSYCHIC_TERRAIN,
CANCELLER_EXPLODING_DAMP, CANCELLER_EXPLODING_DAMP,
CANCELLER_MULTIHIT_MOVES, CANCELLER_MULTIHIT_MOVES,
CANCELLER_MULTI_TARGET_MOVES, CANCELLER_MULTI_TARGET_MOVES,
@ -180,6 +180,15 @@ struct DamageContext
enum ItemHoldEffect holdEffectDef:16; 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 enum SleepClauseBlock
{ {
NOT_BLOCKED_BY_SLEEP_CLAUSE, NOT_BLOCKED_BY_SLEEP_CLAUSE,
@ -242,7 +251,7 @@ bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck);
u32 DoEndTurnEffects(void); u32 DoEndTurnEffects(void);
bool32 HandleFaintedMonActions(void); bool32 HandleFaintedMonActions(void);
void TryClearRageAndFuryCutter(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 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2);
bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility); bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility);
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option); 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);
u32 GetNaturePowerMove(u32 battler); u32 GetNaturePowerMove(u32 battler);
void RemoveAbilityFlags(u32 battler); void RemoveAbilityFlags(u32 battler);
bool32 IsDazzlingAbility(u32 ability);
#endif // GUARD_BATTLE_UTIL_H #endif // GUARD_BATTLE_UTIL_H

View File

@ -162,7 +162,7 @@ enum VolatileFlags
F(VOLATILE_RECHARGE, recharge, (u32, 1)) \ F(VOLATILE_RECHARGE, recharge, (u32, 1)) \
F(VOLATILE_RAGE, rage, (u32, 1)) \ F(VOLATILE_RAGE, rage, (u32, 1)) \
F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \ 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_ESCAPE_PREVENTION, escapePrevention, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \ F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \
F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \ 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_AQUA_RING, aquaRing, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_LASER_FOCUS, laserFocus, (u32, 1)) \ F(VOLATILE_LASER_FOCUS, laserFocus, (u32, 1)) \
F(VOLATILE_POWER_TRICK, powerTrick, (u32, 1), V_BATON_PASSABLE) \ 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_VESSEL_OF_RUIN, vesselOfRuin, (u32, 1)) \
F(VOLATILE_SWORD_OF_RUIN, swordOfRuin, (u32, 1)) \ F(VOLATILE_SWORD_OF_RUIN, swordOfRuin, (u32, 1)) \
F(VOLATILE_TABLETS_OF_RUIN, tabletsOfRuin, (u32, 1)) \ F(VOLATILE_TABLETS_OF_RUIN, tabletsOfRuin, (u32, 1)) \

View File

@ -113,7 +113,6 @@ enum StringID
STRINGID_PKMNCALMEDDOWN, STRINGID_PKMNCALMEDDOWN,
STRINGID_PKMNCANTSLEEPINUPROAR, STRINGID_PKMNCANTSLEEPINUPROAR,
STRINGID_PKMNSTOCKPILED, STRINGID_PKMNSTOCKPILED,
STRINGID_PKMNCANTSTOCKPILE,
STRINGID_PKMNCANTSLEEPINUPROAR2, STRINGID_PKMNCANTSLEEPINUPROAR2,
STRINGID_UPROARKEPTPKMNAWAKE, STRINGID_UPROARKEPTPKMNAWAKE,
STRINGID_PKMNSTAYEDAWAKEUSING, STRINGID_PKMNSTAYEDAWAKEUSING,
@ -239,8 +238,6 @@ enum StringID
STRINGID_STARTEDHAIL, STRINGID_STARTEDHAIL,
STRINGID_HAILCONTINUES, STRINGID_HAILCONTINUES,
STRINGID_HAILSTOPPED, STRINGID_HAILSTOPPED,
STRINGID_FAILEDTOSPITUP,
STRINGID_FAILEDTOSWALLOW,
STRINGID_STATCHANGESGONE, STRINGID_STATCHANGESGONE,
STRINGID_COINSSCATTERED, STRINGID_COINSSCATTERED,
STRINGID_TOOWEAKFORSUBSTITUTE, STRINGID_TOOWEAKFORSUBSTITUTE,
@ -858,20 +855,6 @@ enum UproarOverTurnStringID
B_MSG_UPROAR_ENDS, 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 // gKOFailedStringIds
enum KOFailedStringID enum KOFailedStringID
{ {

View File

@ -1141,6 +1141,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// check non-user target // check non-user target
if (!(moveTarget & MOVE_TARGET_USER)) if (!(moveTarget & MOVE_TARGET_USER))
{ {
if (Ai_IsPriorityBlocked(battlerAtk, battlerDef, move, aiData))
return TRUE;
if (CanAbilityBlockMove(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK)) if (CanAbilityBlockMove(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK))
RETURN_SCORE_MINUS(20); RETURN_SCORE_MINUS(20);
@ -2871,7 +2874,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_NO_RETREAT: case EFFECT_NO_RETREAT:
if (gDisableStructs[battlerAtk].noRetreat) if (gBattleMons[battlerAtk].volatiles.noRetreat)
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_EXTREME_EVOBOOST: case EFFECT_EXTREME_EVOBOOST:

View File

@ -535,6 +535,24 @@ bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffe
return TRUE; 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. // 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. // 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) 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)]; 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)) if (CanAbilityBlockMove(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, battlerDefAbility, ctx->move, AI_CHECK))
return TRUE; return TRUE;

View File

@ -234,21 +234,6 @@ bool32 IsMoveBlockedByMaxGuard(u32 move)
return FALSE; 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) static u16 GetTypeBasedMaxMove(u32 battler, u32 type)
{ {
// Gigantamax check // Gigantamax check

View File

@ -4840,7 +4840,9 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move)
priority++; priority++;
} }
else if (ability == ABILITY_TRIAGE && IsHealingMove(move)) else if (ability == ABILITY_TRIAGE && IsHealingMove(move))
{
priority += 3; priority += 3;
}
if (gProtectStructs[battler].quash) if (gProtectStructs[battler].quash)
priority = -8; priority = -8;

View File

@ -272,7 +272,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNCALMEDDOWN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} calmed down."), [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_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_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_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_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 [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_STARTEDHAIL] = COMPOUND_STRING("It started to hail!"),
[STRINGID_HAILCONTINUES] = COMPOUND_STRING("The hail is crashing down."), [STRINGID_HAILCONTINUES] = COMPOUND_STRING("The hail is crashing down."),
[STRINGID_HAILSTOPPED] = COMPOUND_STRING("The hail stopped."), [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_STATCHANGESGONE] = COMPOUND_STRING("All stat changes were eliminated!"),
[STRINGID_COINSSCATTERED] = COMPOUND_STRING("Coins were scattered everywhere!"), [STRINGID_COINSSCATTERED] = COMPOUND_STRING("Coins were scattered everywhere!"),
[STRINGID_TOOWEAKFORSUBSTITUTE] = COMPOUND_STRING("But it does not have enough HP left to make a substitute!"), [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_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_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_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_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_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!"), [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 [B_MSG_UPROAR_ENDS] = STRINGID_PKMNCALMEDDOWN
}; };
const u16 gStockpileUsedStringIds[] =
{
[B_MSG_STOCKPILED] = STRINGID_PKMNSTOCKPILED,
[B_MSG_CANT_STOCKPILE] = STRINGID_PKMNCANTSTOCKPILE,
};
const u16 gWokeUpStringIds[] = const u16 gWokeUpStringIds[] =
{ {
[B_MSG_WOKE_UP] = STRINGID_PKMNWOKEUP, [B_MSG_WOKE_UP] = STRINGID_PKMNWOKEUP,
[B_MSG_WOKE_UP_UPROAR] = STRINGID_PKMNWOKEUPINUPROAR [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[] = const u16 gUproarAwakeStringIds[] =
{ {
[B_MSG_CANT_SLEEP_UPROAR] = STRINGID_PKMNCANTSLEEPINUPROAR2, [B_MSG_CANT_SLEEP_UPROAR] = STRINGID_PKMNCANTSLEEPINUPROAR2,

View File

@ -467,7 +467,7 @@ static void Cmd_setreflect(void);
static void Cmd_setseeded(void); static void Cmd_setseeded(void);
static void Cmd_manipulatedamage(void); static void Cmd_manipulatedamage(void);
static void Cmd_trysetrest(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_unused_0x83(void);
static void Cmd_jumpifuproarwakes(void); static void Cmd_jumpifuproarwakes(void);
static void Cmd_stockpile(void); static void Cmd_stockpile(void);
@ -507,7 +507,7 @@ static void Cmd_settypetorandomresistance(void);
static void Cmd_setalwayshitflag(void); static void Cmd_setalwayshitflag(void);
static void Cmd_copymovepermanently(void); static void Cmd_copymovepermanently(void);
static void Cmd_unused_0xA9(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_trysetdestinybondtohappen(void);
static void Cmd_settailwind(void); static void Cmd_settailwind(void);
static void Cmd_tryspiteppreduce(void); static void Cmd_tryspiteppreduce(void);
@ -532,7 +532,7 @@ static void Cmd_unused_0xBF(void);
static void Cmd_recoverbasedonsunlight(void); static void Cmd_recoverbasedonsunlight(void);
static void Cmd_setstickyweb(void); static void Cmd_setstickyweb(void);
static void Cmd_selectfirstvalidtarget(void); static void Cmd_selectfirstvalidtarget(void);
static void Cmd_trysetfutureattack(void); static void Cmd_setfutureattack(void);
static void Cmd_trydobeatup(void); static void Cmd_trydobeatup(void);
static void Cmd_setsemiinvulnerablebit(void); static void Cmd_setsemiinvulnerablebit(void);
static void Cmd_tryfiretwoturnmovenowbyeffect(void); static void Cmd_tryfiretwoturnmovenowbyeffect(void);
@ -565,7 +565,7 @@ static void Cmd_trysetsnatch(void);
static void Cmd_unused2(void); static void Cmd_unused2(void);
static void Cmd_switchoutabilities(void); static void Cmd_switchoutabilities(void);
static void Cmd_jumpifhasnohp(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_pickup(void);
static void Cmd_unused_0xE6(void); static void Cmd_unused_0xE6(void);
static void Cmd_unused_0xE7(void); static void Cmd_unused_0xE7(void);
@ -726,7 +726,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_setseeded, //0x7F Cmd_setseeded, //0x7F
Cmd_manipulatedamage, //0x80 Cmd_manipulatedamage, //0x80
Cmd_trysetrest, //0x81 Cmd_trysetrest, //0x81
Cmd_jumpifnotfirstturn, //0x82 Cmd_unused_0x82, //0x82
Cmd_unused_0x83, //0x83 Cmd_unused_0x83, //0x83
Cmd_jumpifuproarwakes, //0x84 Cmd_jumpifuproarwakes, //0x84
Cmd_stockpile, //0x85 Cmd_stockpile, //0x85
@ -766,7 +766,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_setalwayshitflag, //0xA7 Cmd_setalwayshitflag, //0xA7
Cmd_copymovepermanently, //0xA8 Cmd_copymovepermanently, //0xA8
Cmd_unused_0xA9, //0xA9 Cmd_unused_0xA9, //0xA9
Cmd_trysetdestinybond, //0xAA Cmd_unused_AA, //0xAA
Cmd_trysetdestinybondtohappen, //0xAB Cmd_trysetdestinybondtohappen, //0xAB
Cmd_settailwind, //0xAC Cmd_settailwind, //0xAC
Cmd_tryspiteppreduce, //0xAD Cmd_tryspiteppreduce, //0xAD
@ -791,7 +791,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_recoverbasedonsunlight, //0xC0 Cmd_recoverbasedonsunlight, //0xC0
Cmd_setstickyweb, //0xC1 Cmd_setstickyweb, //0xC1
Cmd_selectfirstvalidtarget, //0xC2 Cmd_selectfirstvalidtarget, //0xC2
Cmd_trysetfutureattack, //0xC3 Cmd_setfutureattack, //0xC3
Cmd_trydobeatup, //0xC4 Cmd_trydobeatup, //0xC4
Cmd_setsemiinvulnerablebit, //0xC5 Cmd_setsemiinvulnerablebit, //0xC5
Cmd_tryfiretwoturnmovenowbyeffect, //0xC6 Cmd_tryfiretwoturnmovenowbyeffect, //0xC6
@ -824,7 +824,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_unused2, //0xE1 Cmd_unused2, //0xE1
Cmd_switchoutabilities, //0xE2 Cmd_switchoutabilities, //0xE2
Cmd_jumpifhasnohp, //0xE3 Cmd_jumpifhasnohp, //0xE3
Cmd_jumpifnotcurrentmoveargtype, //0xE4 Cmd_unused_0xE4, //0xE4
Cmd_pickup, //0xE5 Cmd_pickup, //0xE5
Cmd_unused_0xE6, //0xE6 Cmd_unused_0xE6, //0xE6
Cmd_unused_0xE7, //0xE7 Cmd_unused_0xE7, //0xE7
@ -1040,23 +1040,23 @@ u32 NumFaintedBattlersByAttacker(u32 battlerAtk)
return numMonsFainted; return numMonsFainted;
} }
bool32 IsMovePowderBlocked(u32 battlerAtk, u32 battlerDef, u32 move) bool32 IsMovePowderBlocked(struct BattleContext *ctx)
{ {
bool32 effect = FALSE; bool32 effect = FALSE;
if (IsPowderMove(move) && (battlerAtk != battlerDef)) if (IsPowderMove(ctx->currentMove) && (ctx->battlerAtk != ctx->battlerDef))
{ {
if (B_POWDER_GRASS >= GEN_6 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; gBattlerAbility = ctx->battlerDef;
RecordAbilityBattle(gBattlerTarget, ABILITY_OVERCOAT); RecordAbilityBattle(ctx->battlerDef, ABILITY_OVERCOAT);
effect = TRUE; 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); RecordItemEffectBattle(ctx->battlerDef, HOLD_EFFECT_SAFETY_GOGGLES);
gLastUsedItem = gBattleMons[battlerDef].item; gLastUsedItem = gBattleMons[ctx->battlerDef].item;
effect = TRUE; effect = TRUE;
} }
@ -1103,22 +1103,30 @@ static void Cmd_attackcanceler(void)
return; 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) if (!IsBattlerAlive(gBattlerAttacker)
&& effect != EFFECT_EXPLOSION && ctx.moveEffect != EFFECT_EXPLOSION
&& effect != EFFECT_MISTY_EXPLOSION) && ctx.moveEffect != EFFECT_MISTY_EXPLOSION)
{ {
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
gBattlescriptCurrInstr = BattleScript_MoveEnd; gBattlescriptCurrInstr = BattleScript_MoveEnd;
return; 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; return;
if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF
&& GetBattlerAbility(gBattlerAttacker) == ABILITY_PARENTAL_BOND && ctx.ability[ctx.battlerAtk] == ABILITY_PARENTAL_BOND
&& IsMoveAffectedByParentalBond(gCurrentMove, gBattlerAttacker) && IsMoveAffectedByParentalBond(gCurrentMove, gBattlerAttacker)
&& !(gAbsentBattlerFlags & (1u << gBattlerTarget)) && !(gAbsentBattlerFlags & (1u << gBattlerTarget))
&& GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE)
@ -1129,44 +1137,43 @@ static void Cmd_attackcanceler(void)
return; return;
} }
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
if (CanAbilityBlockMove( if (CanAbilityBlockMove(
gBattlerAttacker, ctx.battlerAtk,
gBattlerTarget, ctx.battlerDef,
GetBattlerAbility(gBattlerAttacker), ctx.ability[ctx.battlerAtk],
abilityDef, ctx.ability[ctx.battlerDef],
gCurrentMove, ctx.currentMove,
RUN_SCRIPT)) RUN_SCRIPT))
return; return;
if (GetMoveNonVolatileStatus(gCurrentMove) == MOVE_EFFECT_PARALYSIS) if (GetMoveNonVolatileStatus(ctx.currentMove) == MOVE_EFFECT_PARALYSIS)
{ {
if (CanAbilityAbsorbMove( if (CanAbilityAbsorbMove(
gBattlerAttacker, ctx.battlerAtk,
gBattlerTarget, ctx.battlerDef,
abilityDef, ctx.ability[ctx.battlerDef],
gCurrentMove, ctx.currentMove,
GetBattleMoveType(gCurrentMove), GetBattleMoveType(ctx.currentMove),
RUN_SCRIPT)) RUN_SCRIPT))
return; return;
} }
if (IsMovePowderBlocked(gBattlerAttacker, gBattlerTarget, gCurrentMove)) if (IsMovePowderBlocked(&ctx))
return; return;
// Check if no available target present on the field or if Sky Battles ban the move // Check if no available target present on the field or if Sky Battles ban the move
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove) if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
&& (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) && (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)))
|| (IsMoveNotAllowedInSkyBattles(gCurrentMove))) || (IsMoveNotAllowedInSkyBattles(gCurrentMove)))
{ {
gBattleStruct->noTargetPresent = TRUE; 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; gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem;
else else
gBattlescriptCurrInstr = BattleScript_ButItFailed; 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); CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
return; return;
} }
@ -1197,7 +1204,7 @@ static void Cmd_attackcanceler(void)
{ {
u32 battler = gBattlerTarget; u32 battler = gBattlerTarget;
if (abilityDef == ABILITY_MAGIC_BOUNCE) if (ctx.ability[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE)
{ {
battler = gBattlerTarget; battler = gBattlerTarget;
gBattleStruct->bouncedMoveIsUsed = TRUE; gBattleStruct->bouncedMoveIsUsed = TRUE;
@ -1257,11 +1264,11 @@ static void Cmd_attackcanceler(void)
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
} }
else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove)
&& (effect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) && (ctx.moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
&& (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) && (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))
&& effect != EFFECT_SUCKER_PUNCH && ctx.moveEffect != EFFECT_SUCKER_PUNCH
&& effect != EFFECT_COUNTER && ctx.moveEffect != EFFECT_COUNTER
&& effect != EFFECT_UPPER_HAND) && ctx.moveEffect != EFFECT_UPPER_HAND)
{ {
if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove)) if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove))
gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE;
@ -3238,7 +3245,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
gBattlescriptCurrInstr++; gBattlescriptCurrInstr++;
break; break;
case MOVE_EFFECT_PREVENT_ESCAPE: 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; gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE;
gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; 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!"); DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
// #endif // #endif
} }
if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0)
gBattleMons[gBattlerAttacker].volatiles.destinyBond--;
gProtectStructs[gBattlerAttacker].shellTrap = FALSE; gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE; gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE;
gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE; gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE;
@ -7572,7 +7582,7 @@ static void UpdateSentMonFlags(u32 battler)
static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId) static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId)
{ {
gBattleMons[battler].volatiles.destinyBond = FALSE; gBattleMons[battler].volatiles.destinyBond = 0;
gHitMarker &= ~HITMARKER_DESTINYBOND; gHitMarker &= ~HITMARKER_DESTINYBOND;
gBattleScripting.battler = battler; gBattleScripting.battler = battler;
gBattleCommunication[MULTISTRING_CHOOSER] = multistringId; gBattleCommunication[MULTISTRING_CHOOSER] = multistringId;
@ -9659,17 +9669,12 @@ static void Cmd_manipulatedamage(void)
static void Cmd_trysetrest(void) static void Cmd_trysetrest(void)
{ {
CMD_ARGS(const u8 *failInstr); CMD_ARGS();
const u8 *failInstr = cmd->failInstr;
gBattlerTarget = gBattlerAttacker; gBattlerTarget = gBattlerAttacker;
gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP * (-1); gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP * (-1);
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN))
{
gBattlescriptCurrInstr = failInstr;
}
else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN))
{ {
gBattlescriptCurrInstr = BattleScript_ElectricTerrainPrevents; 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) static void Cmd_unused_0x83(void)
@ -9752,19 +9749,10 @@ static void Cmd_stockpile(void)
switch (cmd->id) switch (cmd->id)
{ {
case 0: 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].stockpileCounter++;
gDisableStructs[gBattlerAttacker].stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF]; gDisableStructs[gBattlerAttacker].stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF];
gDisableStructs[gBattlerAttacker].stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF]; gDisableStructs[gBattlerAttacker].stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF];
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter); PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STOCKPILED;
}
break; break;
case 1: // Save def/sp def stats. case 1: // Save def/sp def stats.
if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
@ -9780,21 +9768,13 @@ static void Cmd_stockpile(void)
static void Cmd_stockpiletobasedamage(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) if (gBattleCommunication[MISS_TYPE] != B_MSG_PROTECTED)
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter; gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
} }
}
static void Cmd_stockpiletohpheal(void) static void Cmd_stockpiletohpheal(void)
{ {
@ -9802,19 +9782,11 @@ static void Cmd_stockpiletohpheal(void)
const u8 *failInstr = cmd->failInstr; const u8 *failInstr = cmd->failInstr;
if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed)
{
gBattlescriptCurrInstr = failInstr;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FAILED;
}
else
{
if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp) if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp)
{ {
gDisableStructs[gBattlerAttacker].stockpileCounter = 0; gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
gBattlescriptCurrInstr = failInstr; gBattlescriptCurrInstr = failInstr;
gBattlerTarget = gBattlerAttacker; gBattlerTarget = gBattlerAttacker;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FULL_HP;
} }
else else
{ {
@ -9837,7 +9809,6 @@ static void Cmd_stockpiletohpheal(void)
gBattlerTarget = gBattlerAttacker; gBattlerTarget = gBattlerAttacker;
} }
} }
}
void BS_RemoveStockpileCounters(void) void BS_RemoveStockpileCounters(void)
{ {
@ -11488,23 +11459,8 @@ static inline bool32 IsDanamaxMonPresent(void)
return FALSE; 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) static void TrySetDestinyBondToHappen(void)
@ -12231,16 +12187,10 @@ static void Cmd_selectfirstvalidtarget(void)
gBattlescriptCurrInstr = cmd->nextInstr; 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;
}
else
{
gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK; gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK;
gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove; gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove;
gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker;
@ -12254,7 +12204,6 @@ static void Cmd_trysetfutureattack(void)
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
} }
}
static void Cmd_trydobeatup(void) static void Cmd_trydobeatup(void)
{ {
@ -13054,18 +13003,8 @@ static void Cmd_jumpifhasnohp(void)
gBattlescriptCurrInstr = cmd->nextInstr; 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) 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) void BS_JumpIfMoreThanHalfHP(void)
{ {
NATIVE_ARGS(u8 battler, const u8 *jumpInstr); 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) void BS_SetPledge(void)
{ {
NATIVE_ARGS(const u8 *jumpInstr); 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) void BS_SetSimpleBeam(void)
{ {
NATIVE_ARGS(const u8 *failInstr); NATIVE_ARGS(const u8 *failInstr);
@ -17183,15 +17091,6 @@ void BS_HandleFormChange(void)
gBattlescriptCurrInstr = cmd->nextInstr; 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) void BS_TryAutotomize(void)
{ {
NATIVE_ARGS(const u8 *failInstr); NATIVE_ARGS(const u8 *failInstr);
@ -17441,8 +17340,7 @@ void BS_SetAuroraVeil(void)
{ {
NATIVE_ARGS(); NATIVE_ARGS();
u32 side = GetBattlerSide(gBattlerAttacker); u32 side = GetBattlerSide(gBattlerAttacker);
if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL)
|| !(HasWeatherEffect() && gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)))
{ {
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattleCommunication[MULTISTRING_CHOOSER] = 0;
@ -17877,9 +17775,7 @@ void BS_CutOneThirdHpAndRaiseStats(void)
{ {
NATIVE_ARGS(const u8 *failInstr); NATIVE_ARGS(const u8 *failInstr);
bool8 atLeastOneStatBoosted = FALSE; bool32 atLeastOneStatBoosted = FALSE;
u16 hpFraction = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3);
for (u32 stat = 1; stat < NUM_STATS; stat++) for (u32 stat = 1; stat < NUM_STATS; stat++)
{ {
if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN)) if (CompareStat(gBattlerAttacker, stat, MAX_STAT_STAGE, CMP_LESS_THAN))
@ -17888,9 +17784,9 @@ void BS_CutOneThirdHpAndRaiseStats(void)
break; break;
} }
} }
if (atLeastOneStatBoosted && gBattleMons[gBattlerAttacker].hp > hpFraction) if (atLeastOneStatBoosted)
{ {
gBattleStruct->moveDamage[gBattlerAttacker] = hpFraction; gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3);
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
} }
else else
@ -17899,37 +17795,13 @@ void BS_CutOneThirdHpAndRaiseStats(void)
} }
} }
void BS_CheckPoltergeist(void) void BS_SetPoltergeistMessage(void)
{ {
NATIVE_ARGS(const u8 *failInstr); 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); PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].item);
gLastUsedItem = gBattleMons[gBattlerTarget].item; gLastUsedItem = gBattleMons[gBattlerTarget].item;
gBattlescriptCurrInstr = cmd->nextInstr; 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;
}
}
void BS_CureCertainStatuses(void) void BS_CureCertainStatuses(void)
{ {

View File

@ -132,20 +132,19 @@ bool32 IsTypeStellarBoosted(u32 battler, u32 type)
// Returns the STAB power multiplier to use when Terastallized. // Returns the STAB power multiplier to use when Terastallized.
// Power multipliers from Smogon Research thread. // 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); u32 teraType = GetBattlerTeraType(ctx->battlerAtk);
bool32 hasAdaptability = (GetBattlerAbility(battler) == ABILITY_ADAPTABILITY);
// Safety check. // Safety check.
if (GetActiveGimmick(battler) != GIMMICK_TERA) if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_TERA)
return UQ_4_12(1.0); return UQ_4_12(1.0);
// Stellar-type checks. // Stellar-type checks.
if (teraType == TYPE_STELLAR) if (teraType == TYPE_STELLAR)
{ {
bool32 shouldBoost = IsTypeStellarBoosted(battler, type); bool32 shouldBoost = IsTypeStellarBoosted(ctx->battlerAtk, ctx->moveType);
if (IS_BATTLER_OF_BASE_TYPE(battler, type)) if (IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
{ {
if (shouldBoost) if (shouldBoost)
return UQ_4_12(2.0); return UQ_4_12(2.0);
@ -158,18 +157,18 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
return UQ_4_12(1.0); return UQ_4_12(1.0);
} }
// Base and Tera type. // 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); return UQ_4_12(2.25);
else else
return UQ_4_12(2.0); return UQ_4_12(2.0);
} }
// Base or Tera type only. // Base or Tera type only.
else if ((type == teraType && !IS_BATTLER_OF_BASE_TYPE(battler, type)) else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|| (type != teraType && IS_BATTLER_OF_BASE_TYPE(battler, type))) || (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); return UQ_4_12(2.0);
else else
return UQ_4_12(1.5); return UQ_4_12(1.5);

File diff suppressed because it is too large Load Diff

View File

@ -819,7 +819,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_FIRST_TURN_ONLY] = [EFFECT_FIRST_TURN_ONLY] =
{ {
.battleScript = BattleScript_EffectFirstTurnOnly, .battleScript = BattleScript_EffectHit,
.battleTvScore = 4, .battleTvScore = 4,
.encourageEncore = TRUE, .encourageEncore = TRUE,
}, },
@ -1392,7 +1392,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_SUCKER_PUNCH] = [EFFECT_SUCKER_PUNCH] =
{ {
.battleScript = BattleScript_EffectSuckerPunch, .battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
}, },
@ -1531,7 +1531,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_LAST_RESORT] = [EFFECT_LAST_RESORT] =
{ {
.battleScript = BattleScript_EffectLastResort, .battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
}, },
@ -1721,7 +1721,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_MAT_BLOCK] = [EFFECT_MAT_BLOCK] =
{ {
.battleScript = BattleScript_EffectMatBlock, .battleScript = BattleScript_EffectProtect,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
.encourageEncore = TRUE, .encourageEncore = TRUE,
}, },
@ -1774,7 +1774,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_FAIL_IF_NOT_ARG_TYPE] = [EFFECT_FAIL_IF_NOT_ARG_TYPE] =
{ {
.battleScript = BattleScript_FailIfNotArgType, .battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
}, },
@ -1881,7 +1881,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_AURA_WHEEL] = [EFFECT_AURA_WHEEL] =
{ {
.battleScript = BattleScript_EffectAuraWheel, .battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
}, },
@ -2233,7 +2233,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_STEEL_ROLLER] = [EFFECT_STEEL_ROLLER] =
{ {
.battleScript = BattleScript_EffectSteelRoller, .battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points .battleTvScore = 0, // TODO: Assign points
}, },

View File

@ -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);
}
}

View File

@ -44,6 +44,7 @@ SINGLE_BATTLE_TEST("Teraform Zero can be replaced")
PLAYER(SPECIES_TERAPAGOS); PLAYER(SPECIES_TERAPAGOS);
OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); } OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); }
} WHEN { } WHEN {
TURN { MOVE(opponent, MOVE_POUND); }
TURN { MOVE(opponent, MOVE_WORRY_SEED); MOVE(player, MOVE_REST, gimmick: GIMMICK_TERA); } TURN { MOVE(opponent, MOVE_WORRY_SEED); MOVE(player, MOVE_REST, gimmick: GIMMICK_TERA); }
} SCENE { } SCENE {
MESSAGE("The opposing Whimsicott used Worry Seed!"); MESSAGE("The opposing Whimsicott used Worry Seed!");

View File

@ -903,7 +903,7 @@ SINGLE_BATTLE_TEST("Dynamax: Max Mindstorm sets up Psychic Terrain")
} SCENE { } SCENE {
MESSAGE("The opposing Wobbuffet used Extreme Speed!"); MESSAGE("The opposing Wobbuffet used Extreme Speed!");
MESSAGE("Wobbuffet used Max Mindstorm!"); 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!"); 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-lowering Max Moves, without showing a message")
TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-increasing Max Moves, without showing a message") TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-increasing Max Moves, without showing a message")

View File

@ -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_GENERAL, B_ANIM_ZMOVE_ACTIVATE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_GENESIS_SUPERNOVA, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_GENESIS_SUPERNOVA, player);
NOT { ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, 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!");
} }
} }

View File

@ -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 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 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") TO_DO_BATTLE_TEST("Aurora Veil's damage reduction is ignored by Critical Hits")

View File

@ -1,11 +1,52 @@
#include "global.h" #include "global.h"
#include "test/battle.h" #include "test/battle.h"
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Attack by 1 stage"); SINGLE_BATTLE_TEST("Clangorous Soul cuts the user's HP by 1/3")
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"); s16 dmg;
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Sp. Defense by 1 stage"); GIVEN {
TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Speed by 1 stage"); PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); };
TO_DO_BATTLE_TEST("Clangorous Soul cuts the user's HP by 1/3"); 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 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");

View File

@ -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") SINGLE_BATTLE_TEST("Burn Up fails if the user has Protean/Libero and is not a Fire-type")
{ {
KNOWN_FAILING;
GIVEN { GIVEN {
WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_6); WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_6);
PLAYER(SPECIES_REGIROCK); PLAYER(SPECIES_REGIROCK);

View File

@ -2,3 +2,60 @@
#include "test/battle.h" #include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write No Retreat (Move Effect) test titles") 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);
}
}
}

View File

@ -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); } TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_QUICK_ATTACK); }
} SCENE { } SCENE {
MESSAGE("Claydol used Psychic Terrain!"); 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); } NOT { HP_BAR(opponent); }
MESSAGE("The opposing Wobbuffet used Quick Attack!"); MESSAGE("The opposing Wobbuffet used Quick Attack!");
HP_BAR(player); 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 { GIVEN {
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); HP(1); } 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!"); 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);
}
}

View File

@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Stockpile's count can go up only to 3")
MESSAGE("Wobbuffet stockpiled 3!"); MESSAGE("Wobbuffet stockpiled 3!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player); 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 { } SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, move, player); NOT ANIMATION(ANIM_TYPE_MOVE, move, player);
if (move == MOVE_SWALLOW) if (move == MOVE_SWALLOW)
MESSAGE("But it failed to swallow a thing!"); MESSAGE("But it failed!");
else else
MESSAGE("But it failed to spit up a thing!"); MESSAGE("But it failed!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player);
MESSAGE("Wobbuffet stockpiled 1!"); MESSAGE("Wobbuffet stockpiled 1!");