Merge branch 'rh-hideout-master'

This commit is contained in:
RoamerX 2025-09-19 16:06:45 +08:00
commit db9e97e2f0
65 changed files with 1646 additions and 428 deletions

View File

@ -1050,7 +1050,7 @@
.4byte \failInstr
.endm
.macro trydobeatup endInstr, failInstr
.macro trydobeatup endInstr:req, failInstr:req
.byte 0xc4
.4byte \endInstr
.4byte \failInstr

View File

@ -1585,7 +1585,7 @@ BattleScript_MoveEffectFlameBurst::
healthbarupdate BS_SCRIPTING
datahpupdate BS_SCRIPTING
tryfaintmon BS_SCRIPTING
goto BattleScript_MoveEnd
return
BattleScript_EffectPowerTrick::
attackcanceler
@ -1673,7 +1673,7 @@ BattleScript_DefogDoAnim::
BattleScript_DefogPrintString::
printfromtable gStatDownStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_DefogTryHazards::
BattleScript_DefogTryHazards:
copybyte gEffectBattler, gBattlerAttacker
trydefog TRUE, NULL
copybyte gBattlerAttacker, gEffectBattler
@ -1683,6 +1683,12 @@ BattleScript_DefogTryHazardsWithAnim:
waitanimation
goto BattleScript_DefogTryHazards
BattleScript_MoveEffectDefog::
saveattacker
trydefog TRUE, NULL
restoreattacker
return
BattleScript_EffectCopycat::
attackcanceler
attackstring
@ -2217,6 +2223,10 @@ BattleScript_EffectEntrainment::
setlastusedability
printstring STRINGID_PKMNACQUIREDABILITY
waitmessage B_WAIT_TIME_LONG
trytoclearprimalweather
tryrevertweatherform
flushtextbox
tryendneutralizinggas
goto BattleScript_MoveEnd
BattleScript_EffectSimpleBeam::
@ -2292,6 +2302,9 @@ BattleScript_EffectHealingWishGen4:
switchindataupdate BS_ATTACKER
hpthresholds BS_ATTACKER
trytoclearprimalweather
tryrevertweatherform
flushtextbox
tryendneutralizinggas
flushtextbox
printstring STRINGID_SWITCHINMON
switchinanim BS_ATTACKER, FALSE, TRUE
@ -2604,8 +2617,11 @@ BattleScript_EffectMiracleEye::
ppreduce
setvolatile BS_TARGET, VOLATILE_MIRACLE_EYE
goto BattleScript_IdentifiedFoe
BattleScript_EffectGravity::
call BattleScript_EffectGravityInternal
goto BattleScript_MoveEnd
BattleScript_EffectGravityInternal:
attackcanceler
attackstring
ppreduce
@ -2631,7 +2647,7 @@ BattleScript_GravityLoopEnd:
moveendcase MOVEEND_TARGET_VISIBLE
jumpifnexttargetvalid BattleScript_GravityLoop
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectRoost::
attackcanceler
@ -2756,6 +2772,13 @@ BattleScript_TerrainPreventsEnd2::
waitmessage B_WAIT_TIME_LONG
end2
BattleScript_ImmunityProtectedEnd2::
call BattleScript_AbilityPopUp
pause B_WAIT_TIME_SHORT
printfromtable gStatusPreventionStringIds
waitmessage B_WAIT_TIME_LONG
end2
BattleScript_ElectricTerrainPrevents::
pause B_WAIT_TIME_SHORT
printstring STRINGID_ELECTRICTERRAINPREVENTS
@ -3303,6 +3326,9 @@ BattleScript_EffectTransform::
attackstring
ppreduce
trytoclearprimalweather
tryrevertweatherform
flushtextbox
tryendneutralizinggas
flushtextbox
transformdataexecution
attackanimation
@ -3347,11 +3373,15 @@ BattleScript_EffectReflect::
BattleScript_PrintReflectLightScreenSafeguardString::
attackanimation
waitanimation
BattleScript_EffectAuroraVeilSuccess::
printfromtable gReflectLightScreenSafeguardStringIds
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_MoveEffectAuroraVeil::
printfromtable gReflectLightScreenSafeguardStringIds
waitmessage B_WAIT_TIME_LONG
return
BattleScript_VoltAbsorbHeal:
copybyte gBattlerAbility, gBattlerTarget
tryhealquarterhealth BS_TARGET, BattleScript_MonMadeMoveUseless @ Check if max hp
@ -3732,13 +3762,13 @@ BattleScript_EffectSpite::
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
@ TODO: Simplfy script
BattleScript_EffectHealBell::
attackcanceler
attackstring
ppreduce
attackanimation
waitanimation
BattleScript_EffectHealBell_FromHeal::
healpartystatus
waitstate
printfromtable gPartyStatusHealStringIds
@ -3758,6 +3788,15 @@ BattleScript_PartyHealEnd::
waitstate
goto BattleScript_MoveEnd
BattleScript_MoveEffectAromatherapy::
healpartystatus
waitstate
printfromtable gPartyStatusHealStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_ATTACKER_WITH_PARTNER
waitstate
return
BattleScript_EffectMeanLook::
attackcanceler
attackstring
@ -4247,15 +4286,6 @@ BattleScript_DoEffectTeleport::
BattleScript_EffectBeatUp::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
.if B_BEAT_UP >= GEN_5
attackstring
ppreduce
critcalc
damagecalc
adjustdamage
trydobeatup
goto BattleScript_HitFromAtkAnimation
.else
attackstring
pause B_WAIT_TIME_SHORT
ppreduce
@ -4285,7 +4315,6 @@ BattleScript_BeatUpAttack::
goto BattleScript_BeatUpLoop
BattleScript_BeatUpEnd::
end
.endif
BattleScript_EffectDefenseCurl::
attackcanceler
@ -4522,6 +4551,7 @@ BattleScript_EffectNonVolatileStatus::
attackanimation
waitanimation
setnonvolatilestatus TRIGGER_ON_MOVE
clearmoveresultflags MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE
resultmessage
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
@ -4763,8 +4793,8 @@ BattleScript_BrickBreakDoHit::
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
setadditionaleffects
tryfaintmon BS_TARGET
setadditionaleffects
goto BattleScript_MoveEnd
BattleScript_EffectYawn::
@ -4776,11 +4806,15 @@ BattleScript_EffectYawn::
setyawn BattleScript_ButItFailed
attackanimation
waitanimation
BattleScript_EffectYawnSuccess::
printstring STRINGID_PKMNWASMADEDROWSY
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_MoveEffectYawnSide::
printstring STRINGID_PKMNWASMADEDROWSY
waitmessage B_WAIT_TIME_LONG
return
BattleScript_PrintAbilityMadeIneffective::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
@ -5042,6 +5076,9 @@ BattleScript_FaintAttacker::
dofaintanimation BS_ATTACKER
printstring STRINGID_ATTACKERFAINTED
cleareffectsonfaint BS_ATTACKER
trytoclearprimalweather
tryrevertweatherform
flushtextbox
waitanimation
tryactivatesoulheart
tryactivatereceiver BS_ATTACKER
@ -5057,6 +5094,9 @@ BattleScript_FaintTarget::
dofaintanimation BS_TARGET
printstring STRINGID_TARGETFAINTED
cleareffectsonfaint BS_TARGET
trytoclearprimalweather
tryrevertweatherform
flushtextbox
waitanimation
tryactivatesoulheart
tryactivatereceiver BS_TARGET
@ -6577,6 +6617,7 @@ BattleScript_CudChewActivates::
BattleScript_ApplyDisguiseFormChangeHPLoss::
jumpifgenconfiglowerthan GEN_CONFIG_DISGUISE_HP_LOSS, GEN_8, BattleScript_ApplyDisguiseFormChangeHPLossReturn
orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE
healthbarupdate BS_SCRIPTING
datahpupdate BS_SCRIPTING
BattleScript_ApplyDisguiseFormChangeHPLossReturn:
@ -6701,7 +6742,7 @@ BattleScript_MoveUsedWokeUp::
BattleScript_MonWokeUpInUproar::
printstring STRINGID_PKMNWOKEUPINUPROAR
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_ATTACKER
updatestatusicon BS_EFFECT_BATTLER
end2
BattleScript_PoisonTurnDmg::
@ -6947,7 +6988,7 @@ BattleScript_UpdateEffectStatusIconRet::
flushtextbox
return
BattleScript_YawnMakesAsleep::
BattleScript_YawnMakesAsleepEnd2::
statusanimation BS_EFFECT_BATTLER
printstring STRINGID_PKMNFELLASLEEP
waitmessage B_WAIT_TIME_LONG
@ -7823,7 +7864,7 @@ BattleScript_FlinchPrevention::
call BattleScript_AbilityPopUp
printstring STRINGID_PKMNSXPREVENTSFLINCHING
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
return
BattleScript_OwnTempoPrevents::
pause B_WAIT_TIME_SHORT
@ -7912,7 +7953,7 @@ BattleScript_TeraShellDistortingTypeMatchups::
BattleScript_CursedBodyActivates::
call BattleScript_AbilityPopUp
printstring STRINGID_CUSEDBODYDISABLED
printstring STRINGID_CURSEDBODYDISABLED
waitmessage B_WAIT_TIME_LONG
return
@ -7928,6 +7969,10 @@ BattleScript_MummyActivates::
recordability BS_ATTACKER
printstring STRINGID_ATTACKERACQUIREDABILITY
waitmessage B_WAIT_TIME_LONG
trytoclearprimalweather
tryrevertweatherform
flushtextbox
tryendneutralizinggas
return
BattleScript_WanderingSpiritActivates::
@ -7997,11 +8042,12 @@ BattleScript_WeakArmorDefPrintString:
printstring STRINGID_TARGETABILITYSTATLOWER
waitmessage B_WAIT_TIME_LONG
BattleScript_WeakArmorActivatesSpeed:
.if B_WEAK_ARMOR_SPEED >= GEN_7
jumpifgenconfiglowerthan GEN_CONFIG_WEAK_ARMOR_SPEED, GEN_7, BattleScript_WeakArmorSetSpeedGen6
setstatchanger STAT_SPEED, 2, FALSE
.else
goto BattleScript_WeakArmorDoSpeed
BattleScript_WeakArmorSetSpeedGen6:
setstatchanger STAT_SPEED, 1, FALSE
.endif
BattleScript_WeakArmorDoSpeed:
statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_WeakArmorActivatesEnd
jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_WeakArmorSpeedPrintString
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_EMPTY, BattleScript_WeakArmorActivatesEnd
@ -9252,26 +9298,7 @@ BattleScript_TargetAbilityStatRaiseRet_End:
BattleScript_EffectMaxMove::
attackcanceler
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
attackstring
ppreduce
critcalc
damagecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
tryfaintmon BS_TARGET
setadditionaleffects
moveendall
end
goto BattleScript_HitFromAtkString
BattleScript_EffectRaiseStatAllies::
savetarget
@ -9287,7 +9314,7 @@ BattleScript_RaiseSideStatsIncrement:
setallytonexttarget BattleScript_RaiseSideStatsLoop
BattleScript_RaiseSideStatsEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectLowerStatFoes::
savetarget
@ -9303,26 +9330,26 @@ BattleScript_LowerSideStatsIncrement:
setallytonexttarget BattleScript_LowerSideStatsLoop
BattleScript_LowerSideStatsEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectSetWeather::
playanimation 0, B_ANIM_MAX_SET_WEATHER
printfromtable gMoveWeatherChangeStringIds
waitmessage B_WAIT_TIME_LONG
call BattleScript_ActivateWeatherAbilities
goto BattleScript_MoveEnd
return
BattleScript_EffectSetTerrain::
printfromtable gTerrainStringIds
waitmessage B_WAIT_TIME_LONG
playanimation BS_ATTACKER, B_ANIM_RESTORE_BG
call BattleScript_ActivateTerrainEffects
goto BattleScript_MoveEnd
return
BattleScript_DamageNonTypesStarts::
printfromtable gDamageNonTypesStartStringIds
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
return
BattleScript_DamageNonTypesContinues::
printfromtable gDamageNonTypesDmgStringIds
@ -9335,7 +9362,7 @@ BattleScript_EffectTryReducePP::
tryspiteppreduce BattleScript_MoveEnd
printstring STRINGID_PKMNREDUCEDPP
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
return
BattleScript_EffectParalyzeSide::
savetarget
@ -9343,18 +9370,12 @@ BattleScript_EffectParalyzeSide::
BattleScript_ParalyzeSideLoop:
jumpifabsent BS_TARGET, BattleScript_ParalyzeSideIncrement
trysetparalysis BattleScript_ParalyzeSideIncrement
statusanimation BS_TARGET
updatestatusicon BS_TARGET
printfromtable gStatusConditionsStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_EFFECT_BATTLER
waitstate
BattleScript_ParalyzeSideIncrement:
jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_ParalyzeSideEnd
setallytonexttarget BattleScript_ParalyzeSideLoop
BattleScript_ParalyzeSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectPoisonSide::
savetarget
@ -9362,18 +9383,12 @@ BattleScript_EffectPoisonSide::
BattleScript_PoisonSideLoop:
jumpifabsent BS_TARGET, BattleScript_PoisonSideIncrement
trysetpoison BattleScript_PoisonSideIncrement
statusanimation BS_TARGET
updatestatusicon BS_TARGET
printfromtable gStatusConditionsStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_EFFECT_BATTLER
waitstate
BattleScript_PoisonSideIncrement:
jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_PoisonSideEnd
setallytonexttarget BattleScript_PoisonSideLoop
BattleScript_PoisonSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectPoisonParalyzeSide::
savetarget
@ -9381,18 +9396,12 @@ BattleScript_EffectPoisonParalyzeSide::
BattleScript_PoisonParalyzeSideLoop:
jumpifabsent BS_TARGET, BattleScript_PoisonParalyzeSideIncrement
trysetpoisonparalysis BattleScript_PoisonParalyzeSideIncrement
statusanimation BS_TARGET
updatestatusicon BS_TARGET
printfromtable gStatusConditionsStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_EFFECT_BATTLER
waitstate
BattleScript_PoisonParalyzeSideIncrement:
jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_PoisonParalyzeSideEnd
setallytonexttarget BattleScript_PoisonParalyzeSideLoop
BattleScript_PoisonParalyzeSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectEffectSporeSide::
savetarget
@ -9400,18 +9409,12 @@ BattleScript_EffectEffectSporeSide::
BattleScript_EffectSporeSideLoop:
jumpifabsent BS_TARGET, BattleScript_EffectSporeSideIncrement
tryseteffectspore BattleScript_EffectSporeSideIncrement
statusanimation BS_TARGET
updatestatusicon BS_TARGET
printfromtable gStatusConditionsStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_EFFECT_BATTLER
waitstate
BattleScript_EffectSporeSideIncrement:
jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_EffectSporeSideEnd
setallytonexttarget BattleScript_EffectSporeSideLoop
BattleScript_EffectSporeSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectConfuseSide::
savetarget
@ -9429,11 +9432,11 @@ BattleScript_ConfuseSideIncrement:
BattleScript_ConfuseSideEnd:
restoretarget
jumpifbyte CMP_EQUAL, gBattleCommunication + 1, 1, BattleScript_PrintCoinsScattered @ Gold Rush
goto BattleScript_MoveEnd
return
BattleScript_PrintCoinsScattered:
printstring STRINGID_COINSSCATTERED
goto BattleScript_MoveEnd
return
BattleScript_EffectInfatuateSide::
savetarget
@ -9450,7 +9453,7 @@ BattleScript_InfatuateSideIncrement:
setallytonexttarget BattleScript_InfatuateSideLoop
BattleScript_InfatuateSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectTormentSide::
savetarget
@ -9466,7 +9469,7 @@ BattleScript_TormentSideIncrement:
setallytonexttarget BattleScript_TormentSideLoop
BattleScript_TormentSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_TormentEnds::
printstring STRINGID_TORMENTEDNOMORE
@ -9487,7 +9490,7 @@ BattleScript_MeanLookSideIncrement:
setallytonexttarget BattleScript_MeanLookSideLoop
BattleScript_MeanLookSideEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectRaiseCritAlliesAnim::
savetarget
@ -9503,7 +9506,7 @@ BattleScript_RaiseCritAlliesIncrement:
setallytonexttarget BattleScript_RaiseCritAlliesLoop
BattleScript_RaiseCritAlliesEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectHealOneSixthAllies::
jumpifteamhealthy BattleScript_MoveEnd
@ -9522,7 +9525,7 @@ BattleScript_HealOneSixthAlliesIncrement:
setallytonexttarget BattleScript_HealOneSixthAlliesLoop
BattleScript_HealOneSixthAlliesEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectRecycleBerriesAllies::
savetarget
@ -9539,13 +9542,13 @@ BattleScript_RecycleBerriesAlliesIncrement:
setallytonexttarget BattleScript_RecycleBerriesAlliesLoop
BattleScript_RecycleBerriesAlliesEnd:
restoretarget
goto BattleScript_MoveEnd
return
BattleScript_EffectSteelsurge::
setsteelsurge BattleScript_MoveEnd
printfromtable gDmgHazardsStringIds
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
return
@@@ END MAX MOVES @@@
@ -9682,7 +9685,7 @@ BattleScript_SleepClauseBlocked::
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_SleepClausePreventsEnd::
BattleScript_SleepClausePreventsEnd2::
pause B_WAIT_TIME_SHORT
printstring STRINGID_BLOCKEDBYSLEEPCLAUSE
waitmessage B_WAIT_TIME_LONG

