Merge branch 'battle_engine' into battle_ai

This commit is contained in:
Eduardo Quezada D'Ottone 2021-11-21 14:46:09 -03:00 committed by GitHub
commit dee7f97a8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 659 additions and 275 deletions

View File

@ -1877,6 +1877,10 @@
.2byte \species
.4byte \ptr
.endm
.macro tryendneutralizinggas battler:req
various \battler, VARIOUS_TRY_END_NEUTRALIZING_GAS
.endm
.macro trytoapplymimicry battler:req, ptr:req
various \battler, VARIOUS_TRY_TO_APPLY_MIMICRY

View File

@ -2506,20 +2506,30 @@ Move_GIGA_IMPACT:
loadspritegfx ANIM_TAG_IMPACT
monbg ANIM_DEF_PARTNER
setalpha 12, 8
createvisualtask AnimTask_IsContest, 2
jumprettrue SetGigaImpactContestsBG
createvisualtask AnimTask_IsTargetPlayerSide, 2
jumpretfalse SetGigaImpactOpponentBG
goto SetGigaImpactPlayerBG
SetGigaImpactOpponentBG:
fadetobg BG_GIGA_IMPACT_OPPONENT
goto GigaImpactContinuity
SetGigaImpactPlayerBG:
fadetobg BG_GIGA_IMPACT_PLAYER
goto GigaImpactContinuity
SetGigaImpactContestsBG:
fadetobg BG_GIGA_IMPACT_CONTEST
goto GigaImpactContinuity
GigaImpactContinuity:
playsewithpan SE_M_TAKE_DOWN, SOUND_PAN_ATTACKER
createsprite gVerticalDipSpriteTemplate, ANIM_ATTACKER, 2, 6, 1, ANIM_ATTACKER
waitforvisualfinish
delay 11
createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 26, 0, 0, 5
delay 6
@monbg ANIM_DEF_PARTNER
@setalpha 12, 8
@createvisualtask AnimTask_WindUpLunge, 5, 7, 0, -18, 8, 23, 10, 40, 10
@delay 35
createsprite gComplexPaletteBlendSpriteTemplate, 2, 7, 31, 3, 1, 0, 10, 0, 0
waitbgfadeout
createsprite gBasicHitSplatSpriteTemplate, 4, 4, -10, 0, 1, 0
playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET
call SetImpactBackground
delay 1
createsprite gSlideMonToOffsetSpriteTemplate 2, 5, 1, -16, 0, 0, 4
waitforvisualfinish
@ -2534,6 +2544,7 @@ Move_GIGA_IMPACT:
blendoff
restorebg
waitbgfadein
waitforvisualfinish
end
Move_NASTY_PLOT:
@ -7279,7 +7290,7 @@ Move_RELIC_SONG:
monbg ANIM_DEF_PARTNER
launchtask AnimTask_MusicNotesRainbowBlend 0x2 0x0
waitforvisualfinish
panse_1B 0x1DF, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0 @ ???
createvisualtask SoundTask_PlayCryWithEcho, 2, ANIM_ATTACKER, 2
launchtask AnimTask_UproarDistortion 0x2 0x1 0x0
launchtemplate gUproarRingSpriteTemplate 0x3 0x6 0x0 0x0 0x0 0x0 0x1f 0x8
launchtemplate gJaggedMusicNoteSpriteTemplate 0x2 0x4 0x0 0x1d 0xfff4 0x0

View File

@ -2187,6 +2187,7 @@ BattleScript_EffectSimpleBeam:
trytoclearprimalweather
printstring STRINGID_EMPTYSTRING3
waitmessage 1
tryendneutralizinggas BS_TARGET
goto BattleScript_MoveEnd
BattleScript_EffectSuckerPunch:
@ -2409,6 +2410,7 @@ BattleScript_EffectGastroAcid:
trytoclearprimalweather
printstring STRINGID_EMPTYSTRING3
waitmessage 1
tryendneutralizinggas BS_TARGET
goto BattleScript_MoveEnd
BattleScript_EffectToxicSpikes:
@ -8378,6 +8380,12 @@ BattleScript_SwitchInAbilityMsg::
waitmessage B_WAIT_TIME_LONG
end3
BattleScript_SwitchInAbilityMsgRet::
call BattleScript_AbilityPopUp
printfromtable gSwitchInAbilityStringIds
waitmessage B_WAIT_TIME_LONG
return
BattleScript_ActivateAsOne::
call BattleScript_AbilityPopUp
printfromtable gSwitchInAbilityStringIds
@ -9231,3 +9239,19 @@ BattleScript_PastelVeilLoopIncrement:
goto BattleScript_PastelVeilEnd
BattleScript_PastelVeilEnd:
end3
sByteFour:
.byte MAX_BATTLERS_COUNT
BattleScript_NeutralizingGasExits::
savetarget
pause B_WAIT_TIME_SHORT
printstring STRINGID_NEUTRALIZINGGASOVER
waitmessage B_WAIT_TIME_LONG
setbyte gBattlerTarget, 0
BattleScript_NeutralizingGasExitsLoop:
switchinabilities BS_TARGET
addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, sByteFour, BattleScript_NeutralizingGasExitsLoop @ SOMEHOW, comparing to gBattlersCount is problematic.
restoretarget
return

View File

@ -1,19 +0,0 @@
JASC-PAL
0100
16
0 0 0
255 214 0
255 197 0
255 173 0
255 165 0
148 90 222
255 107 0
255 132 0
255 148 0
255 156 41
0 0 0
0 90 0
0 0 0
0 0 0
0 0 0
0 0 0

View File

