merge with be

This commit is contained in:
ghoulslash 2021-09-16 21:41:29 -04:00
commit e756b0accc
12 changed files with 729 additions and 179 deletions

View File

@ -1777,6 +1777,20 @@
various 0, VARIOUS_PICKPOCKET various 0, VARIOUS_PICKPOCKET
.endm .endm
.macro doterrainseed battler:req, ptr:req
various \battler, VARIOUS_TERRAIN_SEED
.4byte \ptr
.endm
.macro makeinvisible battler:req
various \battler, VARIOUS_MAKE_INVISIBLE
.endm
.macro tryroomservice battler:req, ptr:req
various \battler, VARIOUS_ROOM_SERVICE
.4byte \ptr
.endm
@ helpful macros @ helpful macros
.macro setstatchanger stat:req, stages:req, down:req .macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7

View File

@ -1530,6 +1530,7 @@ BattleScript_EffectPsychicTerrain:
printfromtable gTerrainStringIds printfromtable gTerrainStringIds
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL
call BattleScript_TerrainSeedLoop
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectTopsyTurvy: BattleScript_EffectTopsyTurvy:
@ -1852,6 +1853,26 @@ BattleScript_EffectMagnetRise:
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectTrickRoom: BattleScript_EffectTrickRoom:
attackcanceler
attackstring
ppreduce
setroom
attackanimation
waitanimation
printfromtable gRoomsStringIds
waitmessage B_WAIT_TIME_LONG
savetarget
setbyte gBattlerTarget, 0
BattleScript_RoomServiceLoop:
copybyte sBATTLER, gBattlerTarget
tryroomservice BS_TARGET, BattleScript_RoomServiceLoop_NextBattler
removeitem BS_TARGET
BattleScript_RoomServiceLoop_NextBattler:
addbyte gBattlerTarget, 0x1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_RoomServiceLoop
restoretarget
goto BattleScript_MoveEnd
BattleScript_EffectWonderRoom: BattleScript_EffectWonderRoom:
BattleScript_EffectMagicRoom: BattleScript_EffectMagicRoom:
attackcanceler attackcanceler
@ -2163,18 +2184,21 @@ BattleScript_AlreadyAsleep::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
printstring STRINGID_PKMNALREADYASLEEP printstring STRINGID_PKMNALREADYASLEEP
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
orhalfword gMoveResultFlags, MOVE_RESULT_FAILED
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_WasntAffected:: BattleScript_WasntAffected::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
printstring STRINGID_PKMNWASNTAFFECTED printstring STRINGID_PKMNWASNTAFFECTED
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
orhalfword gMoveResultFlags, MOVE_RESULT_FAILED
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_CantMakeAsleep:: BattleScript_CantMakeAsleep::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
printfromtable gUproarAwakeStringIds printfromtable gUproarAwakeStringIds
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
orhalfword gMoveResultFlags, MOVE_RESULT_FAILED
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_EffectPoisonHit: BattleScript_EffectPoisonHit:
@ -5547,16 +5571,28 @@ BattleScript_RoarSuccessSwitch::
waitstate waitstate
printstring STRINGID_PKMNWASDRAGGEDOUT printstring STRINGID_PKMNWASDRAGGEDOUT
switchineffects BS_TARGET switchineffects BS_TARGET
jumpifbyte CMP_EQUAL, sSWITCH_CASE, B_SWITCH_RED_CARD, BattleScript_RoarSuccessSwitch_Ret
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_RoarSuccessSwitch_Ret:
swapattackerwithtarget @ continuation of RedCardActivates
restoretarget
removeitem BS_TARGET
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
return
BattleScript_RoarSuccessEndBattle:: BattleScript_RoarSuccessEndBattle::
call BattleScript_RoarSuccessRet call BattleScript_RoarSuccessRet
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
setoutcomeonteleport BS_ATTACKER setoutcomeonteleport BS_ATTACKER
finishaction finishaction
BattleScript_RoarSuccessRet: BattleScript_RoarSuccessRet:
jumpifbyte CMP_EQUAL, sSWITCH_CASE, B_SWITCH_HIT, BattleScript_RoarSuccessRet_Ret
jumpifbyte CMP_EQUAL, sSWITCH_CASE, B_SWITCH_RED_CARD, BattleScript_RoarSuccessRet_Ret
attackanimation attackanimation
waitanimation waitanimation
BattleScript_RoarSuccessRet_Ret:
switchoutabilities BS_TARGET switchoutabilities BS_TARGET
returntoball BS_TARGET returntoball BS_TARGET
waitstate waitstate
@ -5602,6 +5638,21 @@ BattleScript_TargetItemStatRaise::
BattleScript_TargetItemStatRaiseRemoveItemRet: BattleScript_TargetItemStatRaiseRemoveItemRet:
return return
BattleScript_AttackerItemStatRaise::
copybyte sBATTLER, gBattlerAttacker
statbuffchange MOVE_EFFECT_AFFECTS_USER, BattleScript_AttackerItemStatRaiseRet
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_AttackerItemStatRaiseRet
playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL
waitanimation
setgraphicalstatchangevalues
playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
waitanimation
printstring STRINGID_USINGITEMSTATOFPKMNROSE
waitmessage 0x40
removeitem BS_ATTACKER
BattleScript_AttackerItemStatRaiseRet:
return
BattleScript_MistProtected:: BattleScript_MistProtected::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
printstring STRINGID_PKMNPROTECTEDBYMIST printstring STRINGID_PKMNPROTECTEDBYMIST
@ -6885,12 +6936,26 @@ BattleScript_SnowWarningActivates::
call BattleScript_WeatherFormChanges call BattleScript_WeatherFormChanges
end3 end3
BattleScript_TerrainSeedLoop:
savetarget
setbyte gBattlerTarget, 0
BattleScript_TerrainSeedLoopIter:
copybyte sBATTLER, gBattlerTarget
doterrainseed BS_TARGET, BattleScript_TerrainSeedLoop_NextBattler
removeitem BS_TARGET
BattleScript_TerrainSeedLoop_NextBattler:
addbyte gBattlerTarget, 0x1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_TerrainSeedLoopIter
restoretarget
return
BattleScript_ElectricSurgeActivates:: BattleScript_ElectricSurgeActivates::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
printstring STRINGID_TERRAINBECOMESELECTRIC printstring STRINGID_TERRAINBECOMESELECTRIC
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL
call BattleScript_TerrainSeedLoop
end3 end3
BattleScript_MistySurgeActivates:: BattleScript_MistySurgeActivates::
@ -6899,6 +6964,7 @@ BattleScript_MistySurgeActivates::
printstring STRINGID_TERRAINBECOMESMISTY printstring STRINGID_TERRAINBECOMESMISTY
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL
call BattleScript_TerrainSeedLoop
end3 end3
BattleScript_GrassySurgeActivates:: BattleScript_GrassySurgeActivates::
@ -6907,6 +6973,7 @@ BattleScript_GrassySurgeActivates::
printstring STRINGID_TERRAINBECOMESGRASSY printstring STRINGID_TERRAINBECOMESGRASSY
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL
call BattleScript_TerrainSeedLoop
end3 end3
BattleScript_PsychicSurgeActivates:: BattleScript_PsychicSurgeActivates::
@ -6915,6 +6982,7 @@ BattleScript_PsychicSurgeActivates::
printstring STRINGID_TERRAINBECOMESPSYCHIC printstring STRINGID_TERRAINBECOMESPSYCHIC
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG, NULL
call BattleScript_TerrainSeedLoop
end3 end3
BattleScript_BadDreamsActivates:: BattleScript_BadDreamsActivates::
@ -7066,6 +7134,7 @@ BattleScript_SoundproofProtected::
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
printstring STRINGID_PKMNSXBLOCKSY printstring STRINGID_PKMNSXBLOCKSY
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
orhalfword gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_DazzlingProtected:: BattleScript_DazzlingProtected::
@ -7109,6 +7178,7 @@ BattleScript_AbilityNoSpecificStatLoss::
printstring STRINGID_PKMNSXPREVENTSYLOSS printstring STRINGID_PKMNSXPREVENTSYLOSS
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY
orhalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
return return
BattleScript_StickyHoldActivates:: BattleScript_StickyHoldActivates::
@ -7710,12 +7780,13 @@ BattleScript_BerryStatRaiseEnd2::
BattleScript_BerryStatRaiseEnd2_AbilityPopup: BattleScript_BerryStatRaiseEnd2_AbilityPopup:
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
BattleScript_BerryStatRaiseEnd2_Anim: BattleScript_BerryStatRaiseEnd2_Anim:
playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_BerryStatRaiseEnd2_End
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR, BattleScript_BerryStatRaiseDoStatUp setgraphicalstatchangevalues
BattleScript_BerryStatRaiseDoStatUp:: playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1
setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM
call BattleScript_StatUp call BattleScript_StatUp
removeitem BS_ATTACKER removeitem BS_ATTACKER
BattleScript_BerryStatRaiseEnd2_End::
end2 end2
BattleScript_BerryStatRaiseRet:: BattleScript_BerryStatRaiseRet::
@ -7724,12 +7795,13 @@ BattleScript_BerryStatRaiseRet::
BattleScript_BerryStatRaiseRet_AbilityPopup: BattleScript_BerryStatRaiseRet_AbilityPopup:
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
BattleScript_BerryStatRaiseRet_Anim: BattleScript_BerryStatRaiseRet_Anim:
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL
statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_BerryStatRaiseRet_End statbuffchange STAT_BUFF_ALLOW_PTR, BattleScript_BerryStatRaiseRet_End
BattleScript_BerryStatRaiseRet_End: setgraphicalstatchangevalues
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1
setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM
call BattleScript_StatUp call BattleScript_StatUp
removeitem BS_SCRIPTING removeitem BS_SCRIPTING
BattleScript_BerryStatRaiseRet_End:
return return
BattleScript_BerryFocusEnergyEnd2:: BattleScript_BerryFocusEnergyEnd2::
@ -7983,3 +8055,61 @@ BattleScript_StickyBarbTransfer::
removeitem BS_TARGET removeitem BS_TARGET
return return
BattleScript_RedCardActivates::
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL
printstring STRINGID_REDCARDACTIVATE
waitmessage 0x40
swapattackerwithtarget
jumpifstatus3 BS_EFFECT_BATTLER, STATUS3_ROOTED, BattleScript_RedCardIngrain
jumpifability BS_EFFECT_BATTLER, ABILITY_SUCTION_CUPS, BattleScript_RedCardSuctionCups
setbyte sSWITCH_CASE, B_SWITCH_RED_CARD
forcerandomswitch BattleScript_RedCardEnd
@ changes the current battle script. the rest happens in BattleScript_RoarSuccessSwitch_Ret, if switch is successful
BattleScript_RedCardEnd:
return
BattleScript_RedCardIngrain:
printstring STRINGID_PKMNANCHOREDITSELF
waitmessage 0x40
removeitem BS_SCRIPTING
swapattackerwithtarget
return
BattleScript_RedCardSuctionCups:
printstring STRINGID_PKMNANCHORSITSELFWITH
waitmessage 0x40
removeitem BS_SCRIPTING
swapattackerwithtarget
return
BattleScript_EjectButtonActivates::
makevisible BS_ATTACKER
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL
printstring STRINGID_EJECTBUTTONACTIVATE
waitmessage 0x40
removeitem BS_SCRIPTING
makeinvisible BS_SCRIPTING
openpartyscreen BS_SCRIPTING, BattleScript_EjectButtonEnd
switchoutabilities BS_SCRIPTING
waitstate
switchhandleorder BS_SCRIPTING 0x2
returntoball BS_SCRIPTING
getswitchedmondata BS_SCRIPTING
switchindataupdate BS_SCRIPTING
hpthresholds BS_SCRIPTING
printstring 0x3
switchinanim BS_SCRIPTING 0x1
waitstate
switchineffects BS_SCRIPTING
BattleScript_EjectButtonEnd:
return
BattleScript_EjectPackActivate_Ret::
goto BattleScript_EjectButtonActivates
BattleScript_EjectPackActivate_End2::
call BattleScript_EjectPackActivate_Ret
end2
BattleScript_EjectPackActivates::
jumpifcantswitch BS_SCRIPTING, BattleScript_EjectButtonEnd
goto BattleScript_EjectPackActivate_Ret