View File

@ -130,16 +130,16 @@ 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 endured:1;
u8 octolockedBy:3;
u8 padding2:5;
u8 tryEjectPack:1;
u8 padding:4;
};
// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects
struct ProtectStruct
{
u32 protected:7; // 126 protect options
u32 endured:1;
u32 noValidMoves:1;
u32 helpingHand:1;
u32 bounceMove:1;
@ -155,26 +155,26 @@ struct ProtectStruct
u32 statRaised:1;
u32 usedCustapBerry:1; // also quick claw
u32 touchedProtectLike:1;
u32 unused:8;
u32 disableEjectPack:1;
u32 pranksterElevated:1;
u32 quickDraw:1;
u32 beakBlastCharge:1;
u32 quash:1;
u32 shellTrap:1;
u32 eatMirrorHerb:1;
u32 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
// End of 32-bit bitfield
u16 disableEjectPack:1;
u16 tryEjectPack:1;
u16 pranksterElevated:1;
u16 quickDraw:1;
u16 beakBlastCharge:1;
u16 quash:1;
u16 shellTrap:1;
u16 eatMirrorHerb:1;
u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
u16 usedAllySwitch:1;
u16 lashOutAffected:1;
u16 assuranceDoubled:1;
u16 padding:3;
u16 myceliumMight:1;
u16 laggingTail:1;
u16 padding:11;
// End of 16-bit bitfield
u16 physicalDmg;
u16 specialDmg;
u8 physicalBattlerId;
u8 specialBattlerId;
u8 physicalBattlerId:4;
u8 specialBattlerId:4;
};
// Cleared at the start of HandleAction_ActionFinished
@ -737,6 +737,7 @@ struct BattleStruct
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
u16 beatUpSpecies[PARTY_SIZE];
u8 attackerBeforeBounce:2;
u8 beatUpSlot:3;
u8 pledgeMove:1;

View File

@ -150,7 +150,7 @@ extern const u8 BattleScript_TargetWokeUp[];
extern const u8 BattleScript_TargetBurnHeal[];
extern const u8 BattleScript_TargetPoisonHealed[];
extern const u8 BattleScript_MoveEffectSleep[];
extern const u8 BattleScript_YawnMakesAsleep[];
extern const u8 BattleScript_YawnMakesAsleepEnd2[];
extern const u8 BattleScript_MoveEffectPoison[];
extern const u8 BattleScript_MoveEffectBurn[];
extern const u8 BattleScript_MoveEffectFrostbite[];
@ -424,6 +424,7 @@ extern const u8 BattleScript_EjectPackActivates[];
extern const u8 BattleScript_MentalHerbCureRet[];
extern const u8 BattleScript_MentalHerbCureEnd2[];
extern const u8 BattleScript_TerrainPreventsEnd2[];
extern const u8 BattleScript_ImmunityProtectedEnd2[];
extern const u8 BattleScript_MistyTerrainPrevents[];
extern const u8 BattleScript_ElectricTerrainPrevents[];
extern const u8 BattleScript_DoesntAffectTargetAtkString[];
@ -518,7 +519,7 @@ extern const u8 BattleScript_BoosterEnergyEnd2[];
extern const u8 BattleScript_BoosterEnergyRet[];
extern const u8 BattleScript_TeraShellDistortingTypeMatchups[];
extern const u8 BattleScript_TeraFormChange[];
extern const u8 BattleScript_SleepClausePreventsEnd[];
extern const u8 BattleScript_SleepClausePreventsEnd2[];
extern const u8 BattleScript_PowerConstruct[];
extern const u8 BattleScript_AbilityProtectsDoesntAffect[];
extern const u8 BattleScript_ImmunityProtected[];
@ -551,10 +552,10 @@ extern const u8 BattleScript_EffectStonesurge[];
extern const u8 BattleScript_EffectSteelsurge[];
extern const u8 BattleScript_DamageNonTypesStarts[];
extern const u8 BattleScript_DamageNonTypesContinues[];
extern const u8 BattleScript_DefogTryHazards[];
extern const u8 BattleScript_EffectAuroraVeilSuccess[];
extern const u8 BattleScript_MoveEffectDefog[];
extern const u8 BattleScript_MoveEffectAuroraVeil[];
extern const u8 BattleScript_EffectGravitySuccess[];
extern const u8 BattleScript_EffectYawnSuccess[];
extern const u8 BattleScript_MoveEffectYawnSide[];
extern const u8 BattleScript_EffectTryReducePP[];
extern const u8 BattleScript_EffectParalyzeSide[];
extern const u8 BattleScript_EffectPoisonSide[];
@ -649,7 +650,7 @@ extern const u8 BattleScript_EffectSleepTalk[];
extern const u8 BattleScript_EffectDestinyBond[];
extern const u8 BattleScript_EffectSpite[];
extern const u8 BattleScript_EffectHealBell[];
extern const u8 BattleScript_EffectHealBell_FromHeal[];
extern const u8 BattleScript_MoveEffectAromatherapy[];
extern const u8 BattleScript_EffectMeanLook[];
extern const u8 BattleScript_EffectNightmare[];
extern const u8 BattleScript_EffectMinimize[];

View File

@ -363,7 +363,7 @@ enum BattleWeather
#define B_WEATHER_LOW_LIGHT (B_WEATHER_FOG | B_WEATHER_ICY_ANY | B_WEATHER_RAIN | B_WEATHER_SANDSTORM)
#define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS)
// Explicit numbers until frostbite because those shouldn't be shifted
// Explicit numbers until frostbite because those shouldn't be shifted
enum __attribute__((packed)) MoveEffect
{
MOVE_EFFECT_NONE = 0,

View File

@ -480,7 +480,7 @@ enum StringID
STRINGID_HEALINGWISHCAMETRUE,
STRINGID_HEALINGWISHHEALED,
STRINGID_LUNARDANCECAMETRUE,
STRINGID_CUSEDBODYDISABLED,
STRINGID_CURSEDBODYDISABLED,
STRINGID_ATTACKERACQUIREDABILITY,
STRINGID_TARGETABILITYSTATLOWER,
STRINGID_TARGETSTATWONTGOHIGHER,

View File

@ -35,6 +35,12 @@ enum GenConfigTag
GEN_CONFIG_DISGUISE_HP_LOSS,
GEN_CONFIG_AFTER_YOU_TURN_ORDER,
GEN_CONFIG_HEALING_WISH_SWITCH,
GEN_CONFIG_MEGA_EVO_TURN_ORDER,
GEN_CONFIG_SHEER_COLD_IMMUNITY,
GEN_CONFIG_WEAK_ARMOR_SPEED,
GEN_CONFIG_PRANKSTER_DARK_TYPES,
GEN_CONFIG_DESTINY_BOND_FAIL,
GEN_CONFIG_POWDER_RAIN,
GEN_CONFIG_COUNT
};

View File

@ -38,6 +38,12 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
[GEN_CONFIG_DISGUISE_HP_LOSS] = B_DISGUISE_HP_LOSS,
[GEN_CONFIG_AFTER_YOU_TURN_ORDER] = B_AFTER_YOU_TURN_ORDER,
[GEN_CONFIG_HEALING_WISH_SWITCH] = B_HEALING_WISH_SWITCH,
[GEN_CONFIG_MEGA_EVO_TURN_ORDER] = B_MEGA_EVO_TURN_ORDER,
[GEN_CONFIG_SHEER_COLD_IMMUNITY] = B_SHEER_COLD_IMMUNITY,
[GEN_CONFIG_WEAK_ARMOR_SPEED] = B_WEAK_ARMOR_SPEED,
[GEN_CONFIG_PRANKSTER_DARK_TYPES] = B_PRANKSTER_DARK_TYPES,
[GEN_CONFIG_DESTINY_BOND_FAIL] = B_DESTINY_BOND_FAIL,
[GEN_CONFIG_POWDER_RAIN] = B_POWDER_RAIN,
};
#if TESTING

View File

@ -214,6 +214,7 @@ enum RandomTag
RNG_AI_ASSUME_ALL_STATUS,
RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN,
RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM,
RNG_WRAP,
};
#define RandomWeighted(tag, ...) \

View File

@ -19,6 +19,7 @@ SECTIONS {
{
__ewram_start = .;
*(.ewram*)
. = ALIGN(4);
__ewram_end = .;
} > EWRAM

View File

@ -1258,7 +1258,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
} // def partner ability checks
// gen7+ dark type mons immune to priority->elevated moves from prankster
if (B_PRANKSTER_DARK_TYPES >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)
if (GetGenConfig(GEN_CONFIG_PRANKSTER_DARK_TYPES) >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)
&& aiData->abilities[battlerAtk] == ABILITY_PRANKSTER && IsBattleMoveStatus(move)
&& !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER)))
RETURN_SCORE_MINUS(10);
@ -1702,7 +1702,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_TOXIC_THREAD:
if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPEED))
ADJUST_SCORE(-1); // may still want to just poison
//fallthrough
if (!AI_CanPoison(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;
case EFFECT_LIGHT_SCREEN:
if (gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)
|| (HasPartner(battlerAtk) && AreMovesEquivalent(battlerAtk, BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)))
@ -1720,7 +1722,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_SHEER_COLD:
if (B_SHEER_COLD_IMMUNITY >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE))
if (GetGenConfig(GEN_CONFIG_SHEER_COLD_IMMUNITY) >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE))
RETURN_SCORE_MINUS(20);
// fallthrough
case EFFECT_OHKO:
@ -2600,7 +2602,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
// This only happens if the ally already rolled on double trick room on final turn.
// Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out.
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter)
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1))
ADJUST_SCORE(PERFECT_EFFECT);
else
ADJUST_SCORE(-10);
@ -2611,7 +2613,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM))
ADJUST_SCORE(-10);
// Don't unset a trick room that doesn't harm you unless it's about to expire.
else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer != gBattleTurnCounter && !ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM))
else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1) && !ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM))
ADJUST_SCORE(-10);
}
break;
@ -2808,7 +2810,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_TAILWIND:
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_TAILWIND
|| PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_TAILWIND)
|| (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != gBattleTurnCounter))
|| (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1)))
ADJUST_SCORE(-10);
break;
case EFFECT_LUCKY_CHANT:
@ -3092,7 +3094,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)))
{
@ -3108,7 +3110,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (hasTwoOpponents)
{
// Might be about to die
if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtk), battlerAtk) && CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtkPartner), battlerAtk)
if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtk), battlerAtk) && CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtkPartner), battlerAtk)
&& AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)
&& AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtkPartner), move, predictedMove, DONT_CONSIDER_PRIORITY))
ADJUST_SCORE(GOOD_EFFECT);
@ -3130,14 +3132,14 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
else if (IsBattlerAlive(BATTLE_OPPOSITE(battlerAtkPartner)))
{
// Might be about to die
if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtkPartner), battlerAtk)
if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtkPartner), battlerAtk)
&& AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtkPartner), move, predictedMove, DONT_CONSIDER_PRIORITY))
ADJUST_SCORE(GOOD_EFFECT);
if (ownHitsToKOFoe2 > partnerHitsToKOFoe2 && partnerHitsToKOFoe2 > 1)
ADJUST_SCORE(GOOD_EFFECT);
}
}
}
break;
case EFFECT_PERISH_SONG:
@ -3173,15 +3175,15 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out.
// This unsets Trick Room and resets it with a full timer.
case EFFECT_TRICK_ROOM:
if (hasPartner && gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter
if (hasPartner && gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1)
&& ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)
&& HasMoveWithEffect(battlerAtkPartner, MOVE_TRICK_ROOM)
&& HasMoveWithEffect(battlerAtkPartner, EFFECT_TRICK_ROOM)
&& RandomPercentage(RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN, DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE))
ADJUST_SCORE(PERFECT_EFFECT);
break;
case EFFECT_TAILWIND:
// Anticipate both opponents protecting to stall out Trick Room, and apply Tailwind.
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1)
&& RandomPercentage(RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM, TAILWIND_IN_TRICK_ROOM_CHANCE))
ADJUST_SCORE(BEST_EFFECT);
break;
@ -5182,9 +5184,9 @@ 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))
else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1) && ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM))
ADJUST_SCORE(GOOD_EFFECT);
}
break;
@ -5292,7 +5294,7 @@ case EFFECT_GUARD_SPLIT:
break;
case EFFECT_TAILWIND:
{
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != gBattleTurnCounter)
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1))
break;
if (HasBattlerSideMoveWithEffect(battlerAtk, EFFECT_ELECTRO_BALL))
@ -5313,7 +5315,7 @@ case EFFECT_GUARD_SPLIT:
u32 partnerSpeed = aiData->speedStats[BATTLE_PARTNER(battlerAtk)];
u32 foe1Speed = aiData->speedStats[FOE(battlerAtk)];
u32 foe2Speed = aiData->speedStats[BATTLE_PARTNER(FOE(battlerAtk))];
if (speed <= foe1Speed && (speed * 2) > foe1Speed)
tailwindScore += 1;
if (speed <= foe2Speed && (speed * 2) > foe2Speed)