@ -0,0 +1,19 @@
JASC-PAL
0100
16
0 0 0
240 136 184
232 104 168
136 8 40
248 24 104
216 32 96
224 72 136
160 0 48
216 0 64
200 40 88
192 0 56
176 32 128
176 24 72
152 16 56
200 48 80
216 56 160

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,3 @@
<EFBFBD>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> D!E!F!G!H!I!@!<21>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> њ ћ ќ § ў џ ђ Ј$Ї$І$Ѕ$Є$Ѓ$Ђ$Ё$ $  Ё Ђ Ѓ Є Ѕ І Ї Ј Љ Њ Ћ Ќ ­ Ў Џ
! ! ! !!!!И$З$Ж$Е$Д$Г$В$Б$А$А Б В Г Д Е Ж З И Й К Л М Н О П !!!!!!!Ш$Ч$Ц$Х$Ф$У$Т$С$Р$Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я *!+!,!-!.!/!"!и$з$ж$е$д$г$в$б$а$а б в г д е ж з и й к л м н о п :!;!<!=!>!?!2!ш$ч$ц$х$ф$у$т$с$р$р с т у ф х ц ч ш щ ъ ы ь э ю я J!K!L!M!N!O!B!ш,ч,ц,х,ф,у,т,с,р,р(с(т(у(ф(х(ц(ч(ш(щ(ъ(ы(ь(э(ю(я(J)K)L)M)N)O)B)и,з,ж,е,д,г,в,б,а,а(б(в(г(д(е(ж(з(и(й(к(л(м(н(о(п(:);)<)=)>)?)2)Ш,Ч,Ц,Х,Ф,У,Т,С,Р,Р(С(Т(У(Ф(Х(Ц(Ч(Ш(Щ(Ъ(Ы(Ь(Э(Ю(Я(*)+),)-).)/)")И,З,Ж,Е,Д,Г,В,Б,А,А(Б(В(Г(Д(Е(Ж(З(И(Й(К(Л(М(Н(О(П()))))))Ј,Ї,І,Ѕ,Є,Ѓ,Ђ,Ё, , (Ё(Ђ(Ѓ(Є(Ѕ(І(Ї(Ј(Љ(Њ(Ћ(Ќ(­(Ў(Џ(
) ) ) ))))<29>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(њ(ћ(ќ(§(ў(џ(ђ(<28>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(D)E)F)G)H)I)@)

View File

@ -1,19 +0,0 @@
JASC-PAL
0100
16
41 49 49
106 139 189
246 131 180
255 0 255
255 16 98
238 98 164
230 65 131
222 0 57
222 24 90
205 41 74
205 32 82
189 0 49
172 16 65
156 0 41
148 16 49
131 8 32

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,19 +0,0 @@
JASC-PAL
0100
16
0 0 0
255 255 255
255 0 255
255 16 98
246 131 180
238 98 164
230 65 131
222 0 57
222 24 90
205 32 82
205 41 74
189 0 49
172 16 65
156 0 41
148 16 49
131 8 32

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,3 +0,0 @@
@%I%H%G%F%E%D%<25>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24> <20> <20> <20> <20> <20> <20> <20> <20> ђ$џ$ў$§$ќ$ћ$њ$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24>$<24> <20> <20> <20> <20> <20> <20> <20> <20> %%% % % %
%Џ$Ў$­$Ќ$Ћ$Њ$Љ$Ј$Ї$І$Ѕ$Є$Ѓ$Ђ$Ё$ $  Ё Ђ Ѓ Є Ѕ І Ї Ј %%%%%%%П$О$Н$М$Л$К$Й$И$З$Ж$Е$Д$Г$В$Б$А$А Б В Г Д Е Ж З И "%/%.%-%,%+%*%Я$Ю$Э$Ь$Ы$Ъ$Щ$Ш$Ч$Ц$Х$Ф$У$Т$С$Р$Р С Т У Ф Х Ц Ч Ш 2%?%>%=%<%;%:%п$о$н$м$л$к$й$и$з$ж$е$д$г$в$б$а$а б в г д е ж з и B%O%N%M%L%K%J%я$ю$э$ь$ы$ъ$щ$ш$ч$ц$х$ф$у$т$с$р$р с т у ф х ц ч ш B-O-N-M-L-K-J-я,ю,э,ь,ы,ъ,щ,ш,ч,ц,х,ф,у,т,с,р,р(с(т(у(ф(х(ц(ч(ш(2-?->-=-<-;-:-п,о,н,м,л,к,й,и,з,ж,е,д,г,в,б,а,а(б(в(г(д(е(ж(з(и("-/-.---,-+-*-Я,Ю,Э,Ь,Ы,Ъ,Щ,Ш,Ч,Ц,Х,Ф,У,Т,С,Р,Р(С(Т(У(Ф(Х(Ц(Ч(Ш(-------П,О,Н,М,Л,К,Й,И,З,Ж,Е,Д,Г,В,Б,А,А(Б(В(Г(Д(Е(Ж(З(И(--- - - -
-Џ,Ў,­,Ќ,Ћ,Њ,Љ,Ј,Ї,І,Ѕ,Є,Ѓ,Ђ,Ё, , (Ё(Ђ(Ѓ(Є(Ѕ(І(Ї(Ј(ђ,џ,ў,§,ќ,ћ,њ,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(@-I-H-G-F-E-D-<2D>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>,<2C>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(<28>(

View File

@ -62,12 +62,13 @@ struct ResourceFlags
u32 flags[4];
};
#define RESOURCE_FLAG_FLASH_FIRE 0x1
#define RESOURCE_FLAG_ROOST 0x2
#define RESOURCE_FLAG_UNBURDEN 0x4
#define RESOURCE_FLAG_INTIMIDATED 0x8
#define RESOURCE_FLAG_TRACED 0x10
#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20
#define RESOURCE_FLAG_FLASH_FIRE 0x1
#define RESOURCE_FLAG_ROOST 0x2
#define RESOURCE_FLAG_UNBURDEN 0x4
#define RESOURCE_FLAG_INTIMIDATED 0x8
#define RESOURCE_FLAG_TRACED 0x10
#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20
#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40
struct DisableStruct
{
@ -184,6 +185,8 @@ struct SpecialStatus
u8 damagedMons:4; // Mons that have been damaged directly by using a move, includes substitute.
u8 dancerUsedMove:1;
u8 dancerOriginalTarget:3;
u8 announceNeutralizingGas:1; // See Cmd_switchineffects
u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS
s32 dmg;
s32 physicalDmg;
s32 specialDmg;
@ -236,7 +239,7 @@ struct WishFutureKnock
u8 futureSightAttacker[MAX_BATTLERS_COUNT];
u16 futureSightMove[MAX_BATTLERS_COUNT];
u8 wishCounter[MAX_BATTLERS_COUNT];
u8 wishMonId[MAX_BATTLERS_COUNT];
u8 wishPartyId[MAX_BATTLERS_COUNT];
u8 weatherDuration;
u8 knockedOffMons[2]; // Each battler is represented by a bit. The array entry is dependent on the battler's side.
};

View File

@ -53,10 +53,13 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent);
bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect);
bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex);
bool32 IsRecycleEncouragedItem(u16 item);
bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item);
bool32 IsStatBoostingBerry(u16 item);
bool32 CanKnockOffItem(u8 battler, u16 item);
bool32 IsAbilityOfRating(u16 ability, s8 rating);
s8 GetAbilityRating(u16 ability);
bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability);
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move);
// stat stage checks
bool32 AnyStatIsRaised(u8 battlerId);

View File

@ -261,6 +261,7 @@ extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[];
extern const u8 BattleScript_PoisonHealActivates[];
extern const u8 BattleScript_BadDreamsActivates[];
extern const u8 BattleScript_SwitchInAbilityMsg[];
extern const u8 BattleScript_SwitchInAbilityMsgRet[];
extern const u8 BattleScript_ToxicSpikesPoisoned[];
extern const u8 BattleScript_ToxicSpikesAbsorbed[];
extern const u8 BattleScript_StickyWebOnSwitchIn[];
@ -413,5 +414,6 @@ extern const u8 BattleScript_AttackerFormChangeEnd3NoPopup[];
extern const u8 BattleScript_AttackerFormChangeMoveEffect[];
extern const u8 BattleScript_BothCanNoLongerEscape[];
extern const u8 BattleScript_OctolockEndTurn[];
extern const u8 BattleScript_NeutralizingGasExits[];
#endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -8,21 +8,23 @@
#define MOVE_LIMITATION_TAUNT (1 << 4)
#define MOVE_LIMITATION_IMPRISON (1 << 5)
#define ABILITYEFFECT_ON_SWITCHIN 0x0
#define ABILITYEFFECT_ENDTURN 0x1
#define ABILITYEFFECT_MOVES_BLOCK 0x2
#define ABILITYEFFECT_ABSORBING 0x3
#define ABILITYEFFECT_MOVE_END_ATTACKER 0x4
#define ABILITYEFFECT_MOVE_END 0x5
#define ABILITYEFFECT_IMMUNITY 0x6
#define ABILITYEFFECT_FORECAST 0x7
#define ABILITYEFFECT_SYNCHRONIZE 0x8
#define ABILITYEFFECT_ATK_SYNCHRONIZE 0x9
#define ABILITYEFFECT_INTIMIDATE1 0xA
#define ABILITYEFFECT_INTIMIDATE2 0xB
#define ABILITYEFFECT_TRACE1 0xC
#define ABILITYEFFECT_TRACE2 0xD
#define ABILITYEFFECT_MOVE_END_OTHER 0xE
#define ABILITYEFFECT_ON_SWITCHIN 0
#define ABILITYEFFECT_ENDTURN 1
#define ABILITYEFFECT_MOVES_BLOCK 2
#define ABILITYEFFECT_ABSORBING 3
#define ABILITYEFFECT_MOVE_END_ATTACKER 4
#define ABILITYEFFECT_MOVE_END 5
#define ABILITYEFFECT_IMMUNITY 6
#define ABILITYEFFECT_FORECAST 7
#define ABILITYEFFECT_SYNCHRONIZE 8
#define ABILITYEFFECT_ATK_SYNCHRONIZE 9
#define ABILITYEFFECT_INTIMIDATE1 10
#define ABILITYEFFECT_INTIMIDATE2 11
#define ABILITYEFFECT_TRACE1 12
#define ABILITYEFFECT_TRACE2 13
#define ABILITYEFFECT_MOVE_END_OTHER 14
#define ABILITYEFFECT_NEUTRALIZINGGAS 15
// Special cases
#define ABILITYEFFECT_SWITCH_IN_TERRAIN 0xFE
#define ABILITYEFFECT_SWITCH_IN_WEATHER 0xFF
@ -102,6 +104,7 @@ u32 IsAbilityOnOpposingSide(u32 battlerId, u32 ability);
u32 IsAbilityOnField(u32 ability);
u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability);
u32 IsAbilityPreventingEscape(u32 battlerId);
bool32 IsBattlerProtected(u8 battlerId, u16 move);
bool32 CanBattlerEscape(u32 battlerId); // no ability check
void BattleScriptExecute(const u8* BS_ptr);
void BattleScriptPushCursorAndCallback(const u8* BS_ptr);

View File

@ -51,6 +51,7 @@
#define SPECIES_MELOETTA_PIROUETTE 10019
#define SPECIES_MORPEKO 0
#define SPECIES_MORPEKO_HANGRY 10020
#define SPECIES_SIRFETCHD 10021
#endif
// Items with peculiar battle effects.
@ -91,6 +92,9 @@
#define GEN_8 5
#endif
// Mega Evolution settings
#define B_MEGA_EVO_TURN_ORDER GEN_7 // In Gen7, a Pokémon's Speed after Mega Evolution is used to determine turn order, not its Speed before.
// Calculation settings
#define B_CRIT_CHANCE GEN_7 // Chances of a critical hit landing. See CalcCritChanceStage.
#define B_CRIT_MULTIPLIER GEN_7 // In Gen6+, critical hits multiply damage by 1.5 instead of 2.
@ -114,6 +118,7 @@
#define B_PAYBACK_SWITCH_BOOST GEN_7 // In Gen5+, if the opponent switches out, Payback's damage will no longer be doubled.
#define B_HIDDEN_POWER_DMG GEN_7 // In Gen6+, Hidden Power's base power was set to always be 60. Before, it was determined by the mon's IVs.
#define B_ROUGH_SKIN_DMG GEN_7 // In Gen4+, Rough Skin contact damage is 1/8th of max HP instead of 1/16th. This will also affect Iron Barbs.
#define B_KNOCK_OFF_DMG GEN_8 // In Gen6+, Knock Off deals 50% more damage when knocking off an item
// Type settings
#define B_GHOSTS_ESCAPE GEN_7 // In Gen6+, abilities like Shadow Tag or moves like Mean Look fail on Ghost-type Pokémon. They can also escape any Wild Battle.
@ -152,6 +157,9 @@
#define B_MEMENTO_FAIL GEN_7 // In Gen4+, Memento fails if there is no target or if the target is protected or behind substitute. But not if Atk/Sp. Atk are at -6.
#define B_GLARE_GHOST GEN_7 // In Gen4+, Glare can hit Ghost-type Pokémon normally.
#define B_SKILL_SWAP GEN_7 // In Gen4+, Skill Swap triggers switch-in abilities after use.
#define B_BRICK_BREAK GEN_7 // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune.
#define B_WISH_HP_SOURCE GEN_7 // In Gen5+, Wish heals half of the user's max HP instead of the target's.
#define B_RAMPAGE_CANCELLING GEN_7 // In Gen5+, a failed Thrash, etc, will cancel except on its last turn.
// Ability settings
#define B_ABILITY_WEATHER GEN_7 // In Gen6+, ability-induced weather lasts 5 turns. Before, it lasted until the battle ended or until it was changed by a move or a different weather-affecting ability.
@ -181,6 +189,8 @@
#define B_LURE_BALL_MODIFIER GEN_7 // In Gen7+, Lure Ball's catch multiplier is x5 instead of x3.
#define B_HEAVY_BALL_MODIFIER GEN_7 // In Gen7+, Heavy Ball's ranges change. See Cmd_handleballthrow.
#define B_DREAM_BALL_MODIFIER GEN_8 // In Gen8, Dream Ball's catch multiplier is x4 when the target is asleep or has the ability Comatose.
#define B_SERENE_GRACE_BOOST GEN_7 // In Gen5+, Serene Grace boosts the added flinch chance of King's Rock and Razor Fang.
#define B_LEEK_ALWAYS_CRIT GEN_7 // In Gen6+, if a Farfetch'd or Sirfetch'd holding a Leek use a move with increased Critical Hit ratio, it will always result in a Critical Hit.
// Flag settings
// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to.

View File

@ -207,6 +207,7 @@
#define VARIOUS_CHECK_POLTERGEIST 134
#define VARIOUS_SET_OCTOLOCK 135
#define VARIOUS_CUT_1_3_HP_RAISE_STATS 136
#define VARIOUS_TRY_END_NEUTRALIZING_GAS 137
// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0
@ -225,6 +226,7 @@
// Cmd_statbuffchange
#define STAT_BUFF_ALLOW_PTR (1 << 0) // If set, allow use of jumpptr. Set in every use of statbuffchange
#define STAT_BUFF_NOT_PROTECT_AFFECTED (1 << 5)
#define STAT_BUFF_UPDATE_MOVE_EFFECT (1 << 6)
// stat change flags for Cmd_playstatchangeanimation
#define STAT_CHANGE_NEGATIVE (1 << 0)

View File

@ -607,8 +607,10 @@
#define STRINGID_PKMNBECAMEWEAKERTOFIRE 604
#define STRINGID_ABOUTTOUSEPOLTERGEIST 605
#define STRINGID_CANTESCAPEBECAUSEOFCURRENTMOVE 606
#define STRINGID_NEUTRALIZINGGASENTERS 607
#define STRINGID_NEUTRALIZINGGASOVER 608
#define BATTLESTRINGS_COUNT 607
#define BATTLESTRINGS_COUNT 609
// The below IDs are all indexes into battle message tables,
// used to determine which of a set of messages to print.
@ -844,6 +846,7 @@
#define B_MSG_SWITCHIN_ASONE 13
#define B_MSG_SWITCHIN_CURIOUS_MEDICINE 14
#define B_MSG_SWITCHIN_PASTEL_VEIL 15
#define B_MSG_SWITCHIN_NEUTRALIZING_GAS 16
// gMentalHerbCureStringIds
#define B_MSG_MENTALHERBCURE_INFATUATION 0

View File

@ -62,12 +62,12 @@
#define HOLD_EFFECT_FIRE_POWER 58
#define HOLD_EFFECT_DRAGON_POWER 59
#define HOLD_EFFECT_NORMAL_POWER 60
#define HOLD_EFFECT_UP_GRADE 61
#define HOLD_EFFECT_UPGRADE 61
#define HOLD_EFFECT_SHELL_BELL 62
#define HOLD_EFFECT_LUCKY_PUNCH 63
#define HOLD_EFFECT_METAL_POWDER 64
#define HOLD_EFFECT_THICK_CLUB 65
#define HOLD_EFFECT_STICK 66
#define HOLD_EFFECT_LEEK 66
// Gen4 hold effects.
#define HOLD_EFFECT_CHOICE_SCARF 67

View File

@ -4937,10 +4937,13 @@ extern const u32 gBattleAnimBgImage_Hurricane[];
extern const u32 gBattleAnimBgPalette_Hurricane[];
extern const u32 gBattleAnimBgTilemap_Hurricane[];
extern const u32 gBattleAnimBgPalette_RockWrecker[];
extern const u32 gBattleAnimBgTilemap_GigaImpactPlayer[];
extern const u32 gBattleAnimBgTilemap_GigaImpactOpponent[];
extern const u32 gBattleAnimBgTilemap_GigaImpactContest[];
extern const u32 gBattleAnimBgImage_GigaImpact[];
extern const u32 gBattleAnimBgPalette_GigaImpact[];
extern const u32 gBattleAnimBgImage_SpacialRend[];
extern const u32 gBattleAnimBgPalette_SpacialRend[];
extern const u32 gBattleAnimBgTilemap_SpacialRendOpponent[];
extern const u32 gBattleAnimBgTilemap_SpacialRendPlayer[];
extern const u32 gBattleAnimBgPalette_DarkVoid[];
extern const u32 gBattleAnimBgTilemap_DarkVoid[];
extern const u32 gBattleAnimBgPalette_Dark[];
@ -4960,7 +4963,6 @@ extern const u32 gBattleAnimBgPalette_Fissure[];
extern const u32 gBattleAnimBgPalette_Bug[];
extern const u32 gBattleAnimBgPalette_Solarbeam[];
extern const u32 gBattleAnimBgPalette_MagmaStorm[];
extern const u32 gBattleAnimBgPalette_GigaImpact[];
extern const u32 gBattleAnimBgPalette_TrickRoom[];
extern const u32 gBattleAnimBgTilemap_Dark[];
extern const u32 gBattleAnimBgTilemap_Ghost[];

View File

@ -1355,22 +1355,22 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
}
break;
case EFFECT_SANDSTORM:
if (gBattleWeather & WEATHER_SANDSTORM_ANY //TODO | WEATHER_PRIMAL_ANY)
if (gBattleWeather & (WEATHER_SANDSTORM_ANY | WEATHER_PRIMAL_ANY)
|| PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove))
score -= 8;
break;
case EFFECT_SUNNY_DAY:
if (gBattleWeather & WEATHER_SUN_ANY //TODO | WEATHER_PRIMAL_ANY)
if (gBattleWeather & (WEATHER_SUN_ANY | WEATHER_PRIMAL_ANY)
|| PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove))
score -= 8;
break;
case EFFECT_RAIN_DANCE:
if (gBattleWeather & WEATHER_RAIN_ANY //TODO | WEATHER_PRIMAL_ANY)
if (gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_PRIMAL_ANY)
|| PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove))
score -= 8;
break;
case EFFECT_HAIL:
if (gBattleWeather & WEATHER_HAIL_ANY //TODO | WEATHER_PRIMAL_ANY)
if (gBattleWeather & (WEATHER_HAIL_ANY | WEATHER_PRIMAL_ANY)
|| PartnerMoveEffectIsWeather(AI_DATA->battlerAtkPartner, AI_DATA->partnerMove))
score -= 8;
break;
@ -2283,7 +2283,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|| IsInstructBannedMove(instructedMove)
|| MoveRequiresRecharging(instructedMove)
|| MoveCallsOtherMove(instructedMove)
#ifdef ITEM_Z_RING
#ifdef ITEM_Z_POWER_RING
//|| (IsZMove(instructedMove))
#endif
|| (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF)
@ -2934,6 +2934,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
{
case ABILITY_MOXIE:
case ABILITY_BEAST_BOOST:
case ABILITY_CHILLING_NEIGH:
case ABILITY_GRIM_NEIGH:
case ABILITY_AS_ONE_ICE_RIDER:
case ABILITY_AS_ONE_SHADOW_RIDER:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker should go first
{
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
@ -2945,7 +2949,6 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
// move effect checks
switch (moveEffect)
{
case EFFECT_HIT:
break;
case EFFECT_SLEEP:
@ -3208,6 +3211,10 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case EFFECT_MULTI_HIT:
case EFFECT_DOUBLE_HIT:
case EFFECT_TRIPLE_KICK:
if (AI_MoveMakesContact(AI_DATA->atkAbility, AI_DATA->atkHoldEffect, move)
&& AI_DATA->atkAbility != ABILITY_MAGIC_GUARD
&& AI_DATA->defHoldEffect == HOLD_EFFECT_ROCKY_HELMET)
score -= 2;
break;
case EFFECT_CONVERSION:
if (!IS_BATTLER_OF_TYPE(battlerAtk, gBattleMoves[gBattleMons[battlerAtk].moves[0]].type))
@ -4066,6 +4073,18 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
score++;
if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk)))
score++;
if (AI_DATA->atkAbility == ABILITY_RIPEN)
{
u16 item = GetUsedHeldItem(battlerAtk);
u16 toHeal = (ItemId_GetHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / ItemId_GetHoldEffectParam(item);
if (IsStatBoostingBerry(item) && atkHpPercent > 60)
score++;
else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0)
&& ((GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0))
|| !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0)))
score++; // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry
}
break;
case EFFECT_BRICK_BREAK:
if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_REFLECT)

View File

@ -193,7 +193,7 @@ static bool8 ShouldSwitchIfWonderGuard(void)
opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(gActiveBattler));
if (gBattleMons[GetBattlerAtPosition(opposingPosition)].ability != ABILITY_WONDER_GUARD)
if (GetBattlerAbility(GetBattlerAtPosition(opposingPosition)) != ABILITY_WONDER_GUARD)
return FALSE;
// Check if Pokemon has a super effective move.
@ -286,7 +286,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void)
else
return FALSE;
if (gBattleMons[gActiveBattler].ability == absorbingTypeAbility)
if (AI_GetAbility(gActiveBattler) == absorbingTypeAbility)
return FALSE;
GetAIPartyIndexes(gActiveBattler, &firstId, &lastId);
@ -337,7 +337,7 @@ static bool8 ShouldSwitchIfNaturalCure(void)
{
if (!(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP))
return FALSE;
if (gBattleMons[gActiveBattler].ability != ABILITY_NATURAL_CURE)
if (AI_GetAbility(gActiveBattler) != ABILITY_NATURAL_CURE)
return FALSE;
if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 2)
return FALSE;

View File

@ -1125,31 +1125,35 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability)
// does NOT include ability suppression checks
s32 AI_GetAbility(u32 battlerId)
{
u32 knownAbility = GetBattlerAbility(battlerId);
// The AI knows its own ability.
if (IsBattlerAIControlled(battlerId))
return gBattleMons[battlerId].ability;
return knownAbility;
// Check neutralizing gas, gastro acid
if (knownAbility == ABILITY_NONE)
return knownAbility;
if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE)
return BATTLE_HISTORY->abilities[battlerId];
// Abilities that prevent fleeing.
if (gBattleMons[battlerId].ability == ABILITY_SHADOW_TAG
|| gBattleMons[battlerId].ability == ABILITY_MAGNET_PULL
|| gBattleMons[battlerId].ability == ABILITY_ARENA_TRAP)
return gBattleMons[battlerId].ability;
// Abilities that prevent fleeing - treat as always known
if (knownAbility == ABILITY_SHADOW_TAG || knownAbility == ABILITY_MAGNET_PULL || knownAbility == ABILITY_ARENA_TRAP)
return knownAbility;
// Else, guess the ability
if (gBaseStats[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE)
{
if (gBaseStats[gBattleMons[battlerId].species].abilities[1] != ABILITY_NONE)
u16 abilityGuess = ABILITY_NONE;
while (abilityGuess == ABILITY_NONE)
{
// AI has no knowledge of opponent, so it guesses which ability.
return gBaseStats[gBattleMons[battlerId].species].abilities[Random() & 1];
}
else
{
return gBaseStats[gBattleMons[battlerId].species].abilities[0]; // It's definitely ability 1.
abilityGuess = gBaseStats[gBattleMons[battlerId].species].abilities[Random() % NUM_ABILITY_SLOTS];
}
return abilityGuess;
}
return ABILITY_NONE; // Unknown.
}
@ -1707,7 +1711,7 @@ u32 CountNegativeStatStages(u8 battlerId)
bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4
@ -1723,7 +1727,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4
@ -1739,7 +1743,7 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (!WillAIStrikeFirst()
@ -1753,7 +1757,7 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4
@ -1768,7 +1772,7 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4
@ -1783,7 +1787,7 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (defAbility != ABILITY_CONTRARY
@ -1797,7 +1801,7 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{
if (WillAIStrikeFirst() && CanAIFaintTarget(battlerAtk, battlerDef, 0))
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy.
if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE
@ -2412,9 +2416,19 @@ static bool32 AnyUsefulStatIsRaised(u8 battler)
return FALSE;
}
struct Pokemon *GetPartyBattlerPartyData(u8 battlerId, u8 switchBattler)
{
struct Pokemon *mon;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
mon = &gPlayerParty[switchBattler];
else
mon = &gEnemyParty[switchBattler];
return mon;
}
static bool32 PartyBattlerShouldAvoidHazards(u8 currBattler, u8 switchBattler)
{
struct Pokemon *mon = GetBattlerPartyData(switchBattler);
struct Pokemon *mon = GetPartyBattlerPartyData(currBattler, switchBattler);
u16 ability = GetMonAbility(mon); // we know our own party data
u16 holdEffect = GetBattlerHoldEffect(GetMonData(mon, MON_DATA_HELD_ITEM), TRUE);
u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES);
@ -3372,6 +3386,47 @@ static const u16 sRecycleEncouragedItems[] =
// TODO expand this
};
// Its assumed that the berry is strategically given, so no need to check benefits of the berry
bool32 IsStatBoostingBerry(u16 item)
{
switch (item)
{
case ITEM_LIECHI_BERRY:
case ITEM_GANLON_BERRY:
case ITEM_SALAC_BERRY:
case ITEM_PETAYA_BERRY:
case ITEM_APICOT_BERRY:
//case ITEM_LANSAT_BERRY:
case ITEM_STARF_BERRY:
#ifdef ITEM_EXPANSION
case ITEM_MICLE_BERRY:
#endif
return TRUE;
default:
return FALSE;
}
}
bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item)
{
switch (item)
{
case ITEM_ORAN_BERRY:
if (gBattleMons[battlerAtk].maxHP <= 50)
return TRUE; // Only worth it in the early game
return FALSE;
case ITEM_SITRUS_BERRY:
case ITEM_FIGY_BERRY:
case ITEM_WIKI_BERRY:
case ITEM_MAGO_BERRY:
case ITEM_AGUAV_BERRY:
case ITEM_IAPAPA_BERRY:
return TRUE;
default:
return FALSE;
}
}
bool32 IsRecycleEncouragedItem(u16 item)
{
u32 i;
@ -3393,6 +3448,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128))
return;
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return; // Damaging moves would get a score boost from AI_TryToFaint or PreferStrongestMove so we don't consider them here
switch (statId)
{
@ -3465,6 +3523,9 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20)
{
if (!HasDamagingMove(battlerDef))
@ -3485,6 +3546,9 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove))
{
(*score)++; // burning is good
@ -3501,6 +3565,9 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove))
{
u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk);
@ -3519,6 +3586,9 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove))
*score += 2;
else
@ -3534,6 +3604,9 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
{
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)
&& AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_CONFUSION
&& AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_STATUS)
@ -3546,3 +3619,12 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
*score += 2;
}
}
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move)
{
if (TestMoveFlags(move, FLAG_MAKES_CONTACT)
&& ability != ABILITY_LONG_REACH
&& holdEffect != HOLD_EFFECT_PROTECTIVE_PADS)
return TRUE;
return FALSE;
}

View File

@ -2052,13 +2052,13 @@ const struct BattleAnimBackground gBattleAnimBackgroundTable[] =
[BG_SOLARBEAM_CONTESTS] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_Solarbeam, gBattleAnimBgTilemap_ImpactContests},
//new bgs
[BG_MAGMA_STORM] = {gBattleAnimBgImage_InAir, gBattleAnimBgPalette_MagmaStorm, gBattleAnimBgTilemap_InAir},
[BG_GIGA_IMPACT_OPPONENT] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_ImpactOpponent},
[BG_GIGA_IMPACT_PLAYER] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_ImpactPlayer},
[BG_GIGA_IMPACT_CONTEST] = {gBattleAnimBgImage_Impact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_ImpactContests},
[BG_GIGA_IMPACT_OPPONENT] = {gBattleAnimBgImage_GigaImpact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_GigaImpactOpponent},
[BG_GIGA_IMPACT_PLAYER] = {gBattleAnimBgImage_GigaImpact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_GigaImpactPlayer},
[BG_GIGA_IMPACT_CONTEST] = {gBattleAnimBgImage_GigaImpact, gBattleAnimBgPalette_GigaImpact, gBattleAnimBgTilemap_GigaImpactContest},
[BG_TRICK_ROOM] = {gBattleAnimBgImage_TrickRoom, gBattleAnimBgPalette_TrickRoom, gBattleAnimBgTilemap_TrickRoom},
[BG_ROCK_WRECKER] = {gBattleAnimBgImage_Hurricane, gBattleAnimBgPalette_RockWrecker, gBattleAnimBgTilemap_Hurricane},
[BG_SPACIAL_REND_ON_OPPONENT] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_SpacialRendOpponent},
[BG_SPACIAL_REND_ON_PLAYER] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_SpacialRendPlayer},
[BG_SPACIAL_REND_ON_OPPONENT] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_GigaImpactOpponent},
[BG_SPACIAL_REND_ON_PLAYER] = {gBattleAnimBgImage_SpacialRend, gBattleAnimBgPalette_SpacialRend, gBattleAnimBgTilemap_GigaImpactPlayer},
[BG_DARK_VOID] = {gBattleAnimBgImage_Waterfall, gBattleAnimBgPalette_DarkVoid, gBattleAnimBgTilemap_DarkVoid},
[BG_WATER] = {gBattleAnimBgImage_HydroPump, gBattleAnimBgPalette_HydroPump, gBattleAnimBgTilemap_HydroPump},
[BG_NIGHTMARE] = {gBattleAnimBgImage_Nightmare, gBattleAnimBgPalette_Nightmare, gBattleAnimBgTilemap_Nightmare},

View File

@ -1924,12 +1924,20 @@ static const u8 sText_HoldEffectPsychicPower[] = _("Psychic Power");
static const u8 sText_HoldEffectFirePower[] = _("Fire Power");
static const u8 sText_HoldEffectDragonPower[] = _("Dragon Power");
static const u8 sText_HoldEffectNormalPower[] = _("Normal Power");
static const u8 sText_HoldEffectUpGrade[] = _("Up Grade");
#ifdef ITEM_EXPANSION
static const u8 sText_HoldEffectUpgrade[] = _("Upgrade");
#else
static const u8 sText_HoldEffectUpgrade[] = _("Up Grade");
#endif
static const u8 sText_HoldEffectShellBell[] = _("Shell Bell");
static const u8 sText_HoldEffectLuckyPunch[] = _("Lucky Punch");
static const u8 sText_HoldEffectMetalPowder[] = _("Metal Powder");
static const u8 sText_HoldEffectThickClub[] = _("Thick Club");
static const u8 sText_HoldEffectStick[] = _("Stick");
#ifdef ITEM_EXPANSION
static const u8 sText_HoldEffectLeek[] = _("Leek");
#else
static const u8 sText_HoldEffectLeek[] = _("Stick");
#endif
static const u8 sText_HoldEffectChoiceScarf[] = _("Choice Scarf");
static const u8 sText_HoldEffectChoiceSpecs[] = _("Choice Specs");
static const u8 sText_HoldEffectDampRock[] = _("Damp Rock");
@ -2064,12 +2072,12 @@ static const u8 *const sHoldEffectNames[] =
[HOLD_EFFECT_FIRE_POWER] = sText_HoldEffectFirePower,
[HOLD_EFFECT_DRAGON_POWER] = sText_HoldEffectDragonPower,
[HOLD_EFFECT_NORMAL_POWER] = sText_HoldEffectNormalPower,
[HOLD_EFFECT_UP_GRADE] = sText_HoldEffectUpGrade,
[HOLD_EFFECT_UPGRADE] = sText_HoldEffectUpgrade,
[HOLD_EFFECT_SHELL_BELL] = sText_HoldEffectShellBell,
[HOLD_EFFECT_LUCKY_PUNCH] = sText_HoldEffectLuckyPunch,
[HOLD_EFFECT_METAL_POWDER] = sText_HoldEffectMetalPowder,
[HOLD_EFFECT_THICK_CLUB] = sText_HoldEffectThickClub,
[HOLD_EFFECT_STICK] = sText_HoldEffectStick,
[HOLD_EFFECT_LEEK] = sText_HoldEffectLeek,
[HOLD_EFFECT_CHOICE_SCARF] = sText_HoldEffectChoiceScarf,
[HOLD_EFFECT_CHOICE_SPECS] = sText_HoldEffectChoiceSpecs,
[HOLD_EFFECT_DAMP_ROCK] = sText_HoldEffectDampRock,

View File

@ -104,6 +104,7 @@ static void RunTurnActionsFunctions(void);
static void SetActionsAndBattlersTurnOrder(void);
static void sub_803CDF8(void);
static bool8 AllAtActionConfirmed(void);
static void TryChangeTurnOrder(void);
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void);
static void CheckMegaEvolutionBeforeTurn(void);
static void CheckQuickClaw_CustapBerryActivation(void);
@ -3548,7 +3549,11 @@ static void TryDoEventsBeforeFirstTurn(void)
return;
}
}
// Check neutralizing gas
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0)
return;
// Check all switch in abilities happening from the fastest mon to slowest.
while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount)
{
@ -4669,10 +4674,37 @@ static void CheckMegaEvolutionBeforeTurn(void)
}
}
#if B_MEGA_EVO_TURN_ORDER <= GEN_6
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBattlerId = 0;
#else
gBattleMainFunc = TryChangeTurnOrder; // This will just do nothing if no mon has mega evolved
#endif
}
// In gen7, priority and speed are recalculated during the turn in which a pokemon mega evolves
static void TryChangeTurnOrder(void)
{
s32 i, j;
for (i = 0; i < gBattlersCount - 1; i++)
{
for (j = i + 1; j < gBattlersCount; j++)
{
u8 battler1 = gBattlerByTurnOrder[i];
u8 battler2 = gBattlerByTurnOrder[j];
if (gActionsByTurnOrder[i] == B_ACTION_USE_MOVE
&& gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)
{
if (GetWhoStrikesFirst(battler1, battler2, FALSE))
SwapTurnOrder(i, j);
}
}
}
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBattlerId = 0;
}
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
{
u32 i;

View File

@ -629,7 +629,7 @@ static const u8 sText_TerrainBecomesGrassy[] = _("Grass grew to cover\nthe battl
static const u8 sText_TerrainBecomesElectric[] = _("An electric current runs across\nthe battlefield!");
static const u8 sText_TerrainBecomesPsychic[] = _("The battlefield got weird!");
static const u8 sText_TargetElectrified[] = _("The {B_DEF_NAME_WITH_PREFIX}'s moves\nhave been electrified!");
static const u8 sText_AssaultVestDoesntAllow[] = _("The effects of the {B_LAST_ITEM} prevent status\nmoves from being used!\p");
static const u8 sText_AssaultVestDoesntAllow[] = _("{B_LAST_ITEM}'s effects prevent\nstatus moves from being used!\p");
static const u8 sText_GravityPreventsUsage[] = _("{B_ATK_NAME_WITH_PREFIX} can't use {B_CURRENT_MOVE}\nbecause of gravity!\p");
static const u8 sText_HealBlockPreventsUsage[] = _("{B_ATK_NAME_WITH_PREFIX} was\nprevented from healing!\p");
static const u8 sText_MegaEvoReacting[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_LAST_ITEM} is \nreacting to {B_ATK_TRAINER_NAME}'s Mega Ring!");
@ -733,9 +733,13 @@ static const u8 sText_CantEscapeDueToUsedMove[] = _("{B_ATK_NAME_WITH_PREFIX} ca
static const u8 sText_PkmnBecameWeakerToFire[] = _("{B_DEF_NAME_WITH_PREFIX} became\nweaker to fire!");
static const u8 sText_PkmnAboutToBeAttackedByItsItem[] = _("{B_DEF_NAME_WITH_PREFIX} is about\nto be attacked by its {B_BUFF1}!");
static const u8 sText_CantEscapeBecauseOfCurrentMove[] = _("{B_DEF_NAME_WITH_PREFIX} can no longer escape\nbecause of {B_CURRENT_MOVE}!");
static const u8 sText_NeutralizingGasEnters[] = _("Neutralizing Gas filled the area!");
static const u8 sText_NeutralizingGasOver[] = _("The effects of Neutralizing\nGas wore off!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{
[STRINGID_NEUTRALIZINGGASOVER - 12] = sText_NeutralizingGasOver,
[STRINGID_NEUTRALIZINGGASENTERS - 12] = sText_NeutralizingGasEnters,
[STRINGID_BATTLERTYPECHANGEDTO - 12] = sText_BattlerTypeChangedTo,
[STRINGID_PASTELVEILENTERS - 12] = sText_PastelVeilEnters,
[STRINGID_PASTELVEILPROTECTED -12] = sText_PastelVeilProtected,
@ -1392,6 +1396,7 @@ const u16 gSwitchInAbilityStringIds[] =
[B_MSG_SWITCHIN_ASONE] = STRINGID_ASONEENTERS,
[B_MSG_SWITCHIN_CURIOUS_MEDICINE] = STRINGID_CURIOUSMEDICINEENTERS,
[B_MSG_SWITCHIN_PASTEL_VEIL] = STRINGID_PASTELVEILENTERS,
[B_MSG_SWITCHIN_NEUTRALIZING_GAS] = STRINGID_NEUTRALIZINGGASENTERS,
};
const u16 gMissStringIds[] =

View File

@ -1313,47 +1313,6 @@ static const u8 sBattlePalaceNatureToFlavorTextId[NUM_NATURES] =
[NATURE_QUIRKY] = B_MSG_EAGER_FOR_MORE,
};
bool32 IsBattlerProtected(u8 battlerId, u16 move)
{
// Decorate bypasses protect and detect, but not crafty shield
if (move == MOVE_DECORATE)
{
if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD)
return TRUE;
else if (gProtectStructs[battlerId].protected)
return FALSE;
}
if (!(gBattleMoves[move].flags & FLAG_PROTECT_AFFECTED))
return FALSE;
else if (gBattleMoves[move].effect == MOVE_EFFECT_FEINT)
return FALSE;
else if (gProtectStructs[battlerId].protected)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD
&& gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))
return TRUE;
else if (gProtectStructs[battlerId].banefulBunkered)
return TRUE;
else if (gProtectStructs[battlerId].obstructed && !IS_MOVE_STATUS(move))
return TRUE;
else if (gProtectStructs[battlerId].spikyShielded)
return TRUE;
else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_QUICK_GUARD
&& GetChosenMovePriority(gBattlerAttacker) > 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD
&& IS_MOVE_STATUS(move))
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_MAT_BLOCK
&& !IS_MOVE_STATUS(move))
return TRUE;
else
return FALSE;
}
static bool32 NoTargetPresent(u32 move)
{
if (!IsBattlerAlive(gBattlerTarget))
@ -1902,11 +1861,13 @@ static void Cmd_ppreduce(void)
static const u8 sCriticalHitChance[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5
#endif // B_CRIT_CHANCE
#define BENEFITS_FROM_LEEK(battler, holdEffect)((holdEffect == HOLD_EFFECT_LEEK) && (GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_FARFETCHD || gBattleMons[battler].species == SPECIES_SIRFETCHD))
s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility)
{
s32 critChance = 0;
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT
|| gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
@ -1922,19 +1883,21 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)
|| move == MOVE_SURGING_STRIKES)
|| move == MOVE_SURGING_STRIKES
#if B_LEEK_ALWAYS_CRIT >= GEN_6
|| ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) && BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk))
#endif
)
{
critChance = -2;
}
else
{
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0)
+ ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) != 0)
+ (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
+ 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY)
+ 2 * (holdEffectAtk == HOLD_EFFECT_STICK && gBattleMons[gBattlerAttacker].species == SPECIES_FARFETCHD)
+ 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)
+ (abilityAtk == ABILITY_SUPER_LUCK);
if (critChance >= ARRAY_COUNT(sCriticalHitChance))
@ -1943,6 +1906,7 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi
return critChance;
}
#undef BENEFITS_FROM_LEEK
s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move)
{
@ -3071,7 +3035,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
if (NoAliveMonsForEitherParty()
|| ChangeStatBuffs(SET_STAT_BUFF_VALUE(1),
gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_1 + 1,
affectsUser, 0))
affectsUser | STAT_BUFF_UPDATE_MOVE_EFFECT, 0))
{
gBattlescriptCurrInstr++;
}
@ -3096,7 +3060,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE,
gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1,
flags, gBattlescriptCurrInstr + 1))
flags | STAT_BUFF_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1))
{
if (!mirrorArmorReflected)
gBattlescriptCurrInstr++;
@ -3119,7 +3083,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
if (NoAliveMonsForEitherParty()
|| ChangeStatBuffs(SET_STAT_BUFF_VALUE(2),
gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_2 + 1,
affectsUser, 0))
affectsUser | STAT_BUFF_UPDATE_MOVE_EFFECT, 0))
{
gBattlescriptCurrInstr++;
}
@ -3143,7 +3107,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
flags |= STAT_BUFF_ALLOW_PTR;
if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE,
gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1,
flags, gBattlescriptCurrInstr + 1))
flags | STAT_BUFF_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1))
{
if (!mirrorArmorReflected)
gBattlescriptCurrInstr++;
@ -3205,7 +3169,11 @@ void SetMoveEffect(bool32 primary, u32 certain)
RecordAbilityBattle(gBattlerTarget, gLastUsedAbility);
}
else if (gBattleMons[gBattlerAttacker].item != 0
#ifdef ITEM_EXPANSION
|| gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY_E_READER
#else
|| gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY
#endif
|| gBattleMons[gBattlerTarget].item == 0)
{
gBattlescriptCurrInstr++;
@ -5498,6 +5466,14 @@ static void Cmd_moveend(void)
*(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3;
if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget)
*(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3;
#if B_RAMPAGE_CANCELLING >= GEN_5
if (gBattleMoves[gCurrentMove].effect == EFFECT_RAMPAGE // If we're rampaging
&& (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) // And it is unusable
&& (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
#endif
gProtectStructs[gBattlerAttacker].usesBouncedMove = FALSE;
gProtectStructs[gBattlerAttacker].targetAffected = FALSE;
gBattleStruct->ateBoost[gBattlerAttacker] = 0;
@ -6200,8 +6176,17 @@ static void Cmd_switchineffects(void)
gHitMarker &= ~(HITMARKER_FAINTED(gActiveBattler));
gSpecialStatuses[gActiveBattler].flag40 = 0;
if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED)
// Neutralizing Gas announces itself before hazards
if (gBattleMons[gActiveBattler].ability == ABILITY_NEUTRALIZING_GAS && gSpecialStatuses[gActiveBattler].announceNeutralizingGas == 0)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
gSpecialStatuses[gActiveBattler].announceNeutralizingGas = TRUE;
gBattlerAbility = gActiveBattler;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_SwitchInAbilityMsgRet;
}
else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED)
&& (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES)
&& GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD
&& IsBattlerAffectedByHazards(gActiveBattler, FALSE)
@ -6275,7 +6260,7 @@ static void Cmd_switchineffects(void)
{
// There is a hack here to ensure the truant counter will be 0 when the battler's next turn starts.
// The truant counter is not updated in the case where a mon switches in after a lost judgement in the battle arena.
if (gBattleMons[gActiveBattler].ability == ABILITY_TRUANT
if (GetBattlerAbility(gActiveBattler) == ABILITY_TRUANT
&& gCurrentActionFuncId != B_ACTION_USE_MOVE
&& !gDisableStructs[gActiveBattler].truantSwitchInHack)
gDisableStructs[gActiveBattler].truantCounter = 1;
@ -7466,7 +7451,7 @@ u32 IsLeafGuardProtected(u32 battler)
bool32 IsShieldsDownProtected(u32 battler)
{
return (gBattleMons[battler].ability == ABILITY_SHIELDS_DOWN
return (GetBattlerAbility(battler) == ABILITY_SHIELDS_DOWN
&& GetFormIdFromFormSpeciesId(gBattleMons[battler].species) < GetFormIdFromFormSpeciesId(SPECIES_MINIOR_CORE_RED)); // Minior is not in core form
}
@ -7934,6 +7919,7 @@ static void Cmd_various(void)
break;
case VARIOUS_SWITCHIN_ABILITIES:
gBattlescriptCurrInstr += 3;
AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, gActiveBattler, 0, 0, 0);
AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0);
AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE2, gActiveBattler, 0, 0, 0);
AbilityBattleEffects(ABILITYEFFECT_TRACE2, gActiveBattler, 0, 0, 0);
@ -8114,6 +8100,9 @@ static void Cmd_various(void)
}
else
{
if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS)
gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE;
gBattleMons[gBattlerTarget].ability = ABILITY_SIMPLE;
gBattlescriptCurrInstr += 7;
}
@ -8990,11 +8979,11 @@ static void Cmd_various(void)
for (i = 0; i < gBattlersCount; i++)
{
if (((GetBattlerAbility(i) == ABILITY_DESOLATE_LAND && gBattleWeather & WEATHER_SUN_PRIMAL)
|| (GetBattlerAbility(i) == ABILITY_PRIMORDIAL_SEA && gBattleWeather & WEATHER_RAIN_PRIMAL)
|| (GetBattlerAbility(i) == ABILITY_DELTA_STREAM && gBattleWeather & WEATHER_STRONG_WINDS))
&& IsBattlerAlive(i)
&& !(gStatuses3[i] & STATUS3_GASTRO_ACID))
u32 ability = GetBattlerAbility(i);
if (((ability == ABILITY_DESOLATE_LAND && gBattleWeather & WEATHER_SUN_PRIMAL)
|| (ability == ABILITY_PRIMORDIAL_SEA && gBattleWeather & WEATHER_RAIN_PRIMAL)
|| (ability == ABILITY_DELTA_STREAM && gBattleWeather & WEATHER_STRONG_WINDS))
&& IsBattlerAlive(i))
shouldNotClear = TRUE;
}
if (gBattleWeather & WEATHER_SUN_PRIMAL && !shouldNotClear)
@ -9017,6 +9006,15 @@ static void Cmd_various(void)
}
break;
}
case VARIOUS_TRY_END_NEUTRALIZING_GAS:
if (gSpecialStatuses[gActiveBattler].neutralizingGasRemoved)
{
gSpecialStatuses[gActiveBattler].neutralizingGasRemoved = FALSE;
BattleScriptPush(gBattlescriptCurrInstr + 3);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
}
break;
case VARIOUS_GET_ROTOTILLER_TARGETS:
// Gets the battlers to be affected by rototiller. If there are none, print 'But it failed!'
{
@ -9815,6 +9813,72 @@ static void Cmd_setdrainedhp(void)
gBattlescriptCurrInstr++;
}
static u16 ReverseStatChangeMoveEffect(u16 moveEffect)
{
switch (moveEffect)
{
// +1
case MOVE_EFFECT_ATK_PLUS_1:
return MOVE_EFFECT_ATK_MINUS_1;
case MOVE_EFFECT_DEF_PLUS_1:
return MOVE_EFFECT_DEF_MINUS_1;
case MOVE_EFFECT_SPD_PLUS_1:
return MOVE_EFFECT_SPD_MINUS_1;
case MOVE_EFFECT_SP_ATK_PLUS_1:
return MOVE_EFFECT_SP_ATK_MINUS_1;
case MOVE_EFFECT_SP_DEF_PLUS_1:
return MOVE_EFFECT_SP_DEF_MINUS_1;
case MOVE_EFFECT_ACC_PLUS_1:
return MOVE_EFFECT_ACC_MINUS_1;
case MOVE_EFFECT_EVS_PLUS_1:
return MOVE_EFFECT_EVS_MINUS_1;
// -1
case MOVE_EFFECT_ATK_MINUS_1:
return MOVE_EFFECT_ATK_PLUS_1;
case MOVE_EFFECT_DEF_MINUS_1:
return MOVE_EFFECT_DEF_PLUS_1;
case MOVE_EFFECT_SPD_MINUS_1:
return MOVE_EFFECT_SPD_PLUS_1;
case MOVE_EFFECT_SP_ATK_MINUS_1:
return MOVE_EFFECT_SP_ATK_PLUS_1;
case MOVE_EFFECT_SP_DEF_MINUS_1:
return MOVE_EFFECT_SP_DEF_PLUS_1;
case MOVE_EFFECT_ACC_MINUS_1:
return MOVE_EFFECT_ACC_PLUS_1;
case MOVE_EFFECT_EVS_MINUS_1:
// +2
case MOVE_EFFECT_ATK_PLUS_2:
return MOVE_EFFECT_ATK_MINUS_2;
case MOVE_EFFECT_DEF_PLUS_2:
return MOVE_EFFECT_DEF_MINUS_2;
case MOVE_EFFECT_SPD_PLUS_2:
return MOVE_EFFECT_SPD_MINUS_2;
case MOVE_EFFECT_SP_ATK_PLUS_2:
return MOVE_EFFECT_SP_ATK_MINUS_2;
case MOVE_EFFECT_SP_DEF_PLUS_2:
return MOVE_EFFECT_SP_DEF_MINUS_2;
case MOVE_EFFECT_ACC_PLUS_2:
return MOVE_EFFECT_ACC_MINUS_2;
case MOVE_EFFECT_EVS_PLUS_2:
return MOVE_EFFECT_EVS_MINUS_2;
// -2
case MOVE_EFFECT_ATK_MINUS_2:
return MOVE_EFFECT_ATK_PLUS_2;
case MOVE_EFFECT_DEF_MINUS_2:
return MOVE_EFFECT_DEF_PLUS_2;
case MOVE_EFFECT_SPD_MINUS_2:
return MOVE_EFFECT_SPD_PLUS_2;
case MOVE_EFFECT_SP_ATK_MINUS_2:
return MOVE_EFFECT_SP_ATK_PLUS_2;
case MOVE_EFFECT_SP_DEF_MINUS_2:
return MOVE_EFFECT_SP_DEF_PLUS_2;
case MOVE_EFFECT_ACC_MINUS_2:
return MOVE_EFFECT_ACC_PLUS_2;
case MOVE_EFFECT_EVS_MINUS_2:
return MOVE_EFFECT_EVS_PLUS_2;
}
}
static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr)
{
bool32 certain = FALSE;
@ -9843,6 +9907,11 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
{
statValue ^= STAT_BUFF_NEGATIVE;
gBattleScripting.statChanger ^= STAT_BUFF_NEGATIVE;
if (flags & STAT_BUFF_UPDATE_MOVE_EFFECT)
{
flags &= ~(STAT_BUFF_UPDATE_MOVE_EFFECT);
gBattleScripting.moveEffect = ReverseStatChangeMoveEffect(gBattleScripting.moveEffect);
}
}
else if (GetBattlerAbility(gActiveBattler) == ABILITY_SIMPLE)
{
@ -9924,8 +9993,9 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
return STAT_CHANGE_DIDNT_WORK;
}
else if (!certain
&& ((GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE && statId == STAT_ACC)
|| (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER && statId == STAT_ATK)))
&& ((GetBattlerAbility(gActiveBattler) == ABILITY_KEEN_EYE && statId == STAT_ACC)
|| (GetBattlerAbility(gActiveBattler) == ABILITY_HYPER_CUTTER && statId == STAT_ATK)
|| (GetBattlerAbility(gActiveBattler) == ABILITY_BIG_PECKS && statId == STAT_DEF)))
{
if (flags == STAT_BUFF_ALLOW_PTR)
{
@ -11360,11 +11430,11 @@ static void Cmd_healpartystatus(void)
u16 ability;
if (gBattlerPartyIndexes[gBattlerAttacker] == i)
ability = gBattleMons[gBattlerAttacker].ability;
ability = GetBattlerAbility(gBattlerAttacker);
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattlerPartyIndexes[gActiveBattler] == i
&& !(gAbsentBattlerFlags & gBitTable[gActiveBattler]))
ability = gBattleMons[gActiveBattler].ability;
ability = GetBattlerAbility(gActiveBattler);
else
ability = GetAbilityBySpecies(species, abilityNum);
@ -12265,7 +12335,7 @@ static void Cmd_trywish(void)
if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0)
{
gWishFutureKnock.wishCounter[gBattlerAttacker] = 2;
gWishFutureKnock.wishMonId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
gBattlescriptCurrInstr += 6;
}
else
@ -12274,13 +12344,17 @@ static void Cmd_trywish(void)
}
break;
case 1: // heal effect
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishMonId[gBattlerTarget])
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishPartyId[gBattlerTarget])
#if B_WISH_HP_SOURCE >= GEN_5
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
gBattleMoveDamage = max(1, GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2);
else
gBattleMoveDamage = max(1, GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2);
#else
gBattleMoveDamage = max(1, gBattleMons[gBattlerTarget].maxHP / 2);
#endif
gBattleMoveDamage *= -1;
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
else
@ -12313,6 +12387,9 @@ static void Cmd_setgastroacid(void)
}
else
{
if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS)
gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE;
gStatuses3[gBattlerTarget] |= STATUS3_GASTRO_ACID;
gBattlescriptCurrInstr += 5;
}
@ -12593,25 +12670,33 @@ static void Cmd_trygetintimidatetarget(void)
static void Cmd_switchoutabilities(void)
{
gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
switch (GetBattlerAbility(gActiveBattler))
if (gBattleMons[gActiveBattler].ability == ABILITY_NEUTRALIZING_GAS)
{
case ABILITY_NATURAL_CURE:
gBattleMons[gActiveBattler].status1 = 0;
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
break;
case ABILITY_REGENERATOR:
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3;
gBattleMoveDamage += gBattleMons[gActiveBattler].hp;
if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP)
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP;
BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 2, &gBattleMoveDamage);
MarkBattlerForControllerExec(gActiveBattler);
break;
gBattleMons[gActiveBattler].ability = ABILITY_NONE;
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
}
else
{
switch (GetBattlerAbility(gActiveBattler))
{
case ABILITY_NATURAL_CURE:
gBattleMons[gActiveBattler].status1 = 0;
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
break;
case ABILITY_REGENERATOR:
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 3;
gBattleMoveDamage += gBattleMons[gActiveBattler].hp;
if (gBattleMoveDamage > gBattleMons[gActiveBattler].maxHP)
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP;
BtlController_EmitSetMonData(0, REQUEST_HP_BATTLE, gBitTable[*(gBattleStruct->field_58 + gActiveBattler)], 2, &gBattleMoveDamage);
MarkBattlerForControllerExec(gActiveBattler);
break;
}
gBattlescriptCurrInstr += 2;
}
gBattlescriptCurrInstr += 2;
}
static void Cmd_jumpifhasnohp(void)
@ -13031,14 +13116,32 @@ static void Cmd_snatchsetbattlers(void)
static void Cmd_removelightscreenreflect(void) // brick break
{
u8 opposingSide = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (gSideTimers[opposingSide].reflectTimer || gSideTimers[opposingSide].lightscreenTimer)
u8 side;
bool32 failed;
#if B_BRICK_BREAK >= GEN_4
side = GetBattlerSide(gBattlerAttacker);
#else
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
#endif
#if B_BRICK_BREAK >= GEN_5
failed = (gMoveResultFlags & MOVE_RESULT_NO_EFFECT);
#else
failed = FALSE;
#endif
if (!failed
&& (gSideTimers[side].reflectTimer
|| gSideTimers[side].lightscreenTimer
|| gSideTimers[side].auroraVeilTimer))
{
gSideStatuses[opposingSide] &= ~(SIDE_STATUS_REFLECT);
gSideStatuses[opposingSide] &= ~(SIDE_STATUS_LIGHTSCREEN);
gSideTimers[opposingSide].reflectTimer = 0;
gSideTimers[opposingSide].lightscreenTimer = 0;
gSideStatuses[side] &= ~(SIDE_STATUS_REFLECT);
gSideStatuses[side] &= ~(SIDE_STATUS_LIGHTSCREEN);
gSideStatuses[side] &= ~(SIDE_STATUS_AURORA_VEIL);
gSideTimers[side].reflectTimer = 0;
gSideTimers[side].lightscreenTimer = 0;
gSideTimers[side].auroraVeilTimer = 0;
gBattleScripting.animTurn = 1;
gBattleScripting.animTargetsHit = 1;
}
@ -13088,7 +13191,7 @@ static void Cmd_handleballthrow(void)
u8 catchRate;
gLastThrownBall = gLastUsedItem;
if (gLastUsedItem == ITEM_SAFARI_BALL)
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
catchRate = gBattleStruct->safariCatchFactor * 1275 / 100;
else
catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate;

View File

@ -317,8 +317,8 @@ void HandleAction_UseMove(void)
else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
&& gSideTimers[side].followmeTimer == 0
&& (gBattleMoves[gCurrentMove].power != 0 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER)
&& ((gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|| (gBattleMons[*(gBattleStruct->moveTarget + gBattlerAttacker)].ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER)))
&& ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|| (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER)))
{
side = GetBattlerSide(gBattlerAttacker);
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
@ -387,9 +387,9 @@ void HandleAction_UseMove(void)
{
gActiveBattler = gBattlerByTurnOrder[var];
RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability);
if (gBattleMons[gActiveBattler].ability == ABILITY_LIGHTNING_ROD)
if (GetBattlerAbility(gActiveBattler) == ABILITY_LIGHTNING_ROD)
gSpecialStatuses[gActiveBattler].lightningRodRedirected = TRUE;
else if (gBattleMons[gActiveBattler].ability == ABILITY_STORM_DRAIN)
else if (GetBattlerAbility(gActiveBattler) == ABILITY_STORM_DRAIN)
gSpecialStatuses[gActiveBattler].stormDrainRedirected = TRUE;
gBattlerTarget = gActiveBattler;
}
@ -627,7 +627,7 @@ bool8 TryRunFromBattle(u8 battler)
effect++;
}
#endif
else if (gBattleMons[battler].ability == ABILITY_RUN_AWAY)
else if (GetBattlerAbility(battler) == ABILITY_RUN_AWAY)
{
if (InBattlePyramid())
{
@ -1762,7 +1762,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
limitations++;
}
}
else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[move].power == 0)
else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[move].power == 0 && move != MOVE_ME_FIRST)
{
gCurrentMove = move;
gLastUsedItem = gBattleMons[gActiveBattler].item;
@ -1834,7 +1834,7 @@ u8 CheckMoveLimitations(u8 battlerId, u8 unusableMoves, u8 check)
unusableMoves |= gBitTable[i];
else if (HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != gBattleMons[battlerId].moves[i])
unusableMoves |= gBitTable[i];
else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0)
else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0 && gBattleMons[battlerId].moves[i] != MOVE_ME_FIRST)
unusableMoves |= gBitTable[i];
else if (IsGravityPreventingMove(gBattleMons[battlerId].moves[i]))
unusableMoves |= gBitTable[i];
@ -2727,7 +2727,7 @@ u8 DoBattlerEndTurnEffects(void)
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++)
{
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
&& gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF)
{
gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP);
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
@ -2795,6 +2795,7 @@ u8 DoBattlerEndTurnEffects(void)
case ENDTURN_FLINCH: // reset flinch
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_FLINCHED);
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_DISABLE: // disable
if (gDisableStructs[gActiveBattler].disableTimer != 0)
{
@ -3311,7 +3312,7 @@ u8 AtkCanceller_UnableToUseMove(void)
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_TRUANT: // truant
if (gBattleMons[gBattlerAttacker].ability == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
{
CancelMultiTurnMoves(gBattlerAttacker);
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
@ -3752,7 +3753,7 @@ u8 TryWeatherFormChange(u8 battler)
if (gBattleMons[battler].species == SPECIES_CASTFORM)
{
if (gBattleMons[battler].ability != ABILITY_FORECAST || gBattleMons[battler].hp == 0)
if (GetBattlerAbility(battler) != ABILITY_FORECAST || gBattleMons[battler].hp == 0)
{
ret = 0;
}
@ -3788,11 +3789,11 @@ u8 TryWeatherFormChange(u8 battler)
}
else if (gBattleMons[battler].species == SPECIES_CHERRIM)
{
if (gBattleMons[battler].ability != ABILITY_FLOWER_GIFT || gBattleMons[battler].hp == 0)
if (GetBattlerAbility(battler) != ABILITY_FLOWER_GIFT || gBattleMons[battler].hp == 0)
ret = 0;
else if (gBattleMonForms[battler] == 0 && weatherEffect && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA && gBattleWeather & WEATHER_SUN_ANY)
ret = 2;
else if (gBattleMonForms[battler] != 0 && (!weatherEffect || holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA || !(gBattleWeather & WEATHER_SUN_ANY)))
else if (gBattleMonForms[battler] != 0 && (!weatherEffect || holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA || !(gBattleWeather & WEATHER_SUN_ANY)))
ret = 1;
}
@ -3878,7 +3879,7 @@ static bool32 ShouldChangeFormHpBased(u32 battler)
for (i = 0; i < ARRAY_COUNT(forms); i++)
{
if (gBattleMons[battler].ability == forms[i][0])
if (GetBattlerAbility(battler) == forms[i][0])
{
if (gBattleMons[battler].species == forms[i][2]
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / forms[i][3])
@ -5373,7 +5374,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
case ABILITYEFFECT_IMMUNITY: // 5
for (battler = 0; battler < gBattlersCount; battler++)
{
switch (gBattleMons[battler].ability)
switch (GetBattlerAbility(battler))
{
case ABILITY_IMMUNITY:
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER))
@ -5463,7 +5464,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
case ABILITYEFFECT_FORECAST: // 6
for (battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleMons[battler].ability == ABILITY_FORECAST || gBattleMons[battler].ability == ABILITY_FLOWER_GIFT)
if (GetBattlerAbility(battler) == ABILITY_FORECAST || GetBattlerAbility(battler) == ABILITY_FLOWER_GIFT)
{
effect = TryWeatherFormChange(battler);
if (effect)
@ -5524,7 +5525,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
case ABILITYEFFECT_INTIMIDATE2:
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gBattleResources->flags->flags[i] & RESOURCE_FLAG_INTIMIDATED)
if (GetBattlerAbility(i) == ABILITY_INTIMIDATE && gBattleResources->flags->flags[i] & RESOURCE_FLAG_INTIMIDATED)
{
gLastUsedAbility = ABILITY_INTIMIDATE;
gBattleResources->flags->flags[i] &= ~(RESOURCE_FLAG_INTIMIDATED);
@ -5591,6 +5592,23 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
}
}
break;
case ABILITYEFFECT_NEUTRALIZINGGAS:
// Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gBattleResources->flags->flags[i] & RESOURCE_FLAG_NEUTRALIZING_GAS))
{
gBattleResources->flags->flags[i] |= RESOURCE_FLAG_NEUTRALIZING_GAS;
gBattlerAbility = i;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
if (effect)
break;
}
break;
}
if (effect && gLastUsedAbility != 0xFF)
@ -5601,11 +5619,51 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
return effect;
}
bool32 IsNeutralizingGasBannedAbility(u32 ability)
{
switch (ability)
{
case ABILITY_MULTITYPE:
case ABILITY_ZEN_MODE:
case ABILITY_STANCE_CHANGE:
case ABILITY_POWER_CONSTRUCT:
case ABILITY_SCHOOLING:
case ABILITY_RKS_SYSTEM:
case ABILITY_SHIELDS_DOWN:
case ABILITY_COMATOSE:
case ABILITY_DISGUISE:
case ABILITY_GULP_MISSILE:
case ABILITY_ICE_FACE:
case ABILITY_AS_ONE_ICE_RIDER:
case ABILITY_AS_ONE_SHADOW_RIDER:
return TRUE;
default:
return FALSE;
}
}
bool32 IsNeutralizingGasOnField(void)
{
u32 i;
for (i = 0; i < gBattlersCount; i++)
{
if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gStatuses3[i] & STATUS3_GASTRO_ACID))
return TRUE;
}
return FALSE;
}
u32 GetBattlerAbility(u8 battlerId)
{
if (gStatuses3[battlerId] & STATUS3_GASTRO_ACID)
return ABILITY_NONE;
else if ((((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER
if (IsNeutralizingGasOnField() && !IsNeutralizingGasBannedAbility(gBattleMons[battlerId].ability))
return ABILITY_NONE;
if ((((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER
|| gBattleMons[gBattlerAttacker].ability == ABILITY_TERAVOLT
|| gBattleMons[gBattlerAttacker].ability == ABILITY_TURBOBLAZE)
&& !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID))
@ -5615,8 +5673,8 @@ u32 GetBattlerAbility(u8 battlerId)
&& gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE
&& gCurrentTurnActionNumber < gBattlersCount)
return ABILITY_NONE;
else
return gBattleMons[battlerId].ability;
return gBattleMons[battlerId].ability;
}
u32 IsAbilityOnSide(u32 battlerId, u32 ability)
@ -5668,7 +5726,7 @@ u32 IsAbilityPreventingEscape(u32 battlerId)
return 0;
#endif
#if B_SHADOW_TAG_ESCAPE >= GEN_4
if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && gBattleMons[battlerId].ability != ABILITY_SHADOW_TAG)
if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && GetBattlerAbility(battlerId) != ABILITY_SHADOW_TAG)
#else
if (id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG))
#endif
@ -6860,6 +6918,10 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
switch (atkHoldEffect)
{
case HOLD_EFFECT_FLINCH:
#if B_SERENE_GRACE_BOOST >= GEN_5
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_SERENE_GRACE)
atkHoldEffectParam *= 2;
#endif
if (gBattleMoveDamage != 0 // Need to have done damage
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED
@ -7215,7 +7277,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget)
targetBattler = SetRandomTarget(gBattlerAttacker);
if (gBattleMoves[move].type == TYPE_ELECTRIC
&& IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD)
&& gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD)
&& GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD)
{
targetBattler ^= BIT_FLANK;
RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability);
@ -7223,7 +7285,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget)
}
else if (gBattleMoves[move].type == TYPE_WATER
&& IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN)
&& gBattleMons[targetBattler].ability != ABILITY_STORM_DRAIN)
&& GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN)
{
targetBattler ^= BIT_FLANK;
RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability);
@ -7401,7 +7463,7 @@ u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating)
return HOLD_EFFECT_NONE;
if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)
return HOLD_EFFECT_NONE;
if (gBattleMons[battlerId].ability == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID))
if (GetBattlerAbility(battlerId) == ABILITY_KLUTZ)
return HOLD_EFFECT_NONE;
}
@ -7446,6 +7508,53 @@ bool32 IsMoveMakingContact(u16 move, u8 battlerAtk)
}
}
bool32 IsBattlerProtected(u8 battlerId, u16 move)
{
// Decorate bypasses protect and detect, but not crafty shield
if (move == MOVE_DECORATE)
{
if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD)
return TRUE;
else if (gProtectStructs[battlerId].protected)
return FALSE;
}
// Protective Pads doesn't stop Unseen Fist from bypassing Protect effects, so IsMoveMakingContact() isn't used here.
// This means extra logic is needed to handle Shell Side Arm.
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNSEEN_FIST
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT || (gBattleMoves[move].effect == EFFECT_SHELL_SIDE_ARM && gSwapDamageCategory)))
return FALSE;
else if (!(gBattleMoves[move].flags & FLAG_PROTECT_AFFECTED))
return FALSE;
else if (gBattleMoves[move].effect == MOVE_EFFECT_FEINT)
return FALSE;
else if (gProtectStructs[battlerId].protected)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD
&& gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))
return TRUE;
else if (gProtectStructs[battlerId].banefulBunkered)
return TRUE;
else if (gProtectStructs[battlerId].obstructed && !IS_MOVE_STATUS(move))
return TRUE;
else if (gProtectStructs[battlerId].spikyShielded)
return TRUE;
else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_QUICK_GUARD
&& GetChosenMovePriority(gBattlerAttacker) > 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD
&& IS_MOVE_STATUS(move))
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_MAT_BLOCK
&& !IS_MOVE_STATUS(move))
return TRUE;
else
return FALSE;
}
bool32 IsBattlerGrounded(u8 battlerId)
{
if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_IRON_BALL)
@ -8028,7 +8137,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
if (IsAbilityOnField(ABILITY_AURA_BREAK))
MulModifier(&modifier, UQ_4_12(0.75));
else
MulModifier(&modifier, UQ_4_12(1.25));
MulModifier(&modifier, UQ_4_12(1.33));
}
// attacker partner's abilities
@ -8189,8 +8298,11 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
MulModifier(&modifier, UQ_4_12(0.5));
break;
case EFFECT_KNOCK_OFF:
if (gBattleMons[battlerDef].item != ITEM_NONE && GetBattlerAbility(battlerDef) != ABILITY_STICKY_HOLD)
#if B_KNOCK_OFF_DMG >= GEN_6
if (gBattleMons[battlerDef].item != ITEM_NONE
&& CanBattlerGetOrLoseItem(battlerDef, gBattleMons[battlerDef].item))
MulModifier(&modifier, UQ_4_12(1.5));
#endif
break;
}
@ -8605,7 +8717,9 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
if (((gSideStatuses[defSide] & SIDE_STATUS_REFLECT && IS_MOVE_PHYSICAL(move))
|| (gSideStatuses[defSide] & SIDE_STATUS_LIGHTSCREEN && IS_MOVE_SPECIAL(move))
|| (gSideStatuses[defSide] & SIDE_STATUS_AURORA_VEIL))
&& abilityAtk != ABILITY_INFILTRATOR)
&& abilityAtk != ABILITY_INFILTRATOR
&& !(isCrit)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg)
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
MulModifier(&finalModifier, UQ_4_12(0.66));
@ -8777,9 +8891,6 @@ static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 batt
if (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot)
mod = UQ_4_12(2.0);
if (gProtectStructs[battlerDef].kingsShielded && gBattleMoves[move].effect != EFFECT_FEINT)
mod = UQ_4_12(1.0);
// WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_STRONG_WINDS)
{
@ -9003,9 +9114,9 @@ bool32 CanMegaEvolve(u8 battlerId)
struct MegaEvolutionData *mega = &(((struct ChooseMoveStruct*)(&gBattleResources->bufferA[gActiveBattler][4]))->mega);
#ifdef ITEM_EXPANSION
// Check if Player has a Mega Bracelet
// Check if Player has a Mega Ring
if ((GetBattlerPosition(battlerId) == B_POSITION_PLAYER_LEFT || (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && GetBattlerPosition(battlerId) == B_POSITION_PLAYER_RIGHT))
&& !CheckBagHasItem(ITEM_MEGA_BRACELET, 1))
&& !CheckBagHasItem(ITEM_MEGA_RING, 1))
return FALSE;
#endif