View File

@ -126,7 +126,7 @@ struct ProtectStruct
u32 stealMove:1; u32 stealMove:1;
u32 prlzImmobility:1; u32 prlzImmobility:1;
u32 confusionSelfDmg:1; u32 confusionSelfDmg:1;
u32 targetNotAffected:1; u32 targetAffected:1;
u32 chargingTurn:1; u32 chargingTurn:1;
u32 fleeFlag:2; // For RunAway and Smoke Ball. u32 fleeFlag:2; // For RunAway and Smoke Ball.
u32 usedImprisonedMove:1; u32 usedImprisonedMove:1;
@ -145,6 +145,7 @@ struct ProtectStruct
u32 micle:1; u32 micle:1;
u32 custap:1; // also quick claw u32 custap:1; // also quick claw
u32 touchedProtectLike:1; u32 touchedProtectLike:1;
u32 disableEjectPack:1;
u32 physicalDmg; u32 physicalDmg;
u32 specialDmg; u32 specialDmg;
u8 physicalBattlerId; u8 physicalBattlerId;
@ -153,6 +154,7 @@ struct ProtectStruct
struct SpecialStatus struct SpecialStatus
{ {
u8 statFell:1;
u8 statLowered:1; u8 statLowered:1;
u8 lightningRodRedirected:1; u8 lightningRodRedirected:1;
u8 restoredBattlerSprite: 1; u8 restoredBattlerSprite: 1;
@ -596,6 +598,7 @@ struct BattleStruct
u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon. u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon.
u8 quickClawBattlerId; u8 quickClawBattlerId;
struct StolenItem itemStolen[PARTY_SIZE]; // Player's team that had items stolen (two bytes per party member) struct StolenItem itemStolen[PARTY_SIZE]; // Player's team that had items stolen (two bytes per party member)
u8 blunderPolicy:1; // should blunder policy activate
}; };
#define GET_MOVE_TYPE(move, typeArg) \ #define GET_MOVE_TYPE(move, typeArg) \
@ -667,8 +670,9 @@ struct BattleScripting
u16 moveEffect; u16 moveEffect;
u16 multihitMoveEffect; u16 multihitMoveEffect;
u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN. u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN.
bool8 fixedPopup; // force ability popup to stick until manually called back bool8 fixedPopup; // Force ability popup to stick until manually called back
u16 abilityPopupOverwrite; u16 abilityPopupOverwrite;
u8 switchCase; // Special switching conditions, eg. red card
}; };
// rom_80A5C6C // rom_80A5C6C

View File

@ -373,6 +373,12 @@ extern const u8 BattleScript_BattlerShookOffTaunt[];
extern const u8 BattleScript_BattlerGotOverItsInfatuation[]; extern const u8 BattleScript_BattlerGotOverItsInfatuation[];
extern const u8 BattleScript_Pickpocket[]; extern const u8 BattleScript_Pickpocket[];
extern const u8 BattleScript_StickyBarbTransfer[]; extern const u8 BattleScript_StickyBarbTransfer[];
extern const u8 BattleScript_AttackerItemStatRaise[];
extern const u8 BattleScript_RedCardActivates[];
extern const u8 BattleScript_EjectButtonActivates[];
extern const u8 BattleScript_EjectPackActivate_Ret[];
extern const u8 BattleScript_EjectPackActivate_End2[];
extern const u8 BattleScript_EjectPackActivates[];
extern const u8 BattleScript_MentalHerbCureRet[]; extern const u8 BattleScript_MentalHerbCureRet[];
extern const u8 BattleScript_MentalHerbCureEnd2[]; extern const u8 BattleScript_MentalHerbCureEnd2[];

View File

@ -28,9 +28,10 @@
#define ITEMEFFECT_ON_SWITCH_IN 0x0 #define ITEMEFFECT_ON_SWITCH_IN 0x0
#define ITEMEFFECT_MOVE_END 0x3 #define ITEMEFFECT_MOVE_END 0x3
#define ITEMEFFECT_KINGSROCK_SHELLBELL 0x4 #define ITEMEFFECT_KINGSROCK 0x4
#define ITEMEFFECT_TARGET 0x5 #define ITEMEFFECT_TARGET 0x5
#define ITEMEFFECT_ORBS 0x6 #define ITEMEFFECT_ORBS 0x6
#define ITEMEFFECT_LIFEORB_SHELLBELL 0x7
#define WEATHER_HAS_EFFECT ((!IsAbilityOnField(ABILITY_CLOUD_NINE) && !IsAbilityOnField(ABILITY_AIR_LOCK))) #define WEATHER_HAS_EFFECT ((!IsAbilityOnField(ABILITY_CLOUD_NINE) && !IsAbilityOnField(ABILITY_AIR_LOCK)))
@ -144,7 +145,12 @@ void TryRestoreStolenItems(void);
bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item); bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item);
void TrySaveExchangedItem(u8 battlerId, u16 stolenItem); void TrySaveExchangedItem(u8 battlerId, u16 stolenItem);
bool32 IsPartnerMonFromSameTrainer(u8 battlerId); bool32 IsPartnerMonFromSameTrainer(u8 battlerId);
u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute);
bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes);
void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast);
bool32 CompareStat(u8 battlerId, u8 statId, u8 cmpTo, u8 cmpKind);
bool32 TryRoomService(u8 battlerId);
void BufferStatChange(u8 battlerId, u8 statId, u8 stringId);
// ability checks // ability checks
bool32 IsRolePlayBannedAbilityAtk(u16 ability); bool32 IsRolePlayBannedAbilityAtk(u16 ability);

View File