View File

@ -28,6 +28,17 @@ static u32 GetAIEffectGroup(enum BattleMoveEffects effect);
static u32 GetAIEffectGroupFromMove(u32 battler, u32 move);
// Functions
static u32 AI_GetMoldBreakerSanitizedAbility(u32 battlerAtk, u32 abilityAtk, u32 abilityDef, u32 holdEffectDef, u32 move)
{
if (MoveIgnoresTargetAbility(move))
return ABILITY_NONE;
if (holdEffectDef != HOLD_EFFECT_ABILITY_SHIELD && IsMoldBreakerTypeAbility(battlerAtk, abilityAtk))
return ABILITY_NONE;
return abilityDef;
}
static bool32 AI_IsDoubleSpreadMove(u32 battlerAtk, u32 move)
{
u32 numOfTargets = 0;
@ -896,10 +907,10 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
ctx.updateFlags = FALSE;
ctx.weather = weather;
ctx.fixedBasePower = SetFixedMoveBasePower(battlerAtk, move);
ctx.abilityAtk = aiData->abilities[battlerAtk];
ctx.abilityDef = aiData->abilities[battlerDef];
ctx.holdEffectAtk = aiData->holdEffects[battlerAtk];
ctx.holdEffectDef = aiData->holdEffects[battlerDef];
ctx.abilityAtk = aiData->abilities[battlerAtk];
ctx.abilityDef = AI_GetMoldBreakerSanitizedAbility(battlerAtk, ctx.abilityAtk, aiData->abilities[battlerDef], ctx.holdEffectDef, move);
ctx.typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(&ctx);
u32 movePower = GetMovePower(move);

View File

@ -763,8 +763,9 @@ static bool32 HandleEndTurnWrap(u32 battler)
if (gBattleMons[battler].volatiles.wrapped && IsBattlerAlive(battler))
{
if (--gDisableStructs[battler].wrapTurns != 0)
if (gDisableStructs[battler].wrapTurns != 0)
{
gDisableStructs[battler].wrapTurns--;
if (IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
return effect;
@ -1024,7 +1025,6 @@ static bool32 HandleEndTurnYawn(u32 battler)
&& !UproarWakeUpCheck(battler)
&& !IsLeafGuardProtected(battler, ability))
{
CancelMultiTurnMoves(battler, SKY_DROP_STATUS_YAWN);
gEffectBattler = gBattlerTarget = battler;
if (IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
{
@ -1038,7 +1038,15 @@ static bool32 HandleEndTurnYawn(u32 battler)
}
else if (IsSleepClauseActiveForSide(GetBattlerSide(battler)))
{
BattleScriptExecute(BattleScript_SleepClausePreventsEnd);
BattleScriptExecute(BattleScript_SleepClausePreventsEnd2);
}
else if ((gBattleScripting.battler = IsAbilityOnSide(battler, ABILITY_SWEET_VEIL)))
{
gBattleScripting.battler--;
gLastUsedAbility = ABILITY_SWEET_VEIL;
gBattlerAbility = gBattleScripting.battler;
RecordAbilityBattle(gBattleScripting.battler, ABILITY_SWEET_VEIL);
BattleScriptExecute(BattleScript_ImmunityProtectedEnd2);
}
else
{
@ -1047,10 +1055,11 @@ static bool32 HandleEndTurnYawn(u32 battler)
else
gBattleMons[battler].status1 |= ((Random() % 4) + 3);
CancelMultiTurnMoves(battler, SKY_DROP_STATUS_YAWN);
TryActivateSleepClause(battler, gBattlerPartyIndexes[battler]);
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
BattleScriptExecute(BattleScript_YawnMakesAsleep);
BattleScriptExecute(BattleScript_YawnMakesAsleepEnd2);
}
effect = TRUE;
}
@ -1361,25 +1370,22 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
case THIRD_EVENT_BLOCK_UPROAR:
if (gBattleMons[battler].volatiles.uproarTurns)
{
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++)
for (gEffectBattler = 0; gEffectBattler < gBattlersCount; gEffectBattler++)
{
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF)
if ((gBattleMons[gEffectBattler].status1 & STATUS1_SLEEP)
&& GetBattlerAbility(gEffectBattler) != ABILITY_SOUNDPROOF)
{
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP;
gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE;
gBattleMons[gEffectBattler].status1 &= ~STATUS1_SLEEP;
gBattleMons[gEffectBattler].volatiles.nightmare = FALSE;
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
BattleScriptExecute(BattleScript_MonWokeUpInUproar);
BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1);
MarkBattlerForControllerExec(gBattlerAttacker);
BtlController_EmitSetMonData(gEffectBattler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1);
MarkBattlerForControllerExec(gEffectBattler);
effect = TRUE;
break;
}
}
if (gBattlerAttacker != gBattlersCount)
{
break;
}
else
if (effect == FALSE)
{
gBattlerAttacker = battler;
gBattleMons[battler].volatiles.uproarTurns--; // uproar timer goes down

View File

@ -3197,6 +3197,9 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct));
if (GetProtectType(gProtectStructs[battler].protected) == PROTECT_TYPE_SINGLE) // Side type protects expire at the end of the turn
gProtectStructs[battler].protected = PROTECT_NONE;
if (effect == EFFECT_BATON_PASS)
{
gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP;
@ -3294,9 +3297,7 @@ const u8* FaintClearSetData(u32 battler)
for (i = 0; i < NUM_BATTLE_STATS; i++)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
bool32 keepGastroAcid = FALSE;
if (gBattleMons[battler].volatiles.gastroAcid)
keepGastroAcid = TRUE;
bool32 keepGastroAcid = gBattleMons[battler].volatiles.gastroAcid;
memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles));
gBattleMons[battler].volatiles.gastroAcid = keepGastroAcid; // Edge case: Keep Gastro Acid if pokemon's ability can have effect after fainting, for example Innards Out.
@ -3323,7 +3324,6 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].protected = PROTECT_NONE;
gProtectStructs[battler].quash = FALSE;
gProtectStructs[battler].endured = FALSE;
gProtectStructs[battler].noValidMoves = FALSE;
gProtectStructs[battler].helpingHand = FALSE;
gProtectStructs[battler].bounceMove = FALSE;
@ -3335,7 +3335,6 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].fleeType = 0;
gProtectStructs[battler].notFirstStrike = FALSE;
gProtectStructs[battler].statRaised = FALSE;
gProtectStructs[battler].tryEjectPack = FALSE;
gProtectStructs[battler].pranksterElevated = FALSE;
gDisableStructs[battler].isFirstTurn = 2;
@ -4488,6 +4487,10 @@ static void HandleTurnActionSelectionState(void)
gBattleStruct->chosenMovePositions[battler] = gBattleResources->bufferB[battler][2] & ~RET_GIMMICK;
gChosenMoveByBattler[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3];
if (IsBattleMoveStatus(gChosenMoveByBattler[battler]) && GetBattlerAbility(battler) == ABILITY_MYCELIUM_MIGHT)
gProtectStructs[battler].myceliumMight = TRUE;
if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_LAGGING_TAIL)
gProtectStructs[battler].laggingTail = TRUE;
// Check to see if any gimmicks need to be prepared.
if (gBattleResources->bufferB[battler][2] & RET_GIMMICK)
@ -4821,9 +4824,13 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move)
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS)
return GetMovePriority(MOVE_MAX_GUARD);
if (ability == ABILITY_GALE_WINGS
&& (GetGenConfig(GEN_CONFIG_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler))
&& GetMoveType(move) == TYPE_FLYING)
if (gProtectStructs[battler].quash)
{
priority = -8;
}
else if (ability == ABILITY_GALE_WINGS
&& (GetGenConfig(GEN_CONFIG_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler))
&& GetMoveType(move) == TYPE_FLYING)
{
priority++;
}
@ -4837,10 +4844,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;
}
return priority;
}
@ -4857,16 +4863,16 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov
// Lagging Tail - always last
bool32 battler1HasQuickEffect = gProtectStructs[battler1].quickDraw || gProtectStructs[battler1].usedCustapBerry;
bool32 battler2HasQuickEffect = gProtectStructs[battler2].quickDraw || gProtectStructs[battler2].usedCustapBerry;
bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || (ability1 == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gChosenMoveByBattler[battler1]));
bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || (ability2 == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gChosenMoveByBattler[battler2]));
bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || gProtectStructs[battler1].myceliumMight;
bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || gProtectStructs[battler2].myceliumMight;
if (battler1HasQuickEffect && !battler2HasQuickEffect)
strikesFirst = 1;
else if (battler2HasQuickEffect && !battler1HasQuickEffect)
strikesFirst = -1;
else if (holdEffectBattler1 == HOLD_EFFECT_LAGGING_TAIL && holdEffectBattler2 != HOLD_EFFECT_LAGGING_TAIL)
else if (gProtectStructs[battler1].laggingTail && !gProtectStructs[battler2].laggingTail)
strikesFirst = -1;
else if (holdEffectBattler2 == HOLD_EFFECT_LAGGING_TAIL && holdEffectBattler1 != HOLD_EFFECT_LAGGING_TAIL)
else if (gProtectStructs[battler2].laggingTail && !gProtectStructs[battler1].laggingTail)
strikesFirst = 1;
else if (battler1HasStallingAbility && !battler2HasStallingAbility)
strikesFirst = -1;
@ -5185,7 +5191,7 @@ static bool32 TryDoGimmicksBeforeMoves(void)
}
}
if (B_MEGA_EVO_TURN_ORDER >= GEN_7)
if (GetGenConfig(GEN_CONFIG_MEGA_EVO_TURN_ORDER) >= GEN_7)
TryChangeTurnOrder(); // This will just do nothing if no mon has mega evolved.
return FALSE;
}

View File

@ -270,7 +270,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNFASTASLEEP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n正在呼呼大睡。"),
[STRINGID_PKMNWOKEUP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n醒过来了!"),
[STRINGID_PKMNUPROARKEPTAWAKE] = COMPOUND_STRING("但是,{B_SCR_NAME_WITH_PREFIX2}\n被吵得无法入睡!"),
[STRINGID_PKMNWOKEUPINUPROAR] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX2}\n被吵醒了!"),
[STRINGID_PKMNWOKEUPINUPROAR] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX2}\n被吵醒了!"),
[STRINGID_PKMNCAUSEDUPROAR] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n吵闹了起来!"),
[STRINGID_PKMNMAKINGUPROAR] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n吵闹个不停!"),
[STRINGID_PKMNCALMEDDOWN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n平静了下来!"),
@ -623,7 +623,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_SOLARPOWERHPDROP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}因{B_ATK_ABILITY}\n削减了体力!"), //don't think this message is displayed anymore
[STRINGID_AFTERMATHDMG] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n受伤了!"),
[STRINGID_ANTICIPATIONACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}\n发抖了!"),
[STRINGID_FOREWARNACTIVATES] = COMPOUND_STRING("因{B_SCR_ABILITY}{B_SCR_NAME_WITH_PREFIX2}察觉到了\n{B_DEF_NAME_WITH_PREFIX2}的{B_BUFF1}"),
[STRINGID_FOREWARNACTIVATES] = COMPOUND_STRING("因{B_SCR_ABILITY}{B_SCR_NAME_WITH_PREFIX2}察觉到了\n{B_EFF_NAME_WITH_PREFIX2}的{B_BUFF1}"),
[STRINGID_ICEBODYHPGAIN] = COMPOUND_STRING("因为{B_ATK_ABILITY}\n{B_ATK_NAME_WITH_PREFIX}回复了少许HP。"), //don't think this message is displayed anymore
[STRINGID_SNOWWARNINGHAIL] = COMPOUND_STRING("开始下冰雹了!"),
[STRINGID_FRISKACTIVATES] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}察觉到了\n{B_DEF_NAME_WITH_PREFIX2}的{B_LAST_ITEM}"),
@ -640,7 +640,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_HEALINGWISHCAMETRUE] = COMPOUND_STRING("治愈之愿\n在{B_ATK_NAME_WITH_PREFIX2}身上实现了!"),
[STRINGID_HEALINGWISHHEALED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}的\n体力回复了!"),
[STRINGID_LUNARDANCECAMETRUE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}\n被神秘的月光包围了!"),
[STRINGID_CUSEDBODYDISABLED] = COMPOUND_STRING("因{B_DEF_NAME_WITH_PREFIX2}的{B_DEF_ABILITY}\n封住了{B_ATK_NAME_WITH_PREFIX}的\l{B_BUFF1}"),
[STRINGID_CURSEDBODYDISABLED] = COMPOUND_STRING("因{B_DEF_NAME_WITH_PREFIX2}的{B_DEF_ABILITY}\n封住了{B_ATK_NAME_WITH_PREFIX}的\l{B_BUFF1}"),
[STRINGID_ATTACKERACQUIREDABILITY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}的特性\n变为{B_LAST_ABILITY}了!"),
[STRINGID_TARGETABILITYSTATLOWER] = COMPOUND_STRING("因为{B_DEF_ABILITY}\n{B_DEF_NAME_WITH_PREFIX}的{B_BUFF1}降低了!"),
[STRINGID_TARGETSTATWONTGOHIGHER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}的\n{B_BUFF1}已经无法再提高了!"),

View File