View File

@ -142,7 +142,7 @@ u32 sub_805725C(u8 battlerId)
{
u32 toSub;
if (gBattleMons[battlerId].ability == ABILITY_EARLY_BIRD)
if (GetBattlerAbility(battlerId) == ABILITY_EARLY_BIRD)
toSub = 2;
else
toSub = 1;

View File

@ -2680,7 +2680,7 @@ const struct Item gItems[] =
.name = _("UP-GRADE"),
.itemId = ITEM_UP_GRADE,
.price = 2100,
.holdEffect = HOLD_EFFECT_UP_GRADE,
.holdEffect = HOLD_EFFECT_UPGRADE,
.description = sUpGradeDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -2767,7 +2767,7 @@ const struct Item gItems[] =
.name = _("STICK"),
.itemId = ITEM_STICK,
.price = 200,
.holdEffect = HOLD_EFFECT_STICK,
.holdEffect = HOLD_EFFECT_LEEK,
.description = sStickDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,

View File

@ -1395,7 +1395,6 @@ const u32 gBattleAnimBgPalette_Solarbeam[] = INCBIN_U32("graphics/battle_anims/b
const u32 gBattleAnimBgPalette_MagmaStorm[] = INCBIN_U32("graphics/battle_anims/backgrounds/magma_storm.gbapal.lz");
//new battle bgs
const u32 gBattleAnimBgPalette_GigaImpact[] = INCBIN_U32("graphics/battle_anims/backgrounds/giga_impact.gbapal.lz");
const u32 gBattleAnimBgImage_Hurricane[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/hurricane.4bpp.lz");
const u32 gBattleAnimBgPalette_Hurricane[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/hurricane.gbapal.lz");
@ -1403,10 +1402,14 @@ const u32 gBattleAnimBgTilemap_Hurricane[] = INCBIN_U32("graphics/battle_anims/b
const u32 gBattleAnimBgPalette_RockWrecker[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/rock_wrecker.gbapal.lz");
const u32 gBattleAnimBgTilemap_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.bin.lz");
const u32 gBattleAnimBgTilemap_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin.lz");
const u32 gBattleAnimBgTilemap_GigaImpactContest[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_contest.bin.lz");
const u32 gBattleAnimBgImage_GigaImpact[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact.4bpp.lz");
const u32 gBattleAnimBgPalette_GigaImpact[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact.gbapal.lz");
const u32 gBattleAnimBgImage_SpacialRend[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend.4bpp.lz");
const u32 gBattleAnimBgPalette_SpacialRend[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend.gbapal.lz");
const u32 gBattleAnimBgTilemap_SpacialRendOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend_opponent.bin.lz");
const u32 gBattleAnimBgTilemap_SpacialRendPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/spacial_rend_player.bin.lz");
const u32 gBattleAnimBgPalette_SludgeWave[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/sludge_wave.gbapal.lz");
@ -1450,14 +1453,6 @@ const u32 gBattleAnimBgTilemap_FocusBlast[] = INCBIN_U32("graphics/battle_anims/
const u32 gBattleAnimBgPalette_GarbageFalls[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/garbage_falls.gbapal.lz");
const u32 gBattleAnimBgImage_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.4bpp.lz");
const u32 gBattleAnimBgPalette_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.gbapal.lz");
const u32 gBattleAnimBgTilemap_GigaImpactOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_opponent.bin.lz");
const u32 gBattleAnimBgImage_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.4bpp.lz");
const u32 gBattleAnimBgPalette_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.gbapal.lz");
const u32 gBattleAnimBgTilemap_GigaImpactPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/giga_impact_player.bin.lz");
const u32 gBattleAnimBgImage_GrassyTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/grassy_terrain.4bpp.lz");
const u32 gBattleAnimBgPalette_GrassyTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/grassy_terrain.gbapal.lz");
const u32 gBattleAnimBgTilemap_GrassyTerrain[] = INCBIN_U32("graphics/battle_anims/backgrounds/new/grassy_terrain.bin.lz");