@ -37,6 +37,7 @@
#define sILLUSION_NICK_HACK gBattleScripting + 0x32 #define sILLUSION_NICK_HACK gBattleScripting + 0x32
#define sFIXED_ABILITY_POPUP gBattleScripting + 0x33 #define sFIXED_ABILITY_POPUP gBattleScripting + 0x33
#define sABILITY_OVERWRITE gBattleScripting + 0x34 #define sABILITY_OVERWRITE gBattleScripting + 0x34
#define sSWITCH_CASE gBattleScripting + 0x36
#define cMULTISTRING_CHOOSER gBattleCommunication + 5 #define cMULTISTRING_CHOOSER gBattleCommunication + 5
#define cMISS_TYPE gBattleCommunication + 6 #define cMISS_TYPE gBattleCommunication + 6
@ -174,6 +175,9 @@
#define VARIOUS_TOTEM_BOOST 103 #define VARIOUS_TOTEM_BOOST 103
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104 #define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104
#define VARIOUS_MOVEEND_ITEM_EFFECTS 105 #define VARIOUS_MOVEEND_ITEM_EFFECTS 105
#define VARIOUS_TERRAIN_SEED 106
#define VARIOUS_MAKE_INVISIBLE 107
#define VARIOUS_ROOM_SERVICE 108
// Cmd_manipulatedamage // Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0 #define DMG_CHANGE_SIGN 0
@ -228,16 +232,24 @@
#define MOVEEND_ITEM_EFFECTS_TARGET 13 #define MOVEEND_ITEM_EFFECTS_TARGET 13
#define MOVEEND_MOVE_EFFECTS2 14 #define MOVEEND_MOVE_EFFECTS2 14
#define MOVEEND_ITEM_EFFECTS_ALL 15 #define MOVEEND_ITEM_EFFECTS_ALL 15
#define MOVEEND_KINGSROCK_SHELLBELL 16 #define MOVEEND_KINGSROCK 16 // These item effects will occur each strike of a multi-hit move
#define MOVEEND_SUBSTITUTE 17 #define MOVEEND_SUBSTITUTE 17
#define MOVEEND_UPDATE_LAST_MOVES 18 #define MOVEEND_UPDATE_LAST_MOVES 18
#define MOVEEND_MIRROR_MOVE 19 #define MOVEEND_MIRROR_MOVE 19
#define MOVEEND_NEXT_TARGET 20 #define MOVEEND_NEXT_TARGET 20 // Everything up until here is handled for each strike of a multi-hit move
#define MOVEEND_LIFE_ORB 21 #define MOVEEND_EJECT_BUTTON 21
#define MOVEEND_PICKPOCKET 22 #define MOVEEND_RED_CARD 22
#define MOVEEND_DANCER 23 #define MOVEEND_EJECT_PACK 23
#define MOVEEND_EMERGENCY_EXIT 24 #define MOVEEND_LIFEORB_SHELLBELL 24 // Includes shell bell, throat spray, etc
#define MOVEEND_CLEAR_BITS 25 #define MOVEEND_PICKPOCKET 25
#define MOVEEND_COUNT 26 #define MOVEEND_DANCER 26
#define MOVEEND_EMERGENCY_EXIT 27
#define MOVEEND_CLEAR_BITS 28
#define MOVEEND_COUNT 29
// switch cases
#define B_SWITCH_NORMAL 0
#define B_SWITCH_HIT 1 // dragon tail, circle throw
#define B_SWITCH_RED_CARD 2
#endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H #endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H

View File

@ -573,11 +573,13 @@
#define STRINGID_ITEMCANNOTBEREMOVED 569 #define STRINGID_ITEMCANNOTBEREMOVED 569
#define STRINGID_STICKYBARBTRANSFER 570 #define STRINGID_STICKYBARBTRANSFER 570
#define STRINGID_PKMNBURNHEALED 571 #define STRINGID_PKMNBURNHEALED 571
#define STRINGID_ATKGOTOVERINFATUATION 572 #define STRINGID_REDCARDACTIVATE 572
#define STRINGID_TORMENTEDNOMORE 573 #define STRINGID_EJECTBUTTONACTIVATE 573
#define STRINGID_HEALBLOCKEDNOMORE 574 #define STRINGID_ATKGOTOVERINFATUATION 574
#define STRINGID_TORMENTEDNOMORE 575
#define STRINGID_HEALBLOCKEDNOMORE 576
#define BATTLESTRINGS_COUNT 575 #define BATTLESTRINGS_COUNT 577
// The below IDs are all indexes into battle message tables, // The below IDs are all indexes into battle message tables,
// used to determine which of a set of messages to print. // used to determine which of a set of messages to print.

View File

@ -154,4 +154,10 @@
#define HOLD_EFFECT_CHOICE(holdEffect)((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS)) #define HOLD_EFFECT_CHOICE(holdEffect)((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS))
// Terrain seed params
#define HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN 0
#define HOLD_EFFECT_PARAM_GRASSY_TERRAIN 1
#define HOLD_EFFECT_PARAM_MISTY_TERRAIN 2
#define HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN 3
#endif // GUARD_HOLD_EFFECTS_H #endif // GUARD_HOLD_EFFECTS_H

View File

@ -3033,6 +3033,10 @@ void SwitchInClearSetData(void)
gCurrentMove = 0; gCurrentMove = 0;
gBattleStruct->arenaTurnCounter = 0xFF; gBattleStruct->arenaTurnCounter = 0xFF;
// Reset damage to prevent things like red card activating if the switched-in mon is holding it
gSpecialStatuses[gActiveBattler].physicalDmg = 0;
gSpecialStatuses[gActiveBattler].specialDmg = 0;
ClearBattlerMoveHistory(gActiveBattler); ClearBattlerMoveHistory(gActiveBattler);
ClearBattlerAbilityHistory(gActiveBattler); ClearBattlerAbilityHistory(gActiveBattler);
ClearBattlerItemEffectHistory(gActiveBattler); ClearBattlerItemEffectHistory(gActiveBattler);
@ -3074,7 +3078,7 @@ void FaintClearSetData(void)
gProtectStructs[gActiveBattler].stealMove = 0; gProtectStructs[gActiveBattler].stealMove = 0;
gProtectStructs[gActiveBattler].prlzImmobility = 0; gProtectStructs[gActiveBattler].prlzImmobility = 0;
gProtectStructs[gActiveBattler].confusionSelfDmg = 0; gProtectStructs[gActiveBattler].confusionSelfDmg = 0;
gProtectStructs[gActiveBattler].targetNotAffected = 0; gProtectStructs[gActiveBattler].targetAffected = 0;
gProtectStructs[gActiveBattler].chargingTurn = 0; gProtectStructs[gActiveBattler].chargingTurn = 0;
gProtectStructs[gActiveBattler].fleeFlag = 0; gProtectStructs[gActiveBattler].fleeFlag = 0;
gProtectStructs[gActiveBattler].usedImprisonedMove = 0; gProtectStructs[gActiveBattler].usedImprisonedMove = 0;

View File