@ -1920,7 +1920,7 @@ static void Cmd_adjustdamage(void)
{
enduredHit |= 1u << battlerDef;
}
else if (gProtectStructs[battlerDef].endured)
else if (gDisableStructs[battlerDef].endured)
{
enduredHit |= 1u << battlerDef;
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FOE_ENDURED;
@ -2321,6 +2321,7 @@ static void Cmd_datahpupdate(void)
{
CMD_ARGS(u8 battler);
bool32 isPassiveHpUpdate = gHitMarker & HITMARKER_PASSIVE_HP_UPDATE;
bool32 disguiseActivates = FALSE;
if (gBattleControllerExecFlags)
return;
@ -2362,7 +2363,7 @@ static void Cmd_datahpupdate(void)
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8;
BattleScriptPush(cmd->nextInstr);
gBattlescriptCurrInstr = BattleScript_TargetFormChange;
return;
disguiseActivates = TRUE;
}
else
{
@ -2447,6 +2448,9 @@ static void Cmd_datahpupdate(void)
&& CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerTarget].item)
&& !NoAliveMonsForEitherParty())
gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = TRUE;
if (disguiseActivates)
return;
}
TryRestoreDamageAfterCheekPouch(battler);
@ -2893,7 +2897,7 @@ static inline bool32 TrySetLightScreen(u32 battler)
return FALSE;
}
static void SetNonVolatileStatusCondition(u32 effectBattler, enum MoveEffect effect, enum StatusTrigger trigger)
static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum StatusTrigger trigger)
{
gEffectBattler = effectBattler;
@ -3037,7 +3041,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
battlerAbility,
gBattleScripting.moveEffect,
CHECK_TRIGGER))
SetNonVolatileStatusCondition(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_MOVE);
SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_MOVE);
break;
case MOVE_EFFECT_CONFUSION:
if (!CanBeConfused(gEffectBattler)
@ -3075,6 +3079,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
gLastUsedAbility = ABILITY_INNER_FOCUS;
gBattlerAbility = gEffectBattler;
RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS);
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_FlinchPrevention;
}
else
@ -3173,7 +3178,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_GRIP_CLAW)
gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? 7 : 5;
else
gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? (Random() % 2) + 4 : (Random() % 4) + 2;
gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? RandomUniform(RNG_WRAP, 4, 5) : RandomUniform(RNG_WRAP, 2, 5);
gBattleStruct->wrappedMove[gEffectBattler] = gCurrentMove;
gBattleStruct->wrappedBy[gEffectBattler] = gBattlerAttacker;
@ -3386,6 +3391,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
gBattleStruct->moveDamage[i] = gBattleMons[i].maxHP / 16;
if (gBattleStruct->moveDamage[i] == 0)
gBattleStruct->moveDamage[i] = 1;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_MoveEffectFlameBurst;
}
break;
@ -3892,7 +3898,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
|| gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)
{
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_DefogTryHazards;
gBattlescriptCurrInstr = BattleScript_MoveEffectDefog;
}
break;
case MOVE_EFFECT_AURORA_VEIL:
@ -3905,7 +3911,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 5;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SAFEGUARD;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_EffectAuroraVeilSuccess;
gBattlescriptCurrInstr = BattleScript_MoveEffectAuroraVeil;
}
break;
case MOVE_EFFECT_GRAVITY:
@ -3951,7 +3957,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
{
gBattleMons[gBattlerTarget].volatiles.yawn = 2;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_EffectYawnSuccess;
gBattlescriptCurrInstr = BattleScript_MoveEffectYawnSide;
}
break;
}
@ -4017,7 +4023,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
break;
case MOVE_EFFECT_AROMATHERAPY:
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_EffectHealBell_FromHeal;
gBattlescriptCurrInstr = BattleScript_MoveEffectAromatherapy;
break;
case MOVE_EFFECT_RECYCLE_BERRIES:
if (RandomPercentage(RNG_G_MAX_REPLENISH, 50))
@ -5539,7 +5545,7 @@ static inline bool32 CanEjectButtonTrigger(u32 battlerAtk, u32 battlerDef, enum
static inline bool32 CanEjectPackTrigger(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect)
{
if (gProtectStructs[battlerDef].tryEjectPack
if (gDisableStructs[battlerDef].tryEjectPack
&& GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_EJECT_PACK
&& IsBattlerAlive(battlerDef)
&& CountUsablePartyMons(battlerDef) > 0
@ -6009,7 +6015,7 @@ static void Cmd_moveend(void)
// Not strictly a protect effect, but works the same way
if (gProtectStructs[gBattlerTarget].beakBlastCharge
&& CanBeBurned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker))
&& CanBeBurned(gBattlerAttacker, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
{
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
@ -6559,7 +6565,7 @@ static void Cmd_moveend(void)
}
for (u32 i = 0; i < gBattlersCount; i++)
gProtectStructs[i].tryEjectPack = FALSE;
gDisableStructs[i].tryEjectPack = FALSE;
u8 battlers[4] = {0, 1, 2, 3};
if (numEjectButtonBattlers > 1)
@ -6622,7 +6628,7 @@ static void Cmd_moveend(void)
}
for (u32 i = 0; i < gBattlersCount; i++)
gProtectStructs[i].tryEjectPack = FALSE;
gDisableStructs[i].tryEjectPack = FALSE;
u8 battlers[4] = {0, 1, 2, 3};
if (numEmergencyExitBattlers > 1)
@ -6677,7 +6683,7 @@ static void Cmd_moveend(void)
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
gProtectStructs[i].tryEjectPack = FALSE;
gDisableStructs[i].tryEjectPack = FALSE;
for (i = 0; i < gBattlersCount; i++)
{
@ -6904,7 +6910,7 @@ static void Cmd_moveend(void)
for (i = 0; i < gBattlersCount; i++)
{
gBattleStruct->battlerState[gBattlerAttacker].targetsDone[i] = FALSE;
gProtectStructs[i].tryEjectPack = FALSE;
gDisableStructs[i].tryEjectPack = FALSE;
if (gBattleStruct->battlerState[i].commanderSpecies != SPECIES_NONE && !IsBattlerAlive(i))
{
@ -9527,7 +9533,7 @@ static void Cmd_setprotectlike(void)
{
if (GetMoveEffect(gCurrentMove) == EFFECT_ENDURE)
{
gProtectStructs[gBattlerAttacker].endured = TRUE;
gDisableStructs[gBattlerAttacker].endured = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_BRACED_ITSELF;
}
else if (GetProtectType(protectMethod) == PROTECT_TYPE_SIDE)
@ -10323,7 +10329,7 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChan
}
else if (!flags.onlyChecking)
{
gProtectStructs[battler].tryEjectPack = TRUE;
gDisableStructs[battler].tryEjectPack = TRUE;
gProtectStructs[battler].lashOutAffected = TRUE;
}
}
@ -10924,7 +10930,7 @@ static void Cmd_tryKO(void)
if (lands)
{
if (gProtectStructs[gBattlerTarget].endured)
if (gDisableStructs[gBattlerTarget].endured)
{
gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].hp - 1;
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_FOE_ENDURED;
@ -12464,12 +12470,6 @@ static void Cmd_trysetfutureattack(void)
static void Cmd_trydobeatup(void)
{
#if B_BEAT_UP >= GEN_5
CMD_ARGS();
gBattleStruct->beatUpSlot++;
gBattlescriptCurrInstr = cmd->nextInstr;
#else
CMD_ARGS(const u8 *endInstr, const u8 *failInstr);
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
@ -12514,7 +12514,6 @@ static void Cmd_trydobeatup(void)
gBattlescriptCurrInstr = cmd->failInstr;
}
}
#endif
}
static void Cmd_setsemiinvulnerablebit(void)
@ -14517,13 +14516,13 @@ static void Cmd_setnonvolatilestatus(void)
if (gBattleScripting.moveEffect >= MOVE_EFFECT_CONFUSION)
SetMoveEffect(gBattleScripting.battler, gEffectBattler, FALSE, FALSE);
else
SetNonVolatileStatusCondition(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_ABILITY);
SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_ABILITY);
break;
case TRIGGER_ON_MOVE:
SetNonVolatileStatusCondition(gBattlerTarget, GetMoveNonVolatileStatus(gCurrentMove), TRIGGER_ON_MOVE);
SetNonVolatileStatus(gBattlerTarget, GetMoveNonVolatileStatus(gCurrentMove), TRIGGER_ON_MOVE);
break;
case TRIGGER_ON_PROTECT:
SetNonVolatileStatusCondition(gBattlerAttacker, gBattleScripting.moveEffect, TRIGGER_ON_PROTECT);
SetNonVolatileStatus(gBattlerAttacker, gBattleScripting.moveEffect, TRIGGER_ON_PROTECT);
break;
}
}
@ -16330,12 +16329,8 @@ static void TrySetParalysis(const u8 *nextInstr, const u8 *failInstr)
{
if (CanBeParalyzed(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
{
gBattleMons[gBattlerTarget].status1 |= STATUS1_PARALYSIS;
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
gEffectBattler = gBattlerTarget;
BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
MarkBattlerForControllerExec(gBattlerTarget);
gBattlescriptCurrInstr = nextInstr;
gBattlescriptCurrInstr = nextInstr - 1;
SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_PARALYSIS, TRIGGER_ON_MOVE);
}
else
{
@ -16347,12 +16342,8 @@ static void TrySetPoison(const u8 *nextInstr, const u8 *failInstr)
{
if (CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(gBattlerTarget)))
{
gBattleMons[gBattlerTarget].status1 |= STATUS1_POISON;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gEffectBattler = gBattlerTarget;
BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
MarkBattlerForControllerExec(gBattlerTarget);
gBattlescriptCurrInstr = nextInstr;
gBattlescriptCurrInstr = nextInstr - 1;
SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_POISON, TRIGGER_ON_MOVE);
}
else
{
@ -16364,17 +16355,8 @@ static void TrySetSleep(const u8 *nextInstr, const u8 *failInstr)
{
if (CanBeSlept(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), BLOCKED_BY_SLEEP_CLAUSE))
{
if (B_SLEEP_TURNS >= GEN_5)
gBattleMons[gBattlerTarget].status1 |= STATUS1_SLEEP_TURN((Random() % 3) + 2);
else
gBattleMons[gBattlerTarget].status1 |= STATUS1_SLEEP_TURN((Random() % 4) + 3);
TryActivateSleepClause(gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget]);
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
gEffectBattler = gBattlerTarget;
BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
MarkBattlerForControllerExec(gBattlerTarget);
gBattlescriptCurrInstr = nextInstr;
gBattlescriptCurrInstr = nextInstr - 1;
SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_SLEEP, TRIGGER_ON_MOVE);
}
else
{
@ -17860,7 +17842,7 @@ void BS_GetTotemBoost(void)
void BS_ActivateItemEffects(void)
{
NATIVE_ARGS();
if (ItemBattleEffects(ITEMEFFECT_NORMAL, gBattlerTarget))
if (ItemBattleEffects(ITEMEFFECT_TRY_HEALING, gBattlerTarget))
return;
gBattlescriptCurrInstr = cmd->nextInstr;
}

View File

@ -267,15 +267,8 @@ bool32 EndOrContinueWeather(void)
static u32 CalcBeatUpPower(void)
{
u32 basePower;
u32 species;
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
// Party slot is incremented by the battle script for Beat Up after this damage calculation
species = GetMonData(&party[gBattleStruct->beatUpSlot], MON_DATA_SPECIES);
basePower = (GetSpeciesBaseAttack(species) / 10) + 5;
return basePower;
u32 species = gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot++];
return (GetSpeciesBaseAttack(species) / 10) + 5;
}
static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, u32 abilityDef)
@ -1937,7 +1930,7 @@ static enum MoveCanceller CancellerRecharge(void)
{
if (gBattleMons[gBattlerAttacker].volatiles.recharge)
{
gBattleMons[gBattlerAttacker].volatiles.recharge = TRUE;
gBattleMons[gBattlerAttacker].volatiles.recharge = FALSE;
gDisableStructs[gBattlerAttacker].rechargeTimer = 0;
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
@ -1956,6 +1949,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(void)
TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]);
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP;
gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE;
gEffectBattler = gBattlerAttacker;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR;
BattleScriptCall(BattleScript_MoveUsedWokeUp);
return MOVE_STEP_REMOVES_STATUS;
@ -2341,7 +2335,7 @@ static enum MoveCanceller CancellerWeatherPrimal(void)
if (HasWeatherEffect() && GetMovePower(gCurrentMove) > 0)
{
u32 moveType = GetBattleMoveType(gCurrentMove);
if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (B_POWDER_RAIN >= GEN_7 || !TryActivatePowderStatus(gCurrentMove)))
if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (GetGenConfig(GEN_CONFIG_POWDER_RAIN) >= GEN_7 || !TryActivatePowderStatus(gCurrentMove)))
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN;
effect = MOVE_STEP_BREAK;
@ -2484,14 +2478,19 @@ static enum MoveCanceller CancellerMultihitMoves(void)
{
struct Pokemon* party = GetBattlerParty(gBattlerAttacker);
int i;
gBattleStruct->beatUpSlot = 0;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&party[i], MON_DATA_HP)
&& GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE
u32 species = GetMonData(&party[i], MON_DATA_SPECIES);
if (species != SPECIES_NONE
&& GetMonData(&party[i], MON_DATA_HP)
&& !GetMonData(&party[i], MON_DATA_IS_EGG)
&& !GetMonData(&party[i], MON_DATA_STATUS))
{
gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot++] = species;
gMultiHitCounter++;
}
}
gBattleStruct->beatUpSlot = 0;
@ -2905,9 +2904,9 @@ static void ForewarnChooseMove(u32 battler)
bestId = i;
}
gBattlerTarget = data[bestId].battler;
gEffectBattler = data[bestId].battler;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, data[bestId].moveId)
RecordKnownMove(gBattlerTarget, data[bestId].moveId);
RecordKnownMove(data[bestId].battler, data[bestId].moveId);
Free(data);
}
@ -3975,27 +3974,33 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_INTREPID_SWORD:
if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)
if (!gSpecialStatuses[battler].switchInAbilityDone
&& !GetBattlerPartyState(battler)->intrepidSwordBoost)
{
if (GetGenConfig(GEN_INTREPID_SWORD) == GEN_9)
GetBattlerPartyState(battler)->intrepidSwordBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
effect++;
if (CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{
SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
effect++;
}
}
break;
case ABILITY_DAUNTLESS_SHIELD:
if (!gSpecialStatuses[battler].switchInAbilityDone && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)
if (!gSpecialStatuses[battler].switchInAbilityDone
&& !GetBattlerPartyState(battler)->dauntlessShieldBoost)
{
if (GetGenConfig(GEN_DAUNTLESS_SHIELD) == GEN_9)
GetBattlerPartyState(battler)->dauntlessShieldBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
SET_STATCHANGER(STAT_DEF, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
effect++;
if (CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
{
SET_STATCHANGER(STAT_DEF, 1, FALSE);
BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn);
effect++;
}
}
break;
case ABILITY_WIND_RIDER:
@ -5181,6 +5186,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
RecordAbilityBattle(gBattlerTarget, ABILITY_SYNCHRONIZE);
if (B_SYNCHRONIZE_TOXIC < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
if (CanSetNonVolatileStatus(
gBattlerTarget,
gBattlerAttacker,
@ -5189,9 +5197,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gBattleStruct->synchronizeMoveEffect,
CHECK_TRIGGER))
{
if (B_SYNCHRONIZE_TOXIC < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
gEffectBattler = gBattlerAttacker;
gBattleScripting.moveEffect = gBattleStruct->synchronizeMoveEffect;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, ABILITY_SYNCHRONIZE);
@ -5211,6 +5216,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gBattleScripting.battler = gBattlerAbility = gBattlerAttacker;
RecordAbilityBattle(gBattlerAttacker, ABILITY_SYNCHRONIZE);
if (B_SYNCHRONIZE_TOXIC < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
if (CanSetNonVolatileStatus(
gBattlerAttacker,
gBattlerTarget,
@ -7724,7 +7732,7 @@ enum IronBallCheck
};
// Only called directly when calculating damage type effectiveness, and Iron Ball's type effectiveness mechanics
static bool32 IsBattlerGroundedInverseCheck(u32 battler, enum InverseBattleCheck checkInverse, enum IronBallCheck checkIronBall)
static bool32 IsBattlerGroundedInverseCheck(u32 battler, u32 ability, enum InverseBattleCheck checkInverse, enum IronBallCheck checkIronBall)
{
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
@ -7742,7 +7750,7 @@ static bool32 IsBattlerGroundedInverseCheck(u32 battler, enum InverseBattleCheck
return FALSE;
if (holdEffect == HOLD_EFFECT_AIR_BALLOON)
return FALSE;
if (gAiLogicData->aiCalcInProgress ? gAiLogicData->abilities[battler] == ABILITY_LEVITATE : IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_LEVITATE))
if (ability == ABILITY_LEVITATE)
return FALSE;
if (IS_BATTLER_OF_TYPE(battler, TYPE_FLYING) && (!(checkInverse == INVERSE_BATTLE) || !FlagGet(B_FLAG_INVERSE_BATTLE)))
return FALSE;
@ -7751,7 +7759,7 @@ static bool32 IsBattlerGroundedInverseCheck(u32 battler, enum InverseBattleCheck
bool32 IsBattlerGrounded(u32 battler)
{
return IsBattlerGroundedInverseCheck(battler, NOT_INVERSE_BATTLE, CHECK_IRON_BALL);
return IsBattlerGroundedInverseCheck(battler, GetBattlerAbility(battler), NOT_INVERSE_BATTLE, CHECK_IRON_BALL);
}
u32 GetMoveSlot(u16 *moves, u32 move)
@ -9560,8 +9568,8 @@ s32 CalculateMoveDamage(struct DamageContext *ctx)
ctx->weather = GetWeather();
ctx->abilityAtk = GetBattlerAbility(ctx->battlerAtk);
ctx->abilityDef = GetBattlerAbility(ctx->battlerDef);
ctx->holdEffectAtk = GetItemHoldEffect(ctx->battlerAtk);
ctx->holdEffectDef = GetItemHoldEffect(ctx->battlerDef);
ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk, TRUE);
ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef, TRUE);
ctx->typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(ctx);
@ -9705,7 +9713,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont
if (B_GLARE_GHOST < GEN_4 && ctx->move == MOVE_GLARE && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GHOST))
modifier = UQ_4_12(0.0);
}
else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, INVERSE_BATTLE, CHECK_IRON_BALL) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move)))
else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, INVERSE_BATTLE, CHECK_IRON_BALL) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move)))
{
modifier = UQ_4_12(0.0);
if (ctx->updateFlags && ctx->abilityDef == ABILITY_LEVITATE)
@ -9717,7 +9725,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont
RecordAbilityBattle(ctx->battlerDef, ABILITY_LEVITATE);
}
}
else if (B_SHEER_COLD_IMMUNITY >= GEN_7 && GetMoveEffect(ctx->move) == EFFECT_SHEER_COLD && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_ICE))
else if (GetGenConfig(GEN_CONFIG_SHEER_COLD_IMMUNITY) >= GEN_7 && GetMoveEffect(ctx->move) == EFFECT_SHEER_COLD && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_ICE))
{
modifier = UQ_4_12(0.0);
}
@ -9735,7 +9743,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont
&& ctx->moveType == TYPE_GROUND
&& IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING)
&& GetBattlerHoldEffect(ctx->battlerDef, TRUE) == HOLD_EFFECT_IRON_BALL
&& !IsBattlerGroundedInverseCheck(ctx->battlerDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL)
&& !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL)
&& !FlagGet(B_FLAG_INVERSE_BATTLE))
{
modifier = UQ_4_12(1.0);
@ -10805,7 +10813,7 @@ bool32 TryRoomService(u32 battler)
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget)
{
if (B_PRANKSTER_DARK_TYPES < GEN_7)
if (GetGenConfig(GEN_CONFIG_PRANKSTER_DARK_TYPES) < GEN_7)
return FALSE;
if (!gProtectStructs[battlerPrankster].pranksterElevated)
return FALSE;
@ -11331,7 +11339,7 @@ void ClearDamageCalcResults(void)
bool32 DoesDestinyBondFail(u32 battler)
{
if (B_DESTINY_BOND_FAIL >= GEN_7
if (GetGenConfig(GEN_CONFIG_DESTINY_BOND_FAIL) >= GEN_7
&& GetMoveEffect(gLastLandedMoves[battler]) == EFFECT_DESTINY_BOND
&& GetMoveEffect(gLastResultingMoves[battler]) == EFFECT_DESTINY_BOND)
return TRUE;
@ -11454,7 +11462,7 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID)
for (u32 i = 0; i < gBattlersCount; i++)
{
if (gProtectStructs[i].tryEjectPack
if (gDisableStructs[i].tryEjectPack
&& GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_EJECT_PACK
&& IsBattlerAlive(i)
&& CountUsablePartyMons(i) > 0)
@ -11472,7 +11480,7 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID)
SortBattlersBySpeed(battlers, FALSE);
for (u32 i = 0; i < gBattlersCount; i++)
gProtectStructs[i].tryEjectPack = FALSE;
gDisableStructs[i].tryEjectPack = FALSE;
for (u32 i = 0; i < gBattlersCount; i++)
{

View File

@ -132,6 +132,7 @@ u32 BattlePalace_TryEscapeStatus(u8 battler)
if (UproarWakeUpCheck(battler))
{
// Wake up from Uproar
gEffectBattler = battler;
gBattleMons[battler].status1 &= ~(STATUS1_SLEEP);
gBattleMons[battler].volatiles.nightmare = FALSE;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR;

View File

@ -791,7 +791,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_BEAT_UP] =
{
.battleScript = BattleScript_EffectBeatUp,
.battleScript = (B_BEAT_UP >= GEN_5) ? BattleScript_EffectHit : BattleScript_EffectBeatUp,
.battleTvScore = 2,
},

View File

@ -32096,6 +32096,7 @@ static const u16 sDipplinTeachableLearnset[] = {
static const u16 sHydrappleTeachableLearnset[] = {
MOVE_BODY_SLAM,
MOVE_BULLET_SEED,
MOVE_DEFENSE_CURL,
MOVE_DOUBLE_EDGE,
MOVE_EARTHQUAKE,
MOVE_ENDURE,
@ -32106,6 +32107,7 @@ static const u16 sHydrappleTeachableLearnset[] = {
MOVE_RAIN_DANCE,
MOVE_REFLECT,
MOVE_REST,
MOVE_ROLLOUT,
MOVE_SLEEP_TALK,
MOVE_SOLAR_BEAM,
MOVE_SUNNY_DAY,

View File

@ -2055,19 +2055,7 @@ static u32 LoadDynamicFollowerPalette(u32 species, bool32 shiny, bool32 female)
spritePalette.data = gSpeciesInfo[species].overworldPalette;
}
// Check if pal data must be decompressed
if (IsLZ77Data(spritePalette.data, PLTT_SIZE_4BPP, PLTT_SIZE_4BPP))
{
struct SpritePalette compSpritePalette;
compSpritePalette.data = (const void *) spritePalette.data;
compSpritePalette.tag = spritePalette.tag;
paletteNum = LoadSpritePalette(&compSpritePalette);
}
else
{
paletteNum = LoadSpritePalette(&spritePalette);
}
paletteNum = LoadSpritePalette(&spritePalette);
}
else
#endif //OW_POKEMON_OBJECT_EVENTS == TRUE && OW_PKMN_OBJECTS_SHARE_PALETTES == FALSE

View File

@ -83,3 +83,18 @@ SINGLE_BATTLE_TEST("Desolate Land will not create a softlock when move in semi i
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player);
}
}
SINGLE_BATTLE_TEST("Desolate Land is removed immediately if user faints")
{
GIVEN {
PLAYER(SPECIES_GROUDON) { HP(1); Item(ITEM_RED_ORB); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_POUND); SEND_OUT(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponent);
NOT MESSAGE("The sunlight is strong.");
MESSAGE("The extremely harsh sunlight faded!");
}
}

View File

@ -1,4 +1,25 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Filter (Ability) test titles")
SINGLE_BATTLE_TEST("Filter reduces damage to Super Effective moves by 0.75", s16 damage)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_SOUNDPROOF; }
PARAMETRIZE { ability = ABILITY_FILTER; }
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_MR_MIME].types[0] == TYPE_PSYCHIC);
ASSUME(gSpeciesInfo[SPECIES_MR_MIME].types[1] == TYPE_FAIRY);
ASSUME(gMovesInfo[MOVE_POISON_JAB].type == TYPE_POISON);
ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_FAIRY] > UQ_4_12(1.0));
ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_PSYCHIC] == UQ_4_12(1.0));
PLAYER(SPECIES_MR_MIME) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_POISON_JAB); }
} SCENE {
HP_BAR(player, captureDamage: &results[i].damage);
MESSAGE("It's super effective!");
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.75), results[1].damage);
}
}

View File

@ -9,9 +9,9 @@ SINGLE_BATTLE_TEST("Flash Fire boosts fire type moves by 50% but no subsequent i
PLAYER(SPECIES_HEATRAN) { Ability(ABILITY_FLASH_FIRE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_EMBER); MOVE(opponent, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER); MOVE(opponent, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER, secondaryEffect: FALSE); MOVE(opponent, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER, secondaryEffect: FALSE); MOVE(opponent, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER, secondaryEffect: FALSE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent, captureDamage: &damage[0]);

View File

@ -1,4 +1,115 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Levitate (Ability) test titles")
SINGLE_BATTLE_TEST("Levitate activates when targeted by ground type moves")
{
GIVEN {
ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND);
PLAYER(SPECIES_LUNATONE) { Ability(ABILITY_LEVITATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_MUD_SLAP); }
} SCENE {
ABILITY_POPUP(player, ABILITY_LEVITATE);
MESSAGE("Lunatone makes Ground-type moves miss with Levitate!");
}
}
SINGLE_BATTLE_TEST("Levitate does not activate if protected")
{
GIVEN {
ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND);
PLAYER(SPECIES_LUNATONE) { Ability(ABILITY_LEVITATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_MUD_SLAP); }
} SCENE {
NONE_OF {
ABILITY_POPUP(player, ABILITY_LEVITATE);
MESSAGE("Lunatone makes Ground-type moves miss with Levitate!");
}
}
}
SINGLE_BATTLE_TEST("Levitate does not activate on status moves")
{
GIVEN {
ASSUME(GetMoveType(MOVE_SAND_ATTACK) == TYPE_GROUND);
ASSUME(GetMoveCategory(MOVE_SAND_ATTACK) == DAMAGE_CATEGORY_STATUS);
PLAYER(SPECIES_LUNATONE) { Ability(ABILITY_LEVITATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SAND_ATTACK); }
} SCENE {
NONE_OF {
ABILITY_POPUP(player, ABILITY_LEVITATE);
MESSAGE("Lunatone makes Ground-type moves miss with Levitate!");
}
}
}
SINGLE_BATTLE_TEST("Levitate does not activate if attacked by an opponent with Mold Breaker")
{
GIVEN {
ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND);
PLAYER(SPECIES_LUNATONE) { Ability(ABILITY_LEVITATE); }
OPPONENT(SPECIES_TINKATON) { Ability(ABILITY_MOLD_BREAKER); }
} WHEN {
TURN { MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_MUD_SLAP); }
} SCENE {
NONE_OF {
ABILITY_POPUP(player, ABILITY_LEVITATE);
MESSAGE("Lunatone makes Ground-type moves miss with Levitate!");
}
}
}
DOUBLE_BATTLE_TEST("Levitate does not cause single remaining target to take higher damage")
{
s16 damage[3];
GIVEN {
PLAYER(SPECIES_REGIROCK) { Speed(1); }
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
OPPONENT(SPECIES_LUNATONE) { Speed(3); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
} WHEN {
TURN { MOVE(playerRight, MOVE_CELEBRATE); MOVE(playerLeft, MOVE_EARTHQUAKE); }
TURN { MOVE(playerRight, MOVE_MEMENTO, target:opponentLeft); MOVE(playerLeft, MOVE_EARTHQUAKE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, playerLeft);
HP_BAR(playerRight, captureDamage: &damage[0]);
HP_BAR(opponentRight, captureDamage: &damage[1]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, playerLeft);
HP_BAR(opponentRight, captureDamage: &damage[2]);
} THEN {
EXPECT_EQ(damage[0], damage[1]);
EXPECT_EQ(damage[1], damage[2]);
}
}
AI_SINGLE_BATTLE_TEST("Levitate is seen correctly by switch AI")
{
u32 ability = ABILITY_NONE, item = ITEM_NONE;
PARAMETRIZE { ability = ABILITY_OWN_TEMPO, item = ITEM_NONE ; }
PARAMETRIZE { ability = ABILITY_MOLD_BREAKER, item = ITEM_NONE ; }
PARAMETRIZE { ability = ABILITY_MOLD_BREAKER, item = ITEM_ABILITY_SHIELD ; }
GIVEN {
ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_TINKATON) { Ability(ability); Speed(3); }
OPPONENT(SPECIES_PONYTA) { Level(1); Item(ITEM_EJECT_PACK); Moves(MOVE_OVERHEAT); Speed(4); } // Forces switchout
OPPONENT(SPECIES_VIKAVOLT) { HP(1); Speed(1); Ability(ABILITY_LEVITATE); Moves(MOVE_FLAMETHROWER); Item(item); }
OPPONENT(SPECIES_HYPNO) { Speed(1); Moves(MOVE_IRON_HEAD); }
} WHEN {
if ((ability == ABILITY_MOLD_BREAKER) && (item != ITEM_ABILITY_SHIELD))
TURN { MOVE(player, MOVE_MUD_SLAP); EXPECT_SEND_OUT(opponent, 2); }
else
TURN { MOVE(player, MOVE_MUD_SLAP); EXPECT_SEND_OUT(opponent, 1); }
}
}

View File

@ -67,3 +67,30 @@ SINGLE_BATTLE_TEST("Mycelium Might vs Stall action order depends on speed")
}
}
}
DOUBLE_BATTLE_TEST("Mycelium Might priority bracket will not change if the ability is changed mid-turn")
{
GIVEN {
PLAYER(SPECIES_TOEDSCOOL) { Speed(100); Ability(ABILITY_MYCELIUM_MIGHT); }
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(30); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(20); }
} WHEN {
TURN {
MOVE(opponentLeft, MOVE_WORRY_SEED, target: playerLeft);
MOVE(playerLeft, MOVE_SCREECH, target: opponentLeft);
}
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WORRY_SEED, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCREECH, playerLeft);
// Turn 2
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
}
}