@ -699,15 +699,20 @@ static const u8 sText_PkmnGotOverItsInfatuation[] = _("{B_SCR_ACTIVE_NAME_WITH_P
static const u8 sText_ItemCannotBeRemoved[] = _("{B_ATK_NAME_WITH_PREFIX}'s item cannot be removed!"); static const u8 sText_ItemCannotBeRemoved[] = _("{B_ATK_NAME_WITH_PREFIX}'s item cannot be removed!");
static const u8 sText_StickyBarbTransfer[] = _("The {B_LAST_ITEM} attached itself to\n{B_ATK_NAME_WITH_PREFIX}!"); static const u8 sText_StickyBarbTransfer[] = _("The {B_LAST_ITEM} attached itself to\n{B_ATK_NAME_WITH_PREFIX}!");
static const u8 sText_PkmnBurnHealed[] = _("{B_DEF_NAME_WITH_PREFIX}'s\nburn was healed."); static const u8 sText_PkmnBurnHealed[] = _("{B_DEF_NAME_WITH_PREFIX}'s\nburn was healed.");
static const u8 sText_RedCardActivate[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} held up its {B_LAST_ITEM}\nagainst {B_ATK_NAME_WITH_PREFIX}!");
static const u8 sText_EjectButtonActivate[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is switched\nout with the {B_LAST_ITEM}!");
static const u8 sText_AttackerGotOverInfatuation[] =_("{B_ATK_NAME_WITH_PREFIX} got over\nits infatuation!"); static const u8 sText_AttackerGotOverInfatuation[] =_("{B_ATK_NAME_WITH_PREFIX} got over\nits infatuation!");
static const u8 sText_TormentedNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is\ntormented no more!"); static const u8 sText_TormentedNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is\ntormented no more!");
static const u8 sText_HealBlockedNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is cured of\nits heal block!"); static const u8 sText_HealBlockedNoMore[] = _("{B_ATK_NAME_WITH_PREFIX} is cured of\nits heal block!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{ {
[STRINGID_HEALBLOCKEDNOMORE - 12] = sText_HealBlockedNoMore, [STRINGID_HEALBLOCKEDNOMORE - 12] = sText_HealBlockedNoMore,
[STRINGID_TORMENTEDNOMORE - 12] = sText_TormentedNoMore, [STRINGID_TORMENTEDNOMORE - 12] = sText_TormentedNoMore,
[STRINGID_ATKGOTOVERINFATUATION - 12] = sText_AttackerGotOverInfatuation, [STRINGID_ATKGOTOVERINFATUATION - 12] = sText_AttackerGotOverInfatuation,
[STRINGID_EJECTBUTTONACTIVATE - 12] = sText_EjectButtonActivate,
[STRINGID_REDCARDACTIVATE - 12] = sText_RedCardActivate,
[STRINGID_PKMNBURNHEALED - 12] = sText_PkmnBurnHealed, [STRINGID_PKMNBURNHEALED - 12] = sText_PkmnBurnHealed,
[STRINGID_STICKYBARBTRANSFER - 12] = sText_StickyBarbTransfer, [STRINGID_STICKYBARBTRANSFER - 12] = sText_StickyBarbTransfer,
[STRINGID_ITEMCANNOTBEREMOVED - 12] = sText_ItemCannotBeRemoved, [STRINGID_ITEMCANNOTBEREMOVED - 12] = sText_ItemCannotBeRemoved,

View File

@ -1681,6 +1681,9 @@ static void Cmd_accuracycheck(void)
if ((Random() % 100 + 1) > GetTotalAccuracy(gBattlerAttacker, gBattlerTarget, move)) if ((Random() % 100 + 1) > GetTotalAccuracy(gBattlerAttacker, gBattlerTarget, move))
{ {
gMoveResultFlags |= MOVE_RESULT_MISSED; gMoveResultFlags |= MOVE_RESULT_MISSED;
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
(gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY)) (gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY))
gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK; gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK;
@ -3597,52 +3600,11 @@ static void Cmd_jumpifstat(void)
{ {
bool32 ret = 0; bool32 ret = 0;
u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); u8 battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
u8 statValue = gBattleMons[battlerId].statStages[gBattlescriptCurrInstr[3]]; u8 statId = gBattlescriptCurrInstr[3];
u8 cmpTo = gBattlescriptCurrInstr[4]; u8 cmpTo = gBattlescriptCurrInstr[4];
u8 cmpKind = gBattlescriptCurrInstr[2]; u8 cmpKind = gBattlescriptCurrInstr[2];
// Because this command is used as a way of checking if a stat can be lowered/raised, ret = CompareStat(battlerId, statId, cmpTo, cmpKind);
// we need to do some modification at run-time.
if (GetBattlerAbility(battlerId) == ABILITY_CONTRARY)
{
if (cmpKind == CMP_GREATER_THAN)
cmpKind = CMP_LESS_THAN;
else if (cmpKind == CMP_LESS_THAN)
cmpKind = CMP_GREATER_THAN;
if (cmpTo == 0)
cmpTo = 0xC;
else if (cmpTo == 0xC)
cmpTo = 0;
}
switch (cmpKind)
{
case CMP_EQUAL:
if (statValue == cmpTo)
ret++;
break;
case CMP_NOT_EQUAL:
if (statValue != cmpTo)
ret++;
break;
case CMP_GREATER_THAN:
if (statValue > cmpTo)
ret++;
break;
case CMP_LESS_THAN:
if (statValue < cmpTo)
ret++;
break;
case CMP_COMMON_BITS:
if (statValue & cmpTo)
ret++;
break;
case CMP_NO_COMMON_BITS:
if (!(statValue & cmpTo))
ret++;
break;
}
if (ret) if (ret)
gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 5); gBattlescriptCurrInstr = T2_READ_PTR(gBattlescriptCurrInstr + 5);
@ -4844,7 +4806,7 @@ static void Cmd_moveend(void)
&& gBattleMons[gBattlerTarget].hp != 0 && gBattlerAttacker != gBattlerTarget && gBattleMons[gBattlerTarget].hp != 0 && gBattlerAttacker != gBattlerTarget
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget) && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && TARGET_TURN_DAMAGED && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && TARGET_TURN_DAMAGED
&& gBattleMoves[gCurrentMove].power && gBattleMons[gBattlerTarget].statStages[STAT_ATK] < MAX_STAT_STAGE) && gBattleMoves[gCurrentMove].power && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
gBattleMons[gBattlerTarget].statStages[STAT_ATK]++; gBattleMons[gBattlerTarget].statStages[STAT_ATK]++;
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4951,8 +4913,9 @@ static void Cmd_moveend(void)
else else
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_KINGSROCK_SHELLBELL: // king's rock and shell bell case MOVEEND_KINGSROCK: // King's rock
if (ItemBattleEffects(ITEMEFFECT_KINGSROCK_SHELLBELL, 0, FALSE)) // These effects will occur at each hit in a multi-strike move
if (ItemBattleEffects(ITEMEFFECT_KINGSROCK, 0, FALSE))
effect = TRUE; effect = TRUE;
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
@ -5080,6 +5043,11 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon. case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon.
// Set a flag if move hits either target (for throat spray that can't check damage)
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
gProtectStructs[gBattlerAttacker].targetAffected = 1;
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& !gProtectStructs[gBattlerAttacker].chargingTurn && !gProtectStructs[gBattlerAttacker].chargingTurn
@ -5124,21 +5092,104 @@ static void Cmd_moveend(void)
RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove); RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove);
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_LIFE_ORB: case MOVEEND_EJECT_BUTTON:
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIFE_ORB if (gCurrentMove != MOVE_DRAGON_TAIL
&& gCurrentMove != MOVE_CIRCLE_THROW
&& IsBattlerAlive(gBattlerAttacker) && IsBattlerAlive(gBattlerAttacker)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)) && !TestSheerForceFlag(gBattlerAttacker, gCurrentMove)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD && (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER || (gBattleTypeFlags & BATTLE_TYPE_TRAINER)))
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
{ {
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 10; // Since we check if battler was damaged, we don't need to check move result.
if (gBattleMoveDamage == 0) // In fact, doing so actually prevents multi-target moves from activating eject button properly
gBattleMoveDamage = 1; u8 battlers[4] = {0, 1, 2, 3};
effect = TRUE; SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u8 battler = battlers[i];
// Attacker is the damage-dealer, battler is mon to be switched out
if (IsBattlerAlive(battler)
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_BUTTON
&& !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler)
&& (gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0)
&& CountUsablePartyMons(battler) > 0) // Has mon to switch into
{
gActiveBattler = gBattleScripting.battler = battler;
gLastUsedItem = gBattleMons[battler].item;
if (gBattleMoves[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ItemHurtRet; gBattlescriptCurrInstr = BattleScript_EjectButtonActivates;
gLastUsedItem = gBattleMons[gBattlerAttacker].item; effect = TRUE;
break; // Only the fastest Eject Button activates
} }
}
}
gBattleScripting.moveendState++;
break;
case MOVEEND_RED_CARD:
if (gCurrentMove != MOVE_DRAGON_TAIL
&& gCurrentMove != MOVE_CIRCLE_THROW
&& IsBattlerAlive(gBattlerAttacker)
&& !TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
{
// Since we check if battler was damaged, we don't need to check move result.
// In fact, doing so actually prevents multi-target moves from activating red card properly
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u8 battler = battlers[i];
// Search for fastest hit pokemon with a red card
// Attacker is the one to be switched out, battler is one with red card
if (battler != gBattlerAttacker
&& IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler)
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RED_CARD
&& (gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0)
&& CanBattlerSwitch(gBattlerAttacker))
{
gLastUsedItem = gBattleMons[battler].item;
gActiveBattler = gBattleStruct->savedBattlerTarget = gBattleScripting.battler = battler; // Battler with red card
gEffectBattler = gBattlerAttacker;
if (gBattleMoves[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
effect = TRUE;
break; // Only fastest red card activates
}
}
}
gBattleScripting.moveendState++;
break;
case MOVEEND_EJECT_PACK:
{
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u8 battler = battlers[i];
if (IsBattlerAlive(battler)
&& gSpecialStatuses[battler].statFell
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_PACK
&& !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker)) // Does not activate if attacker used Parting Shot and can switch out
&& CountUsablePartyMons(battler) > 0) // Has mon to switch into
{
gSpecialStatuses[battler].statFell = FALSE;
gActiveBattler = gBattleScripting.battler = battler;
gLastUsedItem = gBattleMons[battler].item;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_EjectPackActivates;
effect = TRUE;
break; // Only fastest eject pack activates
}
}
}
gBattleScripting.moveendState++;
break;
case MOVEEND_LIFEORB_SHELLBELL:
if (ItemBattleEffects(ITEMEFFECT_LIFEORB_SHELLBELL, 0, FALSE))
effect = TRUE;
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_PICKPOCKET: case MOVEEND_PICKPOCKET:
@ -5241,6 +5292,7 @@ static void Cmd_moveend(void)
if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget) if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget)
*(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3; *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3;
gProtectStructs[gBattlerAttacker].usesBouncedMove = 0; gProtectStructs[gBattlerAttacker].usesBouncedMove = 0;
gProtectStructs[gBattlerAttacker].targetAffected = 0;
gBattleStruct->ateBoost[gBattlerAttacker] = 0; gBattleStruct->ateBoost[gBattlerAttacker] = 0;
gStatuses3[gBattlerAttacker] &= ~(STATUS3_ME_FIRST); gStatuses3[gBattlerAttacker] &= ~(STATUS3_ME_FIRST);
gSpecialStatuses[gBattlerAttacker].gemBoost = 0; gSpecialStatuses[gBattlerAttacker].gemBoost = 0;
@ -5510,6 +5562,7 @@ bool32 CanBattlerSwitch(u32 battlerId)
} }
else else
{ {
// Check if attacker side has mon to switch into
battlerIn1 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); battlerIn1 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
@ -5944,6 +5997,7 @@ static void Cmd_switchineffects(void)
if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED) if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES_DAMAGED)
&& (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES) && (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_SPIKES)
&& GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD && GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD
&& IsBattlerAffectedByHazards(gActiveBattler, FALSE)
&& IsBattlerGrounded(gActiveBattler)) && IsBattlerGrounded(gActiveBattler))
{ {
u8 spikesDmg = (5 - gSideTimers[GetBattlerSide(gActiveBattler)].spikesAmount) * 2; u8 spikesDmg = (5 - gSideTimers[GetBattlerSide(gActiveBattler)].spikesAmount) * 2;
@ -5956,6 +6010,7 @@ static void Cmd_switchineffects(void)
} }
else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STEALTH_ROCK_DAMAGED) else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STEALTH_ROCK_DAMAGED)
&& (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STEALTH_ROCK) && (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STEALTH_ROCK)
&& IsBattlerAffectedByHazards(gActiveBattler, FALSE)
&& GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD) && GetBattlerAbility(gActiveBattler) != ABILITY_MAGIC_GUARD)
{ {
gSideStatuses[GetBattlerSide(gActiveBattler)] |= SIDE_STATUS_STEALTH_ROCK_DAMAGED; gSideStatuses[GetBattlerSide(gActiveBattler)] |= SIDE_STATUS_STEALTH_ROCK_DAMAGED;
@ -5977,7 +6032,7 @@ static void Cmd_switchineffects(void)
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ToxicSpikesAbsorbed; gBattlescriptCurrInstr = BattleScript_ToxicSpikesAbsorbed;
} }
else else if (IsBattlerAffectedByHazards(gActiveBattler, TRUE))
{ {
if (!(gBattleMons[gActiveBattler].status1 & STATUS1_ANY) if (!(gBattleMons[gActiveBattler].status1 & STATUS1_ANY)
&& !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL) && !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL)
@ -5999,6 +6054,7 @@ static void Cmd_switchineffects(void)
} }
else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STICKY_WEB_DAMAGED) else if (!(gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STICKY_WEB_DAMAGED)
&& (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STICKY_WEB) && (gSideStatuses[GetBattlerSide(gActiveBattler)] & SIDE_STATUS_STICKY_WEB)
&& IsBattlerAffectedByHazards(gActiveBattler, FALSE)
&& IsBattlerGrounded(gActiveBattler)) && IsBattlerGrounded(gActiveBattler))
{ {
gSideStatuses[GetBattlerSide(gActiveBattler)] |= SIDE_STATUS_STICKY_WEB_DAMAGED; gSideStatuses[GetBattlerSide(gActiveBattler)] |= SIDE_STATUS_STICKY_WEB_DAMAGED;
@ -7454,7 +7510,7 @@ static void Cmd_various(void)
bits = 0; bits = 0;
for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++)
{ {
if (gBattleMons[gActiveBattler].statStages[i] != 12) if (CompareStat(gActiveBattler, i, MAX_STAT_STAGE, CMP_LESS_THAN))
bits |= gBitTable[i]; bits |= gBitTable[i];
} }
if (bits) if (bits)
@ -7691,7 +7747,7 @@ static void Cmd_various(void)
|| GetBattlerAbility(gActiveBattler) == ABILITY_AS_ONE_ICE_RIDER) || GetBattlerAbility(gActiveBattler) == ABILITY_AS_ONE_ICE_RIDER)
&& HasAttackerFaintedTarget() && HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty() && !NoAliveMonsForEitherParty()
&& gBattleMons[gBattlerAttacker].statStages[STAT_ATK] != 12) && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
gBattleMons[gBattlerAttacker].statStages[STAT_ATK]++; gBattleMons[gBattlerAttacker].statStages[STAT_ATK]++;
SET_STATCHANGER(STAT_ATK, 1, FALSE); SET_STATCHANGER(STAT_ATK, 1, FALSE);
@ -7709,7 +7765,7 @@ static void Cmd_various(void)
|| GetBattlerAbility(gActiveBattler) == ABILITY_AS_ONE_SHADOW_RIDER) || GetBattlerAbility(gActiveBattler) == ABILITY_AS_ONE_SHADOW_RIDER)
&& HasAttackerFaintedTarget() && HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty() && !NoAliveMonsForEitherParty()
&& gBattleMons[gBattlerAttacker].statStages[STAT_SPATK] != 12) && CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
gBattleMons[gBattlerAttacker].statStages[STAT_SPATK]++; gBattleMons[gBattlerAttacker].statStages[STAT_SPATK]++;
SET_STATCHANGER(STAT_SPATK, 1, FALSE); SET_STATCHANGER(STAT_SPATK, 1, FALSE);
@ -7754,7 +7810,7 @@ static void Cmd_various(void)
if (GetBattlerAbility(gActiveBattler) == ABILITY_BEAST_BOOST if (GetBattlerAbility(gActiveBattler) == ABILITY_BEAST_BOOST
&& HasAttackerFaintedTarget() && HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty() && !NoAliveMonsForEitherParty()
&& gBattleMons[gBattlerAttacker].statStages[i] != 12) && CompareStat(gBattlerAttacker, i, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
gBattleMons[gBattlerAttacker].statStages[i]++; gBattleMons[gBattlerAttacker].statStages[i]++;
SET_STATCHANGER(i, 1, FALSE); SET_STATCHANGER(i, 1, FALSE);
@ -7771,7 +7827,7 @@ static void Cmd_various(void)
if (GetBattlerAbility(gBattleScripting.battler) == ABILITY_SOUL_HEART if (GetBattlerAbility(gBattleScripting.battler) == ABILITY_SOUL_HEART
&& IsBattlerAlive(gBattleScripting.battler) && IsBattlerAlive(gBattleScripting.battler)
&& !NoAliveMonsForEitherParty() && !NoAliveMonsForEitherParty()
&& gBattleMons[gBattleScripting.battler].statStages[STAT_SPATK] != 12) && CompareStat(gBattleScripting.battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
gBattleMons[gBattleScripting.battler].statStages[STAT_SPATK]++; gBattleMons[gBattleScripting.battler].statStages[STAT_SPATK]++;
SET_STATCHANGER(STAT_SPATK, 1, FALSE); SET_STATCHANGER(STAT_SPATK, 1, FALSE);
@ -7787,7 +7843,7 @@ static void Cmd_various(void)
if (gBattleMoves[gCurrentMove].effect == EFFECT_FELL_STINGER if (gBattleMoves[gCurrentMove].effect == EFFECT_FELL_STINGER
&& HasAttackerFaintedTarget() && HasAttackerFaintedTarget()
&& !NoAliveMonsForEitherParty() && !NoAliveMonsForEitherParty()
&& gBattleMons[gBattlerAttacker].statStages[STAT_ATK] != 12) && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
if (B_FELL_STINGER_STAT_RAISE >= GEN_7) if (B_FELL_STINGER_STAT_RAISE >= GEN_7)
SET_STATCHANGER(STAT_ATK, 3, FALSE); SET_STATCHANGER(STAT_ATK, 3, FALSE);
@ -8113,6 +8169,7 @@ static void Cmd_various(void)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED) && TARGET_TURN_DAMAGED)
{ {
gBattleScripting.switchCase = B_SWITCH_HIT;
gBattlescriptCurrInstr = BattleScript_ForceRandomSwitch; gBattlescriptCurrInstr = BattleScript_ForceRandomSwitch;
} }
else else
@ -8498,6 +8555,50 @@ static void Cmd_various(void)
if (ItemBattleEffects(1, gActiveBattler, FALSE)) if (ItemBattleEffects(1, gActiveBattler, FALSE))
return; return;
break; break;
case VARIOUS_ROOM_SERVICE:
if (GetBattlerHoldEffect(gActiveBattler, TRUE) == HOLD_EFFECT_ROOM_SERVICE && TryRoomService(gActiveBattler))
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryStatRaiseRet;
}
else
{
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
}
return;
case VARIOUS_TERRAIN_SEED:
if (GetBattlerHoldEffect(gActiveBattler, TRUE) == HOLD_EFFECT_SEEDS)
{
u8 effect = 0;
u16 item = gBattleMons[gActiveBattler].item;
switch (GetBattlerHoldEffectParam(gActiveBattler))
{
case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN:
effect = TryHandleSeed(gActiveBattler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, item, FALSE);
break;
case HOLD_EFFECT_PARAM_GRASSY_TERRAIN:
effect = TryHandleSeed(gActiveBattler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, item, FALSE);
break;
case HOLD_EFFECT_PARAM_MISTY_TERRAIN:
effect = TryHandleSeed(gActiveBattler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, item, FALSE);
break;
case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN:
effect = TryHandleSeed(gActiveBattler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, item, FALSE);
break;
}
if (effect)
return;
}
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
return;
case VARIOUS_MAKE_INVISIBLE:
if (gBattleControllerExecFlags)
break;
BtlController_EmitSpriteInvisibility(0, TRUE);
MarkBattlerForControllerExec(gActiveBattler);
break;
} }
gBattlescriptCurrInstr += 3; gBattlescriptCurrInstr += 3;
@ -9184,11 +9285,18 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
gBattleTextBuff2[index] = B_BUFF_EOS; gBattleTextBuff2[index] = B_BUFF_EOS;
if (gBattleMons[gActiveBattler].statStages[statId] == MIN_STAT_STAGE) if (gBattleMons[gActiveBattler].statStages[statId] == MIN_STAT_STAGE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_DECREASE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_DECREASE;
}
else else
{
// Check eject pack. disableEjectPack set for edge cases (e.g. attacking weak armor'd eject pack holder with u-turn)
if (gProtectStructs[gActiveBattler].disableEjectPack == 0)
gSpecialStatuses[gActiveBattler].statFell = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL
} }
} }
}
else // stat increase else // stat increase
{ {
statValue = GET_STAT_BUFF_VALUE(statValue); statValue = GET_STAT_BUFF_VALUE(statValue);
@ -9362,6 +9470,36 @@ static void Cmd_forcerandomswitch(void)
s32 validMons = 0; s32 validMons = 0;
s32 minNeeded; s32 minNeeded;
bool32 redCardForcedSwitch = FALSE;
// Red card checks against wild pokemon. If we have reached here, the player has a mon to switch into
// Red card swaps attacker with target to get the animation correct, so here we check attacker which is really the target. Thanks GF...
if (gBattleScripting.switchCase == B_SWITCH_RED_CARD
&& !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT) // Check opponent's red card activating
{
if (!WILD_DOUBLE_BATTLE)
{
// Wild mon with red card will end single battle
gBattlescriptCurrInstr = BattleScript_RoarSuccessEndBattle;
return;
}
else
{
// Wild double battle, wild mon red card activation on player
if (IS_WHOLE_SIDE_ALIVE(gBattlerTarget))
{
// Both player's battlers are alive
redCardForcedSwitch = FALSE;
}
else
{
// Player has only one mon alive -> force red card switch before manually switching to other mon
redCardForcedSwitch = TRUE;
}
}
}
// Swapping pokemon happens in: // Swapping pokemon happens in:
// trainer battles // trainer battles
// wild double battles when an opposing pokemon uses it against one of the two alive player mons // wild double battles when an opposing pokemon uses it against one of the two alive player mons
@ -9374,6 +9512,7 @@ static void Cmd_forcerandomswitch(void)
|| (WILD_DOUBLE_BATTLE || (WILD_DOUBLE_BATTLE
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER
&& GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) && GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
|| redCardForcedSwitch
) )
{ {
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
@ -9483,7 +9622,7 @@ static void Cmd_forcerandomswitch(void)
} }
} }
if (validMons <= minNeeded) if (!redCardForcedSwitch && validMons <= minNeeded)
{ {
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
} }
@ -10652,8 +10791,8 @@ static void Cmd_handlerollout(void)
static void Cmd_jumpifconfusedandstatmaxed(void) static void Cmd_jumpifconfusedandstatmaxed(void)
{ {
if (gBattleMons[gBattlerTarget].status2 & STATUS2_CONFUSION if (gBattleMons[gBattlerTarget].status2 & STATUS2_CONFUSION
&& gBattleMons[gBattlerTarget].statStages[gBattlescriptCurrInstr[1]] == MAX_STAT_STAGE) && !CompareStat(gBattlerTarget, gBattlescriptCurrInstr[1], MAX_STAT_STAGE, CMP_LESS_THAN))
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); // Fails if we're confused AND stat cannot be raised
else else
gBattlescriptCurrInstr += 6; gBattlescriptCurrInstr += 6;
} }
@ -10863,6 +11002,7 @@ static void Cmd_maxattackhalvehp(void) // belly drum
if (!(gBattleMons[gBattlerAttacker].maxHP / 2)) if (!(gBattleMons[gBattlerAttacker].maxHP / 2))
halfHp = 1; halfHp = 1;
// Belly Drum fails if the user's current HP is less than half its maximum, or if the user's Attack is already at +6 (even if the user has Contrary).
if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE
&& gBattleMons[gBattlerAttacker].hp > halfHp) && gBattleMons[gBattlerAttacker].hp > halfHp)
{ {

View File

@ -1410,7 +1410,6 @@ void CancelMultiTurnMoves(u8 battler)
bool8 WasUnableToUseMove(u8 battler) bool8 WasUnableToUseMove(u8 battler)
{ {
if (gProtectStructs[battler].prlzImmobility if (gProtectStructs[battler].prlzImmobility
|| gProtectStructs[battler].targetNotAffected
|| gProtectStructs[battler].usedImprisonedMove || gProtectStructs[battler].usedImprisonedMove
|| gProtectStructs[battler].loveImmobility || gProtectStructs[battler].loveImmobility
|| gProtectStructs[battler].usedDisabledMove || gProtectStructs[battler].usedDisabledMove
@ -1444,8 +1443,8 @@ void PrepareStringBattle(u16 stringId, u8 battler)
// Check Defiant and Competitive stat raise whenever a stat is lowered. // Check Defiant and Competitive stat raise whenever a stat is lowered.
else if ((stringId == STRINGID_DEFENDERSSTATFELL || stringId == STRINGID_PKMNCUTSATTACKWITH) else if ((stringId == STRINGID_DEFENDERSSTATFELL || stringId == STRINGID_PKMNCUTSATTACKWITH)
&& ((GetBattlerAbility(gBattlerTarget) == ABILITY_DEFIANT && gBattleMons[gBattlerTarget].statStages[STAT_ATK] != MAX_STAT_STAGE) && ((GetBattlerAbility(gBattlerTarget) == ABILITY_DEFIANT && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|| (GetBattlerAbility(gBattlerTarget) == ABILITY_COMPETITIVE && gBattleMons[gBattlerTarget].statStages[STAT_SPATK] != MAX_STAT_STAGE)) || (GetBattlerAbility(gBattlerTarget) == ABILITY_COMPETITIVE && CompareStat(gBattlerTarget, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)))
&& gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != BATTLE_PARTNER(gBattlerTarget) && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != BATTLE_PARTNER(gBattlerTarget)
&& gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget) && gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget)
{ {
@ -4053,7 +4052,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
gSpecialStatuses[battler].switchInAbilityDone = 1; gSpecialStatuses[battler].switchInAbilityDone = 1;
if (gBattleMons[battler].statStages[statId] != MAX_STAT_STAGE) if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
gBattleMons[battler].statStages[statId]++; gBattleMons[battler].statStages[statId]++;
SET_STATCHANGER(statId, 1, FALSE); SET_STATCHANGER(statId, 1, FALSE);
@ -4304,7 +4303,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
} }
break; break;
case ABILITY_SPEED_BOOST: case ABILITY_SPEED_BOOST:
if (gBattleMons[battler].statStages[STAT_SPEED] < MAX_STAT_STAGE && gDisableStructs[battler].isFirstTurn != 2) if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) && gDisableStructs[battler].isFirstTurn != 2)
{ {
gBattleMons[battler].statStages[STAT_SPEED]++; gBattleMons[battler].statStages[STAT_SPEED]++;
gBattleScripting.animArg1 = 14 + STAT_SPEED; gBattleScripting.animArg1 = 14 + STAT_SPEED;
@ -4322,9 +4321,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
for (i = STAT_ATK; i < statsNum; i++) for (i = STAT_ATK; i < statsNum; i++)
{ {
if (gBattleMons[battler].statStages[i] != MIN_STAT_STAGE) if (CompareStat(battler, i, MIN_STAT_STAGE, CMP_GREATER_THAN))
validToLower |= gBitTable[i]; validToLower |= gBitTable[i];
if (gBattleMons[battler].statStages[i] != MAX_STAT_STAGE) if (CompareStat(battler, i, MAX_STAT_STAGE, CMP_LESS_THAN))
validToRaise |= gBitTable[i]; validToRaise |= gBitTable[i];
} }
@ -4527,7 +4526,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
} }
else if (effect == 2) // Boost Stat ability; else if (effect == 2) // Boost Stat ability;
{ {
if (gBattleMons[battler].statStages[statId] == MAX_STAT_STAGE) if (!CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
if ((gProtectStructs[gBattlerAttacker].notFirstStrike)) if ((gProtectStructs[gBattlerAttacker].notFirstStrike))
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless; gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless;
@ -4556,7 +4555,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& moveType == TYPE_DARK && moveType == TYPE_DARK
&& gBattleMons[battler].statStages[STAT_ATK] != MAX_STAT_STAGE) && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
SET_STATCHANGER(STAT_ATK, 1, FALSE); SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4569,7 +4568,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST) && (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST)
&& gBattleMons[battler].statStages[STAT_SPEED] != MAX_STAT_STAGE) && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
SET_STATCHANGER(STAT_SPEED, 1, FALSE); SET_STATCHANGER(STAT_SPEED, 1, FALSE);
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4582,7 +4581,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& moveType == TYPE_WATER && moveType == TYPE_WATER
&& gBattleMons[battler].statStages[STAT_DEF] != MAX_STAT_STAGE) && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
SET_STATCHANGER(STAT_DEF, 2, FALSE); SET_STATCHANGER(STAT_DEF, 2, FALSE);
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4594,7 +4593,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& gBattleMons[battler].statStages[STAT_DEF] != MAX_STAT_STAGE) && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
SET_STATCHANGER(STAT_DEF, 1, FALSE); SET_STATCHANGER(STAT_DEF, 1, FALSE);
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4611,7 +4610,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2 && gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1) && (gMultiHitCounter == 0 || gMultiHitCounter == 1)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)) && !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& gBattleMons[battler].statStages[STAT_SPATK] != MAX_STAT_STAGE) && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
SET_STATCHANGER(STAT_SPATK, 1, FALSE); SET_STATCHANGER(STAT_SPATK, 1, FALSE);
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4642,8 +4641,12 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& IS_MOVE_PHYSICAL(gCurrentMove) && IS_MOVE_PHYSICAL(gCurrentMove)
&& (gBattleMons[battler].statStages[STAT_SPEED] != MAX_STAT_STAGE || gBattleMons[battler].statStages[STAT_DEF] != MIN_STAT_STAGE)) && (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) // Don't activate if speed cannot be raised
|| CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN))) // Don't activate if defense cannot be lowered
{ {
if (gBattleMoves[gCurrentMove].effect == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker))
gProtectStructs[battler].disableEjectPack = 1; // Set flag for target
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_WeakArmorActivates; gBattlescriptCurrInstr = BattleScript_WeakArmorActivates;
effect++; effect++;
@ -4699,7 +4702,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
&& gIsCriticalHit && gIsCriticalHit
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& gBattleMons[battler].statStages[STAT_ATK] != MAX_STAT_STAGE) && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
{ {
SET_STATCHANGER(STAT_ATK, MAX_STAT_STAGE - gBattleMons[battler].statStages[STAT_ATK], FALSE); SET_STATCHANGER(STAT_ATK, MAX_STAT_STAGE - gBattleMons[battler].statStages[STAT_ATK], FALSE);
BattleScriptPushCursor(); BattleScriptPushCursor();
@ -4726,7 +4729,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
case ABILITY_TANGLING_HAIR: case ABILITY_TANGLING_HAIR:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0 && gBattleMons[gBattlerAttacker].hp != 0
&& gBattleMons[gBattlerAttacker].statStages[STAT_SPEED] != MIN_STAT_STAGE && CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg && !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsMoveMakingContact(move, gBattlerAttacker)) && IsMoveMakingContact(move, gBattlerAttacker))
@ -4920,7 +4923,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler) && IsBattlerAlive(battler)
&& gBattleMons[battler].statStages[STAT_SPEED] != MAX_STAT_STAGE && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)
&& (moveType == TYPE_FIRE || moveType == TYPE_WATER)) && (moveType == TYPE_FIRE || moveType == TYPE_WATER))
{ {
SET_STATCHANGER(STAT_SPEED, 6, FALSE); SET_STATCHANGER(STAT_SPEED, 6, FALSE);
@ -5443,11 +5446,9 @@ static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2)
static u8 StatRaiseBerry(u32 battlerId, u32 itemId, u32 statId, bool32 end2) static u8 StatRaiseBerry(u32 battlerId, u32 itemId, u32 statId, bool32 end2)
{ {
if (gBattleMons[battlerId].statStages[statId] < MAX_STAT_STAGE && HasEnoughHpToEatBerry(battlerId, GetBattlerHoldEffectParam(battlerId), itemId)) if (CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && HasEnoughHpToEatBerry(battlerId, GetBattlerHoldEffectParam(battlerId), itemId))
{ {
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); BufferStatChange(battlerId, statId, STRINGID_STATROSE);
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE);
gEffectBattler = battlerId; gEffectBattler = battlerId;
if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) if (GetBattlerAbility(battlerId) == ABILITY_RIPEN)
SET_STATCHANGER(statId, 2, FALSE); SET_STATCHANGER(statId, 2, FALSE);
@ -5474,10 +5475,11 @@ static u8 StatRaiseBerry(u32 battlerId, u32 itemId, u32 statId, bool32 end2)
static u8 RandomStatRaiseBerry(u32 battlerId, u32 itemId, bool32 end2) static u8 RandomStatRaiseBerry(u32 battlerId, u32 itemId, bool32 end2)
{ {
s32 i; s32 i;
u16 stringId;
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
{ {
if (gBattleMons[battlerId].statStages[STAT_ATK + i] < MAX_STAT_STAGE) if (CompareStat(battlerId, STAT_ATK + i, MAX_STAT_STAGE, CMP_LESS_THAN))
break; break;
} }
if (i != 5 && HasEnoughHpToEatBerry(battlerId, GetBattlerHoldEffectParam(battlerId), itemId)) if (i != 5 && HasEnoughHpToEatBerry(battlerId, GetBattlerHoldEffectParam(battlerId), itemId))
@ -5485,21 +5487,19 @@ static u8 RandomStatRaiseBerry(u32 battlerId, u32 itemId, bool32 end2)
do do
{ {
i = Random() % 5; i = Random() % 5;
} while (gBattleMons[battlerId].statStages[STAT_ATK + i] == MAX_STAT_STAGE); } while (!CompareStat(battlerId, STAT_ATK + i, MAX_STAT_STAGE, CMP_LESS_THAN));
PREPARE_STAT_BUFFER(gBattleTextBuff1, i + 1); PREPARE_STAT_BUFFER(gBattleTextBuff1, i + 1);
stringId = (GetBattlerAbility(battlerId) == ABILITY_CONTRARY) ? STRINGID_STATFELL : STRINGID_STATROSE;
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
gBattleTextBuff2[1] = B_BUFF_STRING; gBattleTextBuff2[1] = B_BUFF_STRING;
gBattleTextBuff2[2] = STRINGID_STATSHARPLY; gBattleTextBuff2[2] = STRINGID_STATSHARPLY;
gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8; gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8;
gBattleTextBuff2[4] = B_BUFF_STRING; gBattleTextBuff2[4] = B_BUFF_STRING;
gBattleTextBuff2[5] = STRINGID_STATROSE; gBattleTextBuff2[5] = stringId;
gBattleTextBuff2[6] = STRINGID_STATROSE >> 8; gBattleTextBuff2[6] = stringId >> 8;
gBattleTextBuff2[7] = EOS; gBattleTextBuff2[7] = EOS;
gEffectBattler = battlerId; gEffectBattler = battlerId;
if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) if (GetBattlerAbility(battlerId) == ABILITY_RIPEN)
SET_STATCHANGER(i + 1, 4, FALSE); SET_STATCHANGER(i + 1, 4, FALSE);
else else
@ -5507,7 +5507,6 @@ static u8 RandomStatRaiseBerry(u32 battlerId, u32 itemId, bool32 end2)
gBattleScripting.animArg1 = 0x21 + i + 6; gBattleScripting.animArg1 = 0x21 + i + 6;
gBattleScripting.animArg2 = 0; gBattleScripting.animArg2 = 0;
if (end2) if (end2)
{ {
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
@ -5517,6 +5516,7 @@ static u8 RandomStatRaiseBerry(u32 battlerId, u32 itemId, bool32 end2)
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryStatRaiseRet; gBattlescriptCurrInstr = BattleScript_BerryStatRaiseRet;
} }
return ITEM_STATS_CHANGE; return ITEM_STATS_CHANGE;
} }
return 0; return 0;
@ -5546,13 +5546,11 @@ static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split)
{ {
if (IsBattlerAlive(battlerId) if (IsBattlerAlive(battlerId)
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& gBattleMons[battlerId].statStages[statId] < MAX_STAT_STAGE && CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) && !DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove)
&& GetBattleMoveSplit(gCurrentMove) == split) && GetBattleMoveSplit(gCurrentMove) == split)
{ {
BufferStatChange(battlerId, statId, STRINGID_STATROSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE);
gEffectBattler = battlerId; gEffectBattler = battlerId;
if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) if (GetBattlerAbility(battlerId) == ABILITY_RIPEN)
@ -5569,6 +5567,30 @@ static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split)
return 0; return 0;
} }
u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute)
{
if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
{
BufferStatChange(battler, statId, STRINGID_STATROSE);
gLastUsedItem = itemId; // For surge abilities
gEffectBattler = gBattleScripting.battler = battler;
SET_STATCHANGER(statId, 1, FALSE);
gBattleScripting.animArg1 = 0xE + statId;
gBattleScripting.animArg2 = 0;
if (execute)
{
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
}
else
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryStatRaiseRet;
}
return ITEM_STATS_CHANGE;
}
return 0;
}
static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal) static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal)
{ {
if (HasEnoughHpToEatBerry(battlerId, 2, itemId)) if (HasEnoughHpToEatBerry(battlerId, 2, itemId))
@ -5858,6 +5880,48 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
BattleScriptPushCursorAndCallback(BattleScript_AirBaloonMsgIn); BattleScriptPushCursorAndCallback(BattleScript_AirBaloonMsgIn);
RecordItemEffectBattle(battlerId, HOLD_EFFECT_AIR_BALLOON); RecordItemEffectBattle(battlerId, HOLD_EFFECT_AIR_BALLOON);
break; break;
case HOLD_EFFECT_ROOM_SERVICE:
if (TryRoomService(battlerId))
{
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SEEDS:
switch (GetBattlerHoldEffectParam(battlerId))
{
case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN:
effect = TryHandleSeed(battlerId, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, gLastUsedItem, TRUE);
break;
case HOLD_EFFECT_PARAM_GRASSY_TERRAIN:
effect = TryHandleSeed(battlerId, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, gLastUsedItem, TRUE);
break;
case HOLD_EFFECT_PARAM_MISTY_TERRAIN:
effect = TryHandleSeed(battlerId, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, gLastUsedItem, TRUE);
break;
case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN:
effect = TryHandleSeed(battlerId, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, gLastUsedItem, TRUE);
break;
}
break;
case HOLD_EFFECT_EJECT_PACK:
if (gSpecialStatuses[battlerId].statFell
&& !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker))) // Does not activate if attacker used Parting Shot and can switch out
{
gSpecialStatuses[battlerId].statFell = FALSE;
gActiveBattler = gBattleScripting.battler = battlerId;
effect = ITEM_STATS_CHANGE;
if (moveTurn)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_EjectPackActivate_Ret;
}
else
{
BattleScriptExecute(BattleScript_EjectPackActivate_End2);
}
}
break;
} }
if (effect) if (effect)
@ -6338,13 +6402,13 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
} }
} }
break; break;
case ITEMEFFECT_KINGSROCK_SHELLBELL: case ITEMEFFECT_KINGSROCK:
if (gBattleMoveDamage) // Occur on each hit of a multi-strike move
{
switch (atkHoldEffect) switch (atkHoldEffect)
{ {
case HOLD_EFFECT_FLINCH: case HOLD_EFFECT_FLINCH:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) if (gBattleMoveDamage != 0 // Need to have done damage
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& (Random() % 100) < atkHoldEffectParam && (Random() % 100) < atkHoldEffectParam
&& gBattleMoves[gCurrentMove].flags & FLAG_KINGS_ROCK_AFFECTED && gBattleMoves[gCurrentMove].flags & FLAG_KINGS_ROCK_AFFECTED
@ -6356,10 +6420,27 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
BattleScriptPop(); BattleScriptPop();
} }
break; break;
case HOLD_EFFECT_BLUNDER_POLICY:
if (gBattleStruct->blunderPolicy
&& gBattleMons[gBattlerAttacker].hp != 0
&& CompareStat(gBattlerAttacker, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
{
gBattleStruct->blunderPolicy = FALSE;
gLastUsedItem = atkItem;
gBattleScripting.statChanger = SET_STATCHANGER(STAT_SPEED, 2, FALSE);
effect = ITEM_STATS_CHANGE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AttackerItemStatRaise;
}
break;
}
break;
case ITEMEFFECT_LIFEORB_SHELLBELL:
// Occur after the final hit of a multi-strike move
switch (atkHoldEffect)
{
case HOLD_EFFECT_SHELL_BELL: case HOLD_EFFECT_SHELL_BELL:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) if (gSpecialStatuses[gBattlerAttacker].damagedMons // Need to have done damage
&& gSpecialStatuses[gBattlerTarget].dmg != 0
&& gSpecialStatuses[gBattlerTarget].dmg != 0xFFFF
&& gBattlerAttacker != gBattlerTarget && gBattlerAttacker != gBattlerTarget
&& gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP && gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP
&& gBattleMons[gBattlerAttacker].hp != 0) && gBattleMons[gBattlerAttacker].hp != 0)
@ -6373,10 +6454,39 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
gSpecialStatuses[gBattlerTarget].dmg = 0; gSpecialStatuses[gBattlerTarget].dmg = 0;
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret; gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret;
effect++; effect = ITEM_HP_CHANGE;
} }
break; break;
case HOLD_EFFECT_LIFE_ORB:
if (IsBattlerAlive(gBattlerAttacker)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
{
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 10;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
effect = ITEM_HP_CHANGE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ItemHurtRet;
gLastUsedItem = gBattleMons[gBattlerAttacker].item;
} }
break;
case HOLD_EFFECT_THROAT_SPRAY: // Does NOT need to be a damaging move
if (gProtectStructs[gBattlerAttacker].targetAffected
&& gBattleMons[gBattlerAttacker].hp != 0
&& gBattleMoves[gCurrentMove].flags & FLAG_SOUND
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end
{
gLastUsedItem = atkItem;
gBattleScripting.battler = gBattlerAttacker;
gBattleScripting.statChanger = SET_STATCHANGER(STAT_SPATK, 1, FALSE);
effect = ITEM_STATS_CHANGE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AttackerItemStatRaise;
}
break;
} }
break; break;
case ITEMEFFECT_TARGET: case ITEMEFFECT_TARGET:
@ -8782,14 +8892,6 @@ void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast)
} }
} }
bool32 TestSheerForceFlag(u8 battler, u16 move)
{
if (GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && gBattleMoves[move].flags & FLAG_SHEER_FORCE_BOOST)
return TRUE;
else
return FALSE;
}
void TryRestoreStolenItems(void) void TryRestoreStolenItems(void)
{ {
u32 i; u32 i;
@ -8860,3 +8962,122 @@ void TrySaveExchangedItem(u8 battlerId, u16 stolenItem)
#endif #endif
} }
bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes)
{
bool32 ret = TRUE;
u32 holdEffect = GetBattlerHoldEffect(gActiveBattler, TRUE);
if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON))
{
ret = FALSE;
RecordItemEffectBattle(battlerId, holdEffect);
}
else if (holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS)
{
ret = FALSE;
RecordItemEffectBattle(battlerId, holdEffect);
}
return ret;
}
bool32 TestSheerForceFlag(u8 battler, u16 move)
{
if (GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && gBattleMoves[move].flags & FLAG_SHEER_FORCE_BOOST)
return TRUE;
else
return FALSE;
}
// This function is the body of "jumpifstat", but can be used dynamically in a function
bool32 CompareStat(u8 battlerId, u8 statId, u8 cmpTo, u8 cmpKind)
{
bool8 ret = FALSE;
u8 statValue = gBattleMons[battlerId].statStages[statId];
// Because this command is used as a way of checking if a stat can be lowered/raised,
// we need to do some modification at run-time.
if (GetBattlerAbility(battlerId) == ABILITY_CONTRARY)
{
if (cmpKind == CMP_GREATER_THAN)
cmpKind = CMP_LESS_THAN;
else if (cmpKind == CMP_LESS_THAN)
cmpKind = CMP_GREATER_THAN;
if (cmpTo == MIN_STAT_STAGE)
cmpTo = MAX_STAT_STAGE;
else if (cmpTo == MAX_STAT_STAGE)
cmpTo = MIN_STAT_STAGE;
}
switch (cmpKind)
{
case CMP_EQUAL:
if (statValue == cmpTo)
ret = TRUE;
break;
case CMP_NOT_EQUAL:
if (statValue != cmpTo)
ret = TRUE;
break;
case CMP_GREATER_THAN:
if (statValue > cmpTo)
ret = TRUE;
break;
case CMP_LESS_THAN:
if (statValue < cmpTo)
ret = TRUE;
break;
case CMP_COMMON_BITS:
if (statValue & cmpTo)
ret = TRUE;
break;
case CMP_NO_COMMON_BITS:
if (!(statValue & cmpTo))
ret = TRUE;
break;
}
return ret;
}
void BufferStatChange(u8 battlerId, u8 statId, u8 stringId)
{
bool8 hasContrary = (GetBattlerAbility(battlerId) == ABILITY_CONTRARY);
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
if (stringId == STRINGID_STATFELL)
{
if (hasContrary)
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE)
else
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL)
}
else if (stringId == STRINGID_STATROSE)
{
if (hasContrary)
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL)
else
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE)
}
else
{
PREPARE_STRING_BUFFER(gBattleTextBuff2, stringId)
}
}
bool32 TryRoomService(u8 battlerId)
{
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battlerId, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN))
{
BufferStatChange(battlerId, STAT_SPEED, STRINGID_STATFELL);
gEffectBattler = gBattleScripting.battler = battlerId;
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
gBattleScripting.animArg1 = 0xE + STAT_SPEED;
gBattleScripting.animArg2 = 0;
gLastUsedItem = gBattleMons[battlerId].item;
return TRUE;
}
else
{
return FALSE;
}
}