View File

@ -7,22 +7,31 @@ ASSUMPTIONS
ASSUME(GetMoveCategory(MOVE_CONFUSE_RAY) == DAMAGE_CATEGORY_STATUS);
}
SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon")
SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon (Gen7+)")
{
u32 gen;
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(GEN_CONFIG_PRANKSTER_DARK_TYPES, gen);
PLAYER(SPECIES_UMBREON);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
} WHEN {
TURN { MOVE(opponent, MOVE_CONFUSE_RAY); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent);
MESSAGE("It doesn't affect Umbreon…");
if (gen == GEN_6) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent);
} else {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent);
MESSAGE("It doesn't affect Umbreon…");
}
}
}
SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon after they switch-in")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_PRANKSTER_DARK_TYPES, GEN_7);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_UMBREON);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
@ -49,39 +58,62 @@ DOUBLE_BATTLE_TEST("Prankster-affected moves affect Ally Dark-type Pokémon")
}
}
SINGLE_BATTLE_TEST("Prankster-affected moves called via Assist don't affect Dark-type Pokémon")
SINGLE_BATTLE_TEST("Prankster-affected moves called via Assist don't affect Dark-type Pokémon (Gen 7+)")
{
u32 gen;
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(GEN_CONFIG_PRANKSTER_DARK_TYPES, gen);
PLAYER(SPECIES_UMBREON);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CONFUSE_RAY); };
} WHEN {
TURN { MOVE(opponent, MOVE_ASSIST); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent);
MESSAGE("It doesn't affect Umbreon…");
if (gen == GEN_6) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent);
} else {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent);
MESSAGE("It doesn't affect Umbreon…");
}
}
}
// Tested on Showdown, even though Bulbapedia says otherwise.
DOUBLE_BATTLE_TEST("Prankster-affected moves called via Instruct do not affect Dark-type Pokémon")
{
u32 gen;
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(GEN_CONFIG_PRANKSTER_DARK_TYPES, gen);
PLAYER(SPECIES_VOLBEAT) { Speed(20); Ability(ABILITY_PRANKSTER); }
PLAYER(SPECIES_WOBBUFFET) { Speed(10);}
OPPONENT(SPECIES_UMBREON) { Speed(1); }
OPPONENT(SPECIES_UMBREON) { Speed(15); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
OPPONENT(SPECIES_UMBREON) { Speed(1); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_CONFUSE_RAY, target: opponentLeft);
MOVE(opponentLeft, MOVE_U_TURN, target: playerRight, WITH_RNG(RNG_CONFUSION, FALSE));
SEND_OUT(opponentLeft, 2);
MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft);
}
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, playerLeft);
MESSAGE("It doesn't affect the opposing Umbreon…");
if (gen == GEN_6) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, playerLeft);
} else {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, playerLeft);
MESSAGE("It doesn't affect the opposing Umbreon…");
}
MESSAGE("Wobbuffet used Instruct!");
MESSAGE("Volbeat used Confuse Ray!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, playerLeft);
MESSAGE("It doesn't affect the opposing Umbreon…");
if (gen == GEN_6) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, playerLeft);
} else {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, playerLeft);
MESSAGE("It doesn't affect the opposing Umbreon…");
}
}
}
@ -171,6 +203,7 @@ SINGLE_BATTLE_TEST("Prankster-affected moves which are reflected by Magic Coat c
PARAMETRIZE { sableyeAbility = ABILITY_KEEN_EYE; }
GIVEN {
WITH_CONFIG(GEN_CONFIG_PRANKSTER_DARK_TYPES, GEN_7);
PLAYER(SPECIES_SABLEYE) { Ability(sableyeAbility); }
OPPONENT(SPECIES_MURKROW) { Ability(ABILITY_PRANKSTER); }
} WHEN {

View File

@ -1,4 +1,25 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Prism Armor (Ability) test titles")
SINGLE_BATTLE_TEST("Prism Armor reduces damage to Super Effective moves by 0.75", s16 damage)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; }
PARAMETRIZE { ability = ABILITY_LEVITATE; }
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_NECROZMA].types[0] == TYPE_PSYCHIC);
ASSUME(gSpeciesInfo[SPECIES_NECROZMA].types[1] == TYPE_PSYCHIC);
ASSUME(gMovesInfo[MOVE_DARK_PULSE].type == TYPE_DARK);
ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_FAIRY] > UQ_4_12(1.0));
ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_PSYCHIC] == UQ_4_12(1.0));
PLAYER(SPECIES_NECROZMA);
OPPONENT(SPECIES_WEEZING) { Ability(ability); }
} WHEN {
TURN { MOVE(opponent, MOVE_DARK_PULSE); }
} SCENE {
HP_BAR(player, captureDamage: &results[i].damage);
MESSAGE("It's super effective!");
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.75), results[1].damage);
}
}

View File

@ -0,0 +1,25 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Solid Rock reduces damage to Super Effective moves by 0.75", s16 damage)
{
u32 ability;
PARAMETRIZE { ability = ABILITY_STURDY; }
PARAMETRIZE { ability = ABILITY_SOLID_ROCK; }
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_CARRACOSTA].types[0] == TYPE_WATER);
ASSUME(gSpeciesInfo[SPECIES_CARRACOSTA].types[1] == TYPE_ROCK);
ASSUME(gMovesInfo[MOVE_CLOSE_COMBAT].type == TYPE_FIGHTING);
ASSUME(gTypeEffectivenessTable[TYPE_FIGHTING][TYPE_ROCK] > UQ_4_12(1.0));
ASSUME(gTypeEffectivenessTable[TYPE_FIGHTING][TYPE_WATER] == UQ_4_12(1.0));
PLAYER(SPECIES_CARRACOSTA) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_CLOSE_COMBAT); }
} SCENE {
HP_BAR(player, captureDamage: &results[i].damage);
MESSAGE("It's super effective!");
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.75), results[1].damage);
}
}

View File

@ -17,7 +17,7 @@ DOUBLE_BATTLE_TEST("Sweet Veil prevents Sleep on partner - right target")
} WHEN {
TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); }
} SCENE {
MESSAGE("Wobbuffet used Hypnosis!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPNOSIS, playerLeft);
ABILITY_POPUP(opponentLeft, ABILITY_SWEET_VEIL);
NOT STATUS_ICON(opponentRight, sleep: TRUE);
}
@ -33,7 +33,27 @@ DOUBLE_BATTLE_TEST("Sweet Veil prevents Sleep on partner - left target")
} WHEN {
TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentLeft); }
} SCENE {
MESSAGE("Wobbuffet used Hypnosis!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPNOSIS, playerLeft);
ABILITY_POPUP(opponentRight, ABILITY_SWEET_VEIL);
NOT STATUS_ICON(opponentLeft, sleep: TRUE);
}
}
DOUBLE_BATTLE_TEST("Sweet Veil prevents Yawn activation")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
OPPONENT(SPECIES_BOUNSWEET) { Ability(ABILITY_SWEET_VEIL); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_YAWN, target: opponentLeft); }
TURN { SWITCH(opponentRight, 2); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_YAWN, playerLeft);
// Turn 2
ABILITY_POPUP(opponentRight, ABILITY_SWEET_VEIL);
NOT STATUS_ICON(opponentLeft, sleep: TRUE);
}

View File

@ -7,17 +7,18 @@ ASSUMPTIONS
ASSUME(!IsBattleMoveStatus(MOVE_GUST));
ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL);
ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
ASSUME(B_WEAK_ARMOR_SPEED >= GEN_7);
}
SINGLE_BATTLE_TEST("Weak Armor lowers Defense by 1 and boosts Speed by 2 when hit by a physical attack")
SINGLE_BATTLE_TEST("Weak Armor lowers Defense by 1 and boosts Speed by 1 (Gen5-6) or 2 (Gen7+) when hit by a physical attack")
{
u16 move;
u16 move, gen;
PARAMETRIZE { move = MOVE_SCRATCH; }
PARAMETRIZE { move = MOVE_GUST; }
PARAMETRIZE { move = MOVE_SCRATCH; gen = GEN_6; }
PARAMETRIZE { move = MOVE_SCRATCH; gen = GEN_7; }
PARAMETRIZE { move = MOVE_GUST; gen = GEN_7; }
GIVEN {
WITH_CONFIG(GEN_CONFIG_WEAK_ARMOR_SPEED, gen);
PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -41,7 +42,10 @@ SINGLE_BATTLE_TEST("Weak Armor lowers Defense by 1 and boosts Speed by 2 when hi
} THEN {
if (move == MOVE_SCRATCH) {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 2);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + (gen == GEN_7 ? 2 : 1));
} else {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
}
}
}
@ -79,7 +83,12 @@ SINGLE_BATTLE_TEST("Weak Armor does not trigger when brought in by Dragon Tail a
SINGLE_BATTLE_TEST("Weak Armor still boosts Speed if Defense can't go any lower")
{
u16 gen;
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(GEN_CONFIG_WEAK_ARMOR_SPEED, gen);
PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -100,7 +109,7 @@ SINGLE_BATTLE_TEST("Weak Armor still boosts Speed if Defense can't go any lower"
MESSAGE("Slugma's Weak Armor raised its Speed!");
} THEN {
EXPECT_EQ(player->statStages[STAT_DEF], MIN_STAT_STAGE);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 2);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + (gen == GEN_7 ? 2 : 1));
}
}
@ -135,6 +144,7 @@ SINGLE_BATTLE_TEST("Weak Armor doesn't interrupt multi hit moves if Defense can'
{
u32 j;
GIVEN {
WITH_CONFIG(GEN_CONFIG_WEAK_ARMOR_SPEED, GEN_7);
PLAYER(SPECIES_MAGCARGO) { Ability(ABILITY_WEAK_ARMOR); Defense(999); }
OPPONENT(SPECIES_CLOYSTER) { Ability(ABILITY_SKILL_LINK); }
} WHEN {
@ -173,6 +183,7 @@ SINGLE_BATTLE_TEST("Weak Armor doesn't interrupt multi hit moves if Speed can't
{
u32 j;
GIVEN {
WITH_CONFIG(GEN_CONFIG_WEAK_ARMOR_SPEED, GEN_7);
PLAYER(SPECIES_MAGCARGO) { Ability(ABILITY_WEAK_ARMOR); Defense(999); }
OPPONENT(SPECIES_CLOYSTER) { Ability(ABILITY_SKILL_LINK); }
} WHEN {

View File

@ -595,6 +595,25 @@ AI_DOUBLE_BATTLE_TEST("AI uses Trick Room intelligently")
}
}
AI_DOUBLE_BATTLE_TEST("AI uses Trick Room with both battlers on the turn it expires in line with the double Trick Room config")
{
PASSES_RANDOMLY(DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE, 100, RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN);
GIVEN {
ASSUME(GetMoveEffect(MOVE_TRICK_ROOM) == EFFECT_TRICK_ROOM);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_DOUBLE_BATTLE);
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
PLAYER(SPECIES_WOBBUFFET) { Speed(3); }
OPPONENT(SPECIES_WYNAUT) { Moves(MOVE_TRICK_ROOM, MOVE_PSYCHIC); Speed(2); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_TRICK_ROOM, MOVE_PSYCHIC); Speed(1); }
} WHEN {
TURN { EXPECT_MOVE(opponentLeft, MOVE_TRICK_ROOM); NOT_EXPECT_MOVE(opponentRight, MOVE_TRICK_ROOM); }
TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_TRICK_ROOM); NOT_EXPECT_MOVE(opponentRight, MOVE_TRICK_ROOM); }
TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_TRICK_ROOM); NOT_EXPECT_MOVE(opponentRight, MOVE_TRICK_ROOM); }
TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_TRICK_ROOM); NOT_EXPECT_MOVE(opponentRight, MOVE_TRICK_ROOM); }
TURN { EXPECT_MOVE(opponentLeft, MOVE_TRICK_ROOM); EXPECT_MOVE(opponentRight, MOVE_TRICK_ROOM); }
}
}
AI_DOUBLE_BATTLE_TEST("AI uses Helping Hand if it's about to die")
{
u32 hp;

View File

@ -64,13 +64,14 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: Mid-battle switches prioritize offensive o
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
GIVEN {
ASSUME(P_UPDATED_STATS >= GEN_7); // Swellow's 50 Sp.Atk in Gen 6 instead of the current 75 causes the AI to switch to Electrode
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT | aiRiskyFlag);
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(4); } // Forces switchout
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); SpDefense(41); } // Mid battle, AI sends out Aron
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); Ability(ABILITY_STATIC); }
} WHEN {
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, aiRiskyFlag? 2 : 1); }
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, aiRiskyFlag? 2 : 1); }
}
}

View File

@ -1033,7 +1033,7 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch into mon with good type matchup
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI correctly handles abilities when scoring moves")
{
GIVEN {
ASSUME(B_PRANKSTER_DARK_TYPES >= GEN_7);
WITH_CONFIG(GEN_CONFIG_PRANKSTER_DARK_TYPES, GEN_7);
ASSUME(GetSpeciesType(SPECIES_GRENINJA, 1) == TYPE_DARK);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_MON_CHOICES);
PLAYER(SPECIES_GRENINJA) { Moves(MOVE_WATER_GUN); }

View File

@ -62,7 +62,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 1-100")
{
u32 moveStart = 0;
u32 moveCap = 100;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -92,7 +92,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 1-100")
case EFFECT_DISABLE:
// tests exist elsewhere
// Skipped on purpose.
case EFFECT_PROTECT:
case EFFECT_NON_VOLATILE_STATUS:
@ -124,7 +124,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 101-200")
{
u32 moveStart = 100;
u32 moveCap = 200;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -200,7 +200,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 201-300")
{
u32 moveStart = 200;
u32 moveCap = 300;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -285,7 +285,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 301-400")
{
u32 moveStart = 300;
u32 moveCap = 400;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -329,7 +329,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 301-400")
// tests exist elsewhere
case EFFECT_HEAL_BELL:
case EFFECT_ATTACK_UP_USER_ALLY:
// Skipped on purpose.
case EFFECT_PROTECT:
case EFFECT_NON_VOLATILE_STATUS:
@ -361,7 +361,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 401-500")
{
u32 moveStart = 400;
u32 moveCap = 500;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -390,12 +390,13 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 401-500")
//TODO: AI TESTS
case EFFECT_RESTORE_HP:
case EFFECT_CAPTIVATE:
case EFFECT_DARK_VOID: // Gen 4-6's case is not being handled
// tests exist elsewhere
case EFFECT_TRICK_ROOM:
case EFFECT_GUARD_SPLIT:
case EFFECT_POWER_SPLIT:
// Skipped on purpose.
case EFFECT_PROTECT:
case EFFECT_NON_VOLATILE_STATUS:
@ -427,7 +428,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 501-600")
{
u32 moveStart = 515;
u32 moveCap = 600;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -502,7 +503,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 601-700")
{
u32 moveStart = 600;
u32 moveCap = 700;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -542,7 +543,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 601-700")
case EFFECT_ELECTRIC_TERRAIN:
case EFFECT_PSYCHIC_TERRAIN:
case EFFECT_AURORA_VEIL:
// Skipped on purpose.
case EFFECT_PROTECT:
case EFFECT_NON_VOLATILE_STATUS:
@ -574,7 +575,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 701-800")
{
u32 moveStart = 700;
u32 moveCap = 800;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;
@ -643,7 +644,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 801-900")
{
u32 moveStart = 800;
u32 moveCap = 900;
if (moveCap > MOVES_COUNT)
moveCap = MOVES_COUNT - 1;

View File

@ -71,10 +71,26 @@ SINGLE_BATTLE_TEST("Rayquaza can Mega Evolve knowing Dragon Ascent")
}
}
SINGLE_BATTLE_TEST("Mega Evolution affects turn order")
SINGLE_BATTLE_TEST("Mega Evolution doesn't affect turn order (Gen6)")
{
GIVEN {
ASSUME(B_MEGA_EVO_TURN_ORDER >= GEN_7);
WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_6);
PLAYER(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE); Speed(105); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(106); }
} WHEN {
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); }
} SCENE {
MESSAGE("The opposing Wobbuffet used Celebrate!");
MESSAGE("Gardevoir used Celebrate!");
} THEN {
ASSUME(player->speed == 205);
}
}
SINGLE_BATTLE_TEST("Mega Evolution affects turn order (Gen7+)")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7);
PLAYER(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE); Speed(105); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(106); }
} WHEN {
@ -90,7 +106,7 @@ SINGLE_BATTLE_TEST("Mega Evolution affects turn order")
SINGLE_BATTLE_TEST("Abilities replaced by Mega Evolution do not affect turn order")
{
GIVEN {
ASSUME(B_MEGA_EVO_TURN_ORDER >= GEN_7);
WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7);
ASSUME(GetSpeciesAbility(SPECIES_SABLEYE_MEGA, 0) != ABILITY_STALL
&& GetSpeciesAbility(SPECIES_SABLEYE_MEGA, 1) != ABILITY_STALL);
PLAYER(SPECIES_SABLEYE) { Item(ITEM_SABLENITE); Ability(ABILITY_STALL); Speed(105); }

View File

@ -58,7 +58,7 @@ DOUBLE_BATTLE_TEST("Ultra Burst's order is determined by Speed - player faster")
SINGLE_BATTLE_TEST("Ultra Burst affects turn order")
{
GIVEN {
ASSUME(B_MEGA_EVO_TURN_ORDER >= GEN_7);
WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7);
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); Speed(105); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(106); }
} WHEN {

View File

@ -1018,11 +1018,11 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Volt Crash paralyzes both opponents")
} SCENE {
MESSAGE("Pikachu used G-Max Volt Crash!");
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft);
STATUS_ICON(opponentLeft, paralysis: TRUE);
MESSAGE("The opposing Wobbuffet is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentLeft, paralysis: TRUE);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentRight);
STATUS_ICON(opponentRight, paralysis: TRUE);
MESSAGE("The opposing Wynaut is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentRight, paralysis: TRUE);
}
}
@ -1048,22 +1048,22 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Stun Shock paralyzes or poisons both opponent
// opponent left
ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentLeft);
if (statusAnim == B_ANIM_STATUS_PSN) {
STATUS_ICON(opponentLeft, poison: TRUE);
MESSAGE("The opposing Wobbuffet was poisoned!");
STATUS_ICON(opponentLeft, poison: TRUE);
}
else {
STATUS_ICON(opponentLeft, paralysis: TRUE);
MESSAGE("The opposing Wobbuffet is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentLeft, paralysis: TRUE);
}
// opponent right
ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentRight);
if (statusAnim == B_ANIM_STATUS_PSN) {
STATUS_ICON(opponentRight, poison: TRUE);
MESSAGE("The opposing Wynaut was poisoned!");
STATUS_ICON(opponentRight, poison: TRUE);
}
else {
STATUS_ICON(opponentRight, paralysis: TRUE);
MESSAGE("The opposing Wynaut is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentRight, paralysis: TRUE);
}
}
}
@ -1118,30 +1118,30 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Befuddle paralyzes, poisons, or sleeps both o
// opponent left
ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentLeft);
if (statusAnim == B_ANIM_STATUS_PSN) {
STATUS_ICON(opponentLeft, poison: TRUE);
MESSAGE("The opposing Wobbuffet was poisoned!");
STATUS_ICON(opponentLeft, poison: TRUE);
}
else if (statusAnim == B_ANIM_STATUS_PRZ) {
STATUS_ICON(opponentLeft, paralysis: TRUE);
MESSAGE("The opposing Wobbuffet is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentLeft, paralysis: TRUE);
}
else {
STATUS_ICON(opponentLeft, sleep: TRUE);
MESSAGE("The opposing Wobbuffet fell asleep!");
STATUS_ICON(opponentLeft, sleep: TRUE);
}
// opponent right
ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentRight);
if (statusAnim == B_ANIM_STATUS_PSN) {
STATUS_ICON(opponentRight, poison: TRUE);
MESSAGE("The opposing Wobbuffet was poisoned!");
STATUS_ICON(opponentRight, poison: TRUE);
}
else if (statusAnim == B_ANIM_STATUS_PRZ) {
STATUS_ICON(opponentRight, paralysis: TRUE);
MESSAGE("The opposing Wobbuffet is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentRight, paralysis: TRUE);
}
else {
STATUS_ICON(opponentRight, sleep: TRUE);
MESSAGE("The opposing Wobbuffet fell asleep!");
STATUS_ICON(opponentRight, sleep: TRUE);
}
}
}

View File

@ -6,9 +6,10 @@
SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves do not retain priority")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7); // TODO: Decouple this config from other gimmicks
ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); }
OPPONENT(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Speed(1); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
} WHEN {
TURN { MOVE(opponent, MOVE_SCRATCH);
MOVE(player, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); }

View File

@ -317,3 +317,24 @@ DOUBLE_BATTLE_TEST("Eject Pack: Only the fastest Eject Pack will activate after
}
}
}
SINGLE_BATTLE_TEST("Eject Pack does not activate if mon is switched in due to Eject Button")
{
GIVEN {
PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_ARENA_TRAP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_BUTTON); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(player, MOVE_BULLDOZE);
SEND_OUT(opponent, 1);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLDOZE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
MESSAGE("The opposing Wobbuffet is switched out with the Eject Button!");
MESSAGE("2 sent out Wobbuffet!");
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
}
}

View File

@ -0,0 +1,31 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gItemsInfo[ITEM_LAGGING_TAIL].holdEffect == HOLD_EFFECT_LAGGING_TAIL);
}
DOUBLE_BATTLE_TEST("Lagging Tail priority bracket will not change if the item is removed is changed mid-turn")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Item(ITEM_LAGGING_TAIL); }
PLAYER(SPECIES_WYNAUT) { Speed(10); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(30); Item(ITEM_BERRY_JUICE); }
OPPONENT(SPECIES_WYNAUT) { Speed(20); }
} WHEN {
TURN { MOVE(opponentLeft, MOVE_TRICK, target: playerLeft); }
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerLeft);
// Turn 2
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft); // Now last because of Tricking Lagging Tail onto itself
}
}

View File

@ -131,3 +131,22 @@ SINGLE_BATTLE_TEST("Life Orb activates if move connected but no damage was dealt
MESSAGE("Wobbuffet was hurt by the Life Orb!");
}
}
SINGLE_BATTLE_TEST("Life Orb does not activate on a charge turn")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FLY); }
TURN { SKIP_TURN(player); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLY, player);
NONE_OF {
HP_BAR(player);
MESSAGE("Wobbuffet was hurt by the Life Orb!");
}
HP_BAR(opponent);
HP_BAR(player); // Lief Orb
}
}

View File

@ -112,6 +112,21 @@ SINGLE_BATTLE_TEST("Beak Blast burns only when contact moves are used")
}
}
SINGLE_BATTLE_TEST("Beak Blast doesn't burn fire types")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_ARCANINE].types[1]);
PLAYER(SPECIES_ARCANINE);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_BEAK_BLAST); MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
NOT STATUS_ICON(player, burn: TRUE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAK_BLAST, opponent);
}
}
TO_DO_BATTLE_TEST("Beak Blast's charging message is shown regardless if it would've missed");
TO_DO_BATTLE_TEST("Beak Blast fails if it's forced by Encore after choosing a different move");
TO_DO_BATTLE_TEST("Bulletproof is immune to Beak Blast but not to the burn it causes");

View File

@ -2,7 +2,32 @@
#include "test/battle.h"
// General
TO_DO_BATTLE_TEST("Beat Up hits the target for each non-fainted, non-statused member in the party");
SINGLE_BATTLE_TEST("Beat Up hits the target for each non-fainted, non-statused member in the party")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_PICHU)
PLAYER(SPECIES_PIKACHU) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_RAICHU)
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
MESSAGE("The Pokémon was hit 4 time(s)!");
} THEN {
EXPECT_EQ(gBattleStruct->beatUpSpecies[0], SPECIES_WOBBUFFET);
EXPECT_EQ(gBattleStruct->beatUpSpecies[1], SPECIES_WYNAUT);
EXPECT_EQ(gBattleStruct->beatUpSpecies[2], SPECIES_PICHU);
EXPECT_EQ(gBattleStruct->beatUpSpecies[3], SPECIES_RAICHU);
}
}
TO_DO_BATTLE_TEST("Beat Up doesn't consider Comatose as a status")
TO_DO_BATTLE_TEST("Beat Up's strikes have each an independent chance of a critical hit");

View File

@ -24,6 +24,7 @@ TO_DO_BATTLE_TEST("Copycat copies moves called by other calling moves instead of
DOUBLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their base moves copied by Copycat")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_MEGA_EVO_TURN_ORDER, GEN_7); // TODO: Decouple this config from other gimmicks
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -1,7 +1,7 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND);
}
@ -21,10 +21,28 @@ SINGLE_BATTLE_TEST("Destiny Bond faints the opposing mon if it fainted from the
}
}
SINGLE_BATTLE_TEST("Destiny Bond fails if used sequentially in Gen 7+")
SINGLE_BATTLE_TEST("Destiny Bond doesn't fail if used sequentially (Gen2-6)")
{
GIVEN {
ASSUME(B_DESTINY_BOND_FAIL >= GEN_7);
WITH_CONFIG(GEN_CONFIG_DESTINY_BOND_FAIL, GEN_6);
PLAYER(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
} WHEN {
TURN { MOVE(player, MOVE_DESTINY_BOND); }
TURN { MOVE(player, MOVE_DESTINY_BOND); SWITCH(opponent, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player);
MESSAGE("2 sent out Zigzagoon!");
NOT { MESSAGE("But it failed!"); }
ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player);
}
}
SINGLE_BATTLE_TEST("Destiny Bond fails if used sequentially (Gen7+)")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_DESTINY_BOND_FAIL, GEN_7);
PLAYER(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
@ -39,10 +57,10 @@ SINGLE_BATTLE_TEST("Destiny Bond fails if used sequentially in Gen 7+")
}
}
SINGLE_BATTLE_TEST("Destiny Bond does not fail if used repeatedly separated by other moves in Gen 7+")
SINGLE_BATTLE_TEST("Destiny Bond does not fail if used repeatedly separated by other moves (Gen7+)")
{
GIVEN {
ASSUME(B_DESTINY_BOND_FAIL >= GEN_7);
WITH_CONFIG(GEN_CONFIG_DESTINY_BOND_FAIL, GEN_7);
PLAYER(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
@ -58,10 +76,10 @@ SINGLE_BATTLE_TEST("Destiny Bond does not fail if used repeatedly separated by o
}
}
SINGLE_BATTLE_TEST("Destiny Bond does not fail if used after failing in Gen 7+")
SINGLE_BATTLE_TEST("Destiny Bond does not fail if used after failing (Gen7+)")
{
GIVEN {
ASSUME(B_DESTINY_BOND_FAIL >= GEN_7);
WITH_CONFIG(GEN_CONFIG_DESTINY_BOND_FAIL, GEN_7);
PLAYER(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
@ -108,4 +126,3 @@ TO_DO_BATTLE_TEST("Destiny Bond's effect can trigger on the next turn if the use
TO_DO_BATTLE_TEST("Destiny Bond can be used multiple times in a row (Gen 2-6)");
TO_DO_BATTLE_TEST("Destiny Bond always fails if it was successfully used the previous turn (Gen 7+)");
TO_DO_BATTLE_TEST("Destiny Bond cannot be used in Raids");

View File

@ -77,7 +77,7 @@ WILD_BATTLE_TEST("Embargo doesn't block held item effects that affect effort val
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_WEIGHT); }
OPPONENT(SPECIES_CATERPIE) { HP(1); }
ASSUME(gItemsInfo[ITEM_POWER_WEIGHT].holdEffect == HOLD_EFFECT_POWER_ITEM);
ASSUME(gItemsInfo[ITEM_POWER_WEIGHT].holdEffectParam == 8);
ASSUME(gItemsInfo[ITEM_POWER_WEIGHT].holdEffectParam != 0);
ASSUME(gItemsInfo[ITEM_POWER_WEIGHT].secondaryId == STAT_HP);
ASSUME(gSpeciesInfo[SPECIES_CATERPIE].evYield_HP == 1);
} WHEN {

View File

@ -27,6 +27,33 @@ SINGLE_BATTLE_TEST("Endure does not prevent multiple hits and stat changes occur
}
}
DOUBLE_BATTLE_TEST("Endure is not transferred to a mon that is switched in due to Eject Button")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT) { HP(1); Item(ITEM_EJECT_BUTTON); }
OPPONENT(SPECIES_SQUIRTLE) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(opponentRight, MOVE_ENDURE);
MOVE(playerLeft, MOVE_POUND, target: opponentRight);
SEND_OUT(opponentRight, 2);
MOVE(playerRight, MOVE_POUND, target: opponentRight);
SEND_OUT(opponentRight, 3);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerLeft);
MESSAGE("The opposing Wynaut endured the hit!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerRight);
NOT MESSAGE("The opposing Squirtle endured the hit!");
}
}
TO_DO_BATTLE_TEST("Endure's success rate decreases for every consecutively used turn");
TO_DO_BATTLE_TEST("Endure uses the same counter as Protect");
TO_DO_BATTLE_TEST("Endure doesn't trigger effects that require damage to be done to the Pokémon (Gen 2-4)"); // Eg. Rough Skin

View File

@ -58,4 +58,19 @@ SINGLE_BATTLE_TEST("Entrainment fails if the target's ability has cantBeOverwrit
}
}
SINGLE_BATTLE_TEST("Entrainment causes primal weather to revert")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
} WHEN {
TURN { MOVE(player, MOVE_ENTRAINMENT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ENTRAINMENT, player);
MESSAGE("The extremely harsh sunlight faded!");
} THEN {
EXPECT(opponent->ability == ABILITY_TELEPATHY);
}
}
TO_DO_BATTLE_TEST("Entrainment fails on Dynamaxed Pokémon");

View File

@ -119,7 +119,7 @@ AI_SINGLE_BATTLE_TEST("AI won't use status moves if the player's best attacking
ASSUME(GetMoveEffect(MOVE_FOCUS_PUNCH) == EFFECT_FOCUS_PUNCH);
ASSUME(GetMoveCategory(MOVE_SWORDS_DANCE) == DAMAGE_CATEGORY_STATUS);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_SNORLAX) { Moves(MOVE_FOCUS_PUNCH, MOVE_TACKLE); }
PLAYER(SPECIES_SNORLAX) { Moves(MOVE_FOCUS_PUNCH, MOVE_POUND); }
OPPONENT(SPECIES_CLEFABLE) { Moves(MOVE_PLAY_ROUGH, MOVE_SWORDS_DANCE); }
} WHEN {
TURN { MOVE(player, MOVE_FOCUS_PUNCH); EXPECT_MOVE(opponent, MOVE_PLAY_ROUGH); }

View File

@ -80,10 +80,27 @@ SINGLE_BATTLE_TEST("Powder doesn't damage target if it has Magic Guard")
}
}
SINGLE_BATTLE_TEST("Powder doesn't damage target under heavy rain")
SINGLE_BATTLE_TEST("Powder damages the target under heavy rain (Gen 6)")
{
GIVEN {
ASSUME(B_POWDER_RAIN >= GEN_7);
WITH_CONFIG(GEN_CONFIG_POWDER_RAIN, GEN_6);
PLAYER(SPECIES_KYOGRE_PRIMAL) { Ability(ABILITY_PRIMORDIAL_SEA); }
OPPONENT(SPECIES_VIVILLON);
} WHEN {
TURN { MOVE(opponent, MOVE_POWDER); MOVE(player, MOVE_EMBER); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_POWDER, opponent);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(player);
} THEN {
EXPECT_LT(player->hp, player->maxHP);
}
}
SINGLE_BATTLE_TEST("Powder doesn't damage target under heavy rain (Gen 7+)")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_POWDER_RAIN, GEN_7);
PLAYER(SPECIES_KYOGRE_PRIMAL) { Ability(ABILITY_PRIMORDIAL_SEA); }
OPPONENT(SPECIES_VIVILLON);
} WHEN {
@ -92,7 +109,7 @@ SINGLE_BATTLE_TEST("Powder doesn't damage target under heavy rain")
ANIMATION(ANIM_TYPE_MOVE, MOVE_POWDER, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent);
HP_BAR(player);
}
} THEN {
EXPECT_EQ(player->maxHP, player->hp);

View File

@ -675,3 +675,58 @@ SINGLE_BATTLE_TEST("Protect: Protective Pads protects from secondary effects")
}
}
}
DOUBLE_BATTLE_TEST("Protect is not transferred to a mon that is switched in due to Eject Button")
{
GIVEN {
PLAYER(SPECIES_URSHIFU) { Ability(ABILITY_UNSEEN_FIST); };
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT) { Item(ITEM_EJECT_BUTTON); }
OPPONENT(SPECIES_SQUIRTLE);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(opponentRight, MOVE_PROTECT);
MOVE(playerLeft, MOVE_POUND, target: opponentRight);
SEND_OUT(opponentRight, 2);
MOVE(playerRight, MOVE_POUND, target: opponentRight);
SEND_OUT(opponentRight, 3);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerRight);
HP_BAR(opponentRight);
}
}
DOUBLE_BATTLE_TEST("Wide Guard is still activate even if user is switched out due to Eject Button")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT) { Item(ITEM_EJECT_BUTTON); }
OPPONENT(SPECIES_SQUIRTLE);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(opponentRight, MOVE_WIDE_GUARD);
MOVE(playerLeft, MOVE_POUND, target: opponentRight);
SEND_OUT(opponentRight, 2);
MOVE(playerRight, MOVE_HYPER_VOICE, target: opponentRight);
SEND_OUT(opponentRight, 3);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WIDE_GUARD, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, playerRight);
HP_BAR(opponentLeft);
HP_BAR(opponentRight);
}
}
}

View File

@ -251,7 +251,6 @@ SINGLE_BATTLE_TEST("Rage Fist base power is not increased if move had no affect"
SINGLE_BATTLE_TEST("Rage Fist base power is increased if Disguise breaks (Gen7)")
{
KNOWN_FAILING;
s16 timesGotHit[2];
u16 species = SPECIES_NONE;

View File

@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Role Play copies target's ability")
} THEN {
EXPECT_EQ(player->ability, ABILITY_BLAZE);
EXPECT_EQ(opponent->ability, ABILITY_BLAZE);
}
}
}
DOUBLE_BATTLE_TEST("Role Play copies target's current ability even if it changed during that turn")
@ -93,7 +93,8 @@ SINGLE_BATTLE_TEST("Role Play fails if user's ability can't be suppressed")
u32 species, ability;
PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; }
PARAMETRIZE { species = SPECIES_DARMANITAN; ability = ABILITY_ZEN_MODE; }
if (B_UPDATED_ABILITY_DATA >= GEN_7)
PARAMETRIZE { species = SPECIES_DARMANITAN; ability = ABILITY_ZEN_MODE; }
PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; }
PARAMETRIZE { species = SPECIES_MINIOR; ability = ABILITY_SHIELDS_DOWN; }
PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; }

View File

@ -6,10 +6,26 @@ ASSUMPTIONS
ASSUME(GetMoveEffect(MOVE_SHEER_COLD) == EFFECT_SHEER_COLD);
}
SINGLE_BATTLE_TEST("Sheer Cold doesn't affect Ice-type Pokémon")
SINGLE_BATTLE_TEST("Sheer Cold doesn't affect Ice-type Pokémon (Gen3-6)")
{
GIVEN {
ASSUME(B_SHEER_COLD_IMMUNITY >= GEN_7);
WITH_CONFIG(GEN_CONFIG_SHEER_COLD_IMMUNITY, GEN_6);
ASSUME(GetSpeciesType(SPECIES_GLALIE, 0) == TYPE_ICE);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_GLALIE);
} WHEN {
TURN { MOVE(player, MOVE_SHEER_COLD); }
} SCENE {
NOT MESSAGE("It doesn't affect the opposing Glalie…");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHEER_COLD, player);
HP_BAR(opponent, hp: 0);
}
}
SINGLE_BATTLE_TEST("Sheer Cold doesn't affect Ice-type Pokémon (Gen7+)")
{
GIVEN {
WITH_CONFIG(GEN_CONFIG_SHEER_COLD_IMMUNITY, GEN_7);
ASSUME(GetSpeciesType(SPECIES_GLALIE, 0) == TYPE_ICE);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_GLALIE);

View File

@ -27,3 +27,17 @@ DOUBLE_BATTLE_TEST("Uproar status causes sleeping Pokémon to wake up during an
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
}
}
SINGLE_BATTLE_TEST("Uproar wakes up other pokemon on field")
{
GIVEN {
ASSUME(B_UPROAR_TURNS >= GEN_5);
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_UPROAR); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_UPROAR, opponent);
MESSAGE("The uproar woke Wobbuffet!");
}
}

View File

@ -0,0 +1,86 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(MoveHasAdditionalEffect(MOVE_WRAP, MOVE_EFFECT_WRAP));
}
SINGLE_BATTLE_TEST("Wrap can damage the wrapped mon for 5 turns 50% of the time")
{
PASSES_RANDOMLY(50, 100, RNG_WRAP);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_WRAP); }
TURN {}
TURN {}
TURN {}
TURN {}
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WRAP, player);
HP_BAR(opponent); // Direct damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
NOT HP_BAR(opponent); // Residual Damage
}
}
SINGLE_BATTLE_TEST("Wrap can damage the wrapped mon for 4 turns 50% of the time")
{
PASSES_RANDOMLY(50, 100, RNG_WRAP);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_WRAP); }
TURN {}
TURN {}
TURN {}
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WRAP, player);
HP_BAR(opponent); // Direct damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
NOT HP_BAR(opponent); // Residual Damage
}
}
SINGLE_BATTLE_TEST("Wrap can damage the wrapped mon 7 turns while holding a Grip Claw")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_GRIP_CLAW); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_WRAP); }
TURN {}
TURN {}
TURN {}
TURN {}
TURN {}
TURN {}
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WRAP, player);
HP_BAR(opponent); // Direct damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
HP_BAR(opponent); // Residual Damage
NOT HP_BAR(opponent); // Residual Damage
}
}

View File

@ -690,7 +690,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo
ASSUME(GetMoveEffect(MOVE_UPROAR) == EFFECT_UPROAR);
PLAYER(SPECIES_ZIGZAGOON);
PLAYER(SPECIES_ZIGZAGOON);
PLAYER(SPECIES_ZIGZAGOON);
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_CELEBRATE); }
OPPONENT(SPECIES_ZIGZAGOON);
OPPONENT(SPECIES_ZIGZAGOON);
} WHEN {

View File

@ -77,3 +77,17 @@ SINGLE_BATTLE_TEST("Thunder Wave doesn't affect Electric types in Gen6+")
MESSAGE("It doesn't affect the opposing Pikachu…");
}
}
SINGLE_BATTLE_TEST("Thunder Wave doesn't print an effectiveness message")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_PIDGEY].types[1] == TYPE_FLYING);
PLAYER(SPECIES_PIDGEY);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_THUNDER_WAVE); }
} SCENE {
MESSAGE("The opposing Wobbuffet used Thunder Wave!");
NOT MESSAGE("It's super effective!");
}
}

View File

@ -169,6 +169,7 @@ static const struct Trainer sTestTrainer2 =
TEST("Trainer Class Balls apply to the entire party")
{
ASSUME(B_TRAINER_CLASS_POKE_BALLS >= GEN_8);
u32 j;
struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon));
CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainer2, TRUE, BATTLE_TYPE_TRAINER);

View File

@ -109,7 +109,7 @@ SINGLE_BATTLE_TEST("Trainer Slide: Enemy Mon Unaffected")
{
gBattleTestRunnerState->data.recordedBattle.opponentA = TRAINER_SLIDE_ENEMY_MON_UNAFFECTED;
GIVEN {
ASSUME(B_SHEER_COLD_IMMUNITY >= GEN_7);
WITH_CONFIG(GEN_CONFIG_SHEER_COLD_IMMUNITY, GEN_7);
ASSUME(GetSpeciesType(SPECIES_GLALIE, 0) == TYPE_ICE);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_GLALIE);

View File

@ -446,6 +446,11 @@ top:
case STATE_EXIT:
MgbaExit_(gTestRunnerState.exitCode);
break;
default:
MgbaOpen_();
Test_MgbaPrintf("\e[31mInvalid TestRunner state, exiting\e[0m");
gTestRunnerState.exitCode = 1;
gTestRunnerState.state = STATE_EXIT;
}
if (gMain.callback2 == CB2_TestRunner)

View File

@ -1564,9 +1564,14 @@ void OpenPokemon(u32 sourceLine, u32 side, u32 species)
(*partySize)++;
CreateMon(DATA.currentMon, species, 100, 0, TRUE, 0, OT_ID_PRESET, 0);
data = MOVE_NONE;
// Reset move IDs, but force PP to be non-zero. This is a safeguard against test species that only learn 1 move having test moves with 0 PP
for (i = 0; i < MAX_MON_MOVES; i++)
{
data = MOVE_NONE;
SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &data);
data = 0x7F; // Max PP possible
SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &data);
}
data = 0;
if (B_FRIENDSHIP_BOOST)
{
@ -2112,6 +2117,7 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 *
SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &pp);
*moveSlot = i;
*moveId = ctx->move;
INVALID_IF(GetMovePP(ctx->move) == 0, "%S has 0 PP!", GetMoveName(ctx->move));
break;
}
}
@ -2216,7 +2222,7 @@ void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx)
DATA.battleRecordTurns[DATA.turns][battlerId].secondaryEffect = 1 + ctx.secondaryEffect;
if (ctx.explicitRNG)
DATA.battleRecordTurns[DATA.turns][battlerId].rng = ctx.rng;
u32 shellSideArmCount = 0;
for (u32 i = 0; i < STATE->battlersCount; i++)
{

View File

@ -675,7 +675,7 @@ TEST("Battle strings fit on the battle message window")
case STRINGID_PKMNSXWOREOFF:
case STRINGID_BUFFERENDS:
case STRINGID_FOREWARNACTIVATES:
case STRINGID_CUSEDBODYDISABLED:
case STRINGID_CURSEDBODYDISABLED:
case STRINGID_CURRENTMOVECANTSELECT:
case STRINGID_TARGETISHURTBYSALTCURE:
PREPARE_MOVE_BUFFER(gBattleTextBuff1, longMoveID);

File diff suppressed because it is too large Load Diff