mirror of
https://github.com/pret/pokefirered.git
synced 2026-09-13 11:55:28 -05:00
updated battle engine to 0bb43626afe2cdc6f9bdd7c246e2dca7198ddab3
This commit is contained in:
@@ -1670,6 +1670,10 @@
|
||||
callnative BS_DamageToQuarterTargetHP
|
||||
.endm
|
||||
|
||||
.macro ficklebeamdamagecalculation
|
||||
callnative BS_FickleBeamDamageCalculation
|
||||
.endm
|
||||
|
||||
@ various command changed to more readable macros
|
||||
.macro cancelmultiturnmoves battler:req
|
||||
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES
|
||||
@@ -2519,5 +2523,3 @@
|
||||
printstring STRINGID_EMPTYSTRING3
|
||||
waitmessage 1
|
||||
.endm
|
||||
|
||||
|
||||
|
||||
@@ -22,62 +22,6 @@
|
||||
.section script_data, "aw", %progbits
|
||||
.align 2
|
||||
|
||||
BattleScript_LocalTrainerBattleWon::
|
||||
jumpifbattletype BATTLE_TYPE_TWO_OPPONENTS, BattleScript_LocalTwoTrainersDefeated
|
||||
printstring STRINGID_PLAYERDEFEATEDTRAINER1
|
||||
goto BattleScript_LocalBattleWonLoseTexts
|
||||
BattleScript_LocalTwoTrainersDefeated::
|
||||
printstring STRINGID_TWOENEMIESDEFEATED
|
||||
BattleScript_LocalBattleWonLoseTexts::
|
||||
trainerslidein BS_ATTACKER
|
||||
waitstate
|
||||
printstring STRINGID_TRAINER1LOSETEXT
|
||||
jumpifnotbattletype BATTLE_TYPE_TWO_OPPONENTS, BattleScript_LocalTrainerBattleWonGotMoney
|
||||
trainerslideout B_POSITION_OPPONENT_LEFT
|
||||
waitstate
|
||||
trainerslidein BS_FAINTED
|
||||
waitstate
|
||||
printstring STRINGID_TRAINER2LOSETEXT
|
||||
BattleScript_LocalTrainerBattleWonGotMoney::
|
||||
getmoneyreward
|
||||
printstring STRINGID_PLAYERGOTMONEY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_PayDayMoneyAndPickUpItems::
|
||||
givepaydaymoney
|
||||
pickup
|
||||
end2
|
||||
|
||||
BattleScript_LocalBattleLost::
|
||||
jumpifbattletype BATTLE_TYPE_INGAME_PARTNER, BattleScript_LocalBattleLostPrintWhiteOut
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER_TOWER, BattleScript_BattleTowerLost
|
||||
jumpifbattletype BATTLE_TYPE_EREADER_TRAINER, BattleScript_LocalBattleLostEnd
|
||||
jumpifhalfword CMP_EQUAL, gTrainerBattleOpponent_A, TRAINER_SECRET_BASE, BattleScript_LocalBattleLostEnd
|
||||
jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, 0, BattleScript_RivalBattleLost
|
||||
BattleScript_LocalBattleLostPrintWhiteOut::
|
||||
.if B_WHITEOUT_MONEY >= GEN_4
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_LocalBattleLostEnd
|
||||
printstring STRINGID_PLAYERWHITEOUT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
getmoneyreward
|
||||
printstring STRINGID_PLAYERWHITEOUT2
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
BattleScript_LocalBattleLostEnd::
|
||||
printstring STRINGID_PLAYERLOSTAGAINSTENEMYTRAINER
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
getmoneyreward
|
||||
printstring STRINGID_PLAYERPAIDPRIZEMONEY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
.else
|
||||
printstring STRINGID_PLAYERWHITEOUT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
printstring STRINGID_PLAYERWHITEOUT2
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_LocalBattleLostEnd::
|
||||
end2
|
||||
.endif
|
||||
|
||||
BattleScript_RivalBattleLost::
|
||||
jumpifhasnohp BS_ATTACKER, BattleScript_RivalBattleLostSkipMonRecall
|
||||
printstring STRINGID_TRAINER1MON1COMEBACK
|
||||
@@ -128,11 +72,6 @@ BattleScript_BattleTowerEtcTrainerBattleWonSkipText::
|
||||
pickup
|
||||
end2
|
||||
|
||||
BattleScript_PrintCantRunFromTrainer::
|
||||
jumpifbattletype BATTLE_TYPE_FIRST_BATTLE, BattleScript_LeftoverBirchString
|
||||
printstring STRINGID_NORUNNINGFROMTRAINERS
|
||||
end2
|
||||
|
||||
BattleScript_LeftoverBirchString::
|
||||
printstring STRINGID_DONTLEAVEBIRCH
|
||||
end2
|
||||
@@ -170,6 +109,19 @@ BattleScript_DamageToQuarterTargetHP::
|
||||
damagetoquartertargethp
|
||||
goto BattleScript_HitFromAtkAnimation
|
||||
|
||||
BattleScript_EffectFickleBeam::
|
||||
attackcanceler
|
||||
attackstring
|
||||
ppreduce
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
ficklebeamdamagecalculation
|
||||
goto BattleScript_HitFromCritCalc
|
||||
BattleScript_FickleBeamDoubled::
|
||||
pause B_WAIT_TIME_SHORTEST
|
||||
printstring STRINGID_FICKLEBEAMDOUBLED
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_HitFromCritCalc
|
||||
|
||||
BattleScript_Terastallization::
|
||||
@ TODO: no string prints in S/V, but right now this helps with clarity
|
||||
printstring STRINGID_PKMNSTORINGENERGY
|
||||
@@ -283,6 +235,7 @@ BattleScript_EffectShedTail::
|
||||
ppreduce
|
||||
waitstate
|
||||
jumpifstatus2 BS_ATTACKER, STATUS2_SUBSTITUTE, BattleScript_AlreadyHasSubstitute
|
||||
jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed
|
||||
jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed
|
||||
setsubstitute
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SUBSTITUTE_FAILED, BattleScript_SubstituteString
|
||||
@@ -415,6 +368,7 @@ BattleScript_EffectChillyReceptionBlockedByStrongWinds:
|
||||
call BattleScript_MysteriousAirCurrentBlowsOnRet
|
||||
goto BattleScript_MoveSwitch
|
||||
BattleScript_EffectChillyReceptionTrySwitchWeatherFailed:
|
||||
jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_FailedFromAtkString
|
||||
jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_FailedFromAtkString
|
||||
call BattleScript_EffectChillyReceptionPlayAnimation
|
||||
return
|
||||
@@ -426,6 +380,7 @@ BattleScript_CheckPrimalWeather:
|
||||
return
|
||||
|
||||
BattleScript_MoveSwitch:
|
||||
jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_MoveSwitchEnd
|
||||
jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_MoveSwitchEnd
|
||||
printstring STRINGID_PKMNWENTBACK
|
||||
waitmessage B_WAIT_TIME_SHORT
|
||||
@@ -702,7 +657,7 @@ BattleScript_Teatimerod:
|
||||
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_TeatimeBuffer
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_TeatimeBuffer
|
||||
printfromtable gStatUpStringIds
|
||||
waitmessage 0x40
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
moveendto MOVEEND_NEXT_TARGET
|
||||
jumpifnexttargetvalid BattleScript_TeatimeLoop
|
||||
moveendcase MOVEEND_CLEAR_BITS
|
||||
@@ -714,7 +669,7 @@ BattleScript_Teatimemotor:
|
||||
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_TeatimeBuffer
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_TeatimeBuffer
|
||||
printfromtable gStatUpStringIds
|
||||
waitmessage 0x40
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
moveendto MOVEEND_NEXT_TARGET
|
||||
jumpifnexttargetvalid BattleScript_TeatimeLoop
|
||||
moveendcase MOVEEND_CLEAR_BITS
|
||||
@@ -1002,6 +957,7 @@ BattleScript_OctlockTurnDmgEnd:
|
||||
|
||||
BattleScript_EffectPoltergeist::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||
attackstring
|
||||
ppreduce
|
||||
checkpoltergeist BS_TARGET, BattleScript_ButItFailed
|
||||
@@ -1051,19 +1007,10 @@ BattleScript_BothCanNoLongerEscape::
|
||||
return
|
||||
|
||||
BattleScript_EffectHyperspaceFury::
|
||||
jumpifspecies BS_ATTACKER, SPECIES_HOOPA_UNBOUND, BattleScript_EffectHyperspaceFuryUnbound
|
||||
jumpifspecies BS_ATTACKER, SPECIES_HOOPA_UNBOUND, BattleScript_EffectHit
|
||||
jumpifspecies BS_ATTACKER, SPECIES_HOOPA_CONFINED, BattleScript_ButHoopaCantUseIt
|
||||
goto BattleScript_PokemonCantUseTheMove
|
||||
|
||||
BattleScript_EffectHyperspaceFuryUnbound::
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||
attackstring
|
||||
pause B_WAIT_TIME_LONG
|
||||
ppreduce
|
||||
seteffectprimary MOVE_EFFECT_FEINT
|
||||
goto BattleScript_HitFromCritCalc
|
||||
|
||||
BattleScript_ButHoopaCantUseIt:
|
||||
printstring STRINGID_BUTHOOPACANTUSEIT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
@@ -3401,6 +3348,7 @@ BattleScript_EffectRoar::
|
||||
jumpiftargetdynamaxed BattleScript_RoarBlockedByDynamax
|
||||
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
|
||||
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
|
||||
jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed
|
||||
forcerandomswitch BattleScript_ButItFailed
|
||||
|
||||
BattleScript_RoarBlockedByDynamax:
|
||||
@@ -4553,6 +4501,7 @@ BattleScript_EffectBatonPass::
|
||||
attackcanceler
|
||||
attackstring
|
||||
ppreduce
|
||||
jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed
|
||||
jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed
|
||||
attackanimation
|
||||
waitanimation
|
||||
@@ -5724,6 +5673,62 @@ BattleScript_HandleFaintedMonMultipleEnd::
|
||||
switchineffects BS_FAINTED_MULTIPLE_2
|
||||
end2
|
||||
|
||||
BattleScript_LocalTrainerBattleWon::
|
||||
jumpifbattletype BATTLE_TYPE_TWO_OPPONENTS, BattleScript_LocalTwoTrainersDefeated
|
||||
printstring STRINGID_PLAYERDEFEATEDTRAINER1
|
||||
goto BattleScript_LocalBattleWonLoseTexts
|
||||
BattleScript_LocalTwoTrainersDefeated::
|
||||
printstring STRINGID_TWOENEMIESDEFEATED
|
||||
BattleScript_LocalBattleWonLoseTexts::
|
||||
trainerslidein BS_ATTACKER
|
||||
waitstate
|
||||
printstring STRINGID_TRAINER1LOSETEXT
|
||||
jumpifnotbattletype BATTLE_TYPE_TWO_OPPONENTS, BattleScript_LocalBattleWonReward
|
||||
trainerslideout B_POSITION_OPPONENT_LEFT
|
||||
waitstate
|
||||
trainerslidein BS_FAINTED
|
||||
waitstate
|
||||
printstring STRINGID_TRAINER2LOSETEXT
|
||||
BattleScript_LocalBattleWonReward::
|
||||
getmoneyreward
|
||||
printstring STRINGID_PLAYERGOTMONEY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_PayDayMoneyAndPickUpItems::
|
||||
givepaydaymoney
|
||||
pickup
|
||||
end2
|
||||
|
||||
BattleScript_LocalBattleLost::
|
||||
jumpifbattletype BATTLE_TYPE_INGAME_PARTNER, BattleScript_LocalBattleLostPrintWhiteOut
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER_TOWER, BattleScript_BattleTowerLost
|
||||
jumpifbattletype BATTLE_TYPE_EREADER_TRAINER, BattleScript_LocalBattleLostEnd
|
||||
jumpifhalfword CMP_EQUAL, gTrainerBattleOpponent_A, TRAINER_SECRET_BASE, BattleScript_LocalBattleLostEnd
|
||||
jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, 0, BattleScript_RivalBattleLost
|
||||
BattleScript_LocalBattleLostPrintWhiteOut::
|
||||
.if B_WHITEOUT_MONEY >= GEN_4
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_LocalBattleLostEnd
|
||||
printstring STRINGID_PLAYERWHITEOUT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
getmoneyreward
|
||||
printstring STRINGID_PLAYERWHITEOUT2
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
BattleScript_LocalBattleLostEnd::
|
||||
printstring STRINGID_PLAYERLOSTAGAINSTENEMYTRAINER
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
getmoneyreward
|
||||
printstring STRINGID_PLAYERPAIDPRIZEMONEY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
.else
|
||||
printstring STRINGID_PLAYERWHITEOUT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
printstring STRINGID_PLAYERWHITEOUT2
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_LocalBattleLostEnd::
|
||||
end2
|
||||
.endif
|
||||
|
||||
BattleScript_SmokeBallEscape::
|
||||
playanimation BS_ATTACKER, B_ANIM_SMOKEBALL_ESCAPE
|
||||
printstring STRINGID_PKMNFLEDUSINGITS
|
||||
@@ -5745,6 +5750,10 @@ BattleScript_WildMonFled::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
|
||||
BattleScript_PrintCantRunFromTrainer::
|
||||
printstring STRINGID_NORUNNINGFROMTRAINERS
|
||||
end2
|
||||
|
||||
BattleScript_PrintFailedToRunString::
|
||||
printfromtable gNoEscapeStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
@@ -7118,7 +7127,7 @@ BattleScript_TargetFormChangeWithStringNoPopup::
|
||||
|
||||
BattleScript_BattlerFormChangeWithStringEnd3::
|
||||
pause 5
|
||||
call BattleScript_AbilityPopUp
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
flushtextbox
|
||||
handleformchange BS_SCRIPTING, 0
|
||||
handleformchange BS_SCRIPTING, 1
|
||||
@@ -7722,6 +7731,15 @@ BattleScript_CheekPouchActivates::
|
||||
copybyte gBattlerAttacker, sSAVED_BATTLER
|
||||
return
|
||||
|
||||
BattleScript_PickupActivates::
|
||||
pause 5
|
||||
tryrecycleitem BattleScript_PickupActivatesEnd
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_XFOUNDONEY
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_PickupActivatesEnd:
|
||||
end3
|
||||
|
||||
BattleScript_HarvestActivates::
|
||||
pause 5
|
||||
tryrecycleitem BattleScript_HarvestActivatesEnd
|
||||
@@ -7969,7 +7987,7 @@ BattleScript_DeltaStreamActivates::
|
||||
end3
|
||||
|
||||
BattleScript_ProtosynthesisActivates::
|
||||
call BattleScript_AbilityPopUp
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
printstring STRINGID_SUNLIGHTACTIVATEDABILITY
|
||||
waitmessage B_WAIT_TIME_MED
|
||||
printstring STRINGID_STATWASHEIGHTENED
|
||||
|
||||
@@ -574,12 +574,10 @@ struct LostItem
|
||||
u16 stolen:1;
|
||||
};
|
||||
|
||||
#if HQ_RANDOM == TRUE
|
||||
struct BattleVideo {
|
||||
u32 battleTypeFlags;
|
||||
rng_value_t rngSeed;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct BattleStruct
|
||||
{
|
||||
@@ -645,17 +643,13 @@ struct BattleStruct
|
||||
u16 chosenItem[MAX_BATTLERS_COUNT];
|
||||
u16 choicedMove[MAX_BATTLERS_COUNT];
|
||||
u16 changedItems[MAX_BATTLERS_COUNT];
|
||||
u8 canPickupItem;
|
||||
u8 switchInBattlerCounter;
|
||||
u8 turnSideTracker;
|
||||
u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker]
|
||||
union {
|
||||
struct LinkBattlerHeader linkBattlerHeader;
|
||||
|
||||
#if HQ_RANDOM == FALSE
|
||||
u32 battleVideo[2];
|
||||
#else
|
||||
struct BattleVideo battleVideo;
|
||||
#endif
|
||||
} multiBuffer;
|
||||
u8 wishPerishSongState;
|
||||
u8 wishPerishSongBattlerId;
|
||||
@@ -724,7 +718,6 @@ struct BattleStruct
|
||||
bool8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects.
|
||||
u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit.
|
||||
u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching)
|
||||
bool8 allowedToChangeFormInWeather[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side, used by Ice Face.
|
||||
u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party.
|
||||
u8 storedHealingWish:4; // Each battler as a bit.
|
||||
u8 storedLunarDance:4; // Each battler as a bit.
|
||||
@@ -761,6 +754,7 @@ struct BattleStruct
|
||||
u8 distortedTypeMatchups;
|
||||
u8 categoryOverride; // for Z-Moves and Max Moves
|
||||
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
|
||||
u8 fickleBeamBoosted:1;
|
||||
|
||||
// pokefirered
|
||||
u8 field_DA; // battle tower related
|
||||
|
||||
@@ -31,8 +31,8 @@ bool32 NoAliveMonsForPlayer(void);
|
||||
bool32 NoAliveMonsForEitherParty(void);
|
||||
void SetMoveEffect(bool32 primary, bool32 certain);
|
||||
bool32 CanBattlerSwitch(u32 battlerId);
|
||||
void BattleDestroyYesNoCursorAt(void);
|
||||
void BattleCreateYesNoCursorAt(void);
|
||||
void BattleDestroyYesNoCursorAt(u8 cursorPosition);
|
||||
void BattleCreateYesNoCursorAt(u8 cursorPosition);
|
||||
void BufferMoveToLearnIntoBattleTextBuff2(void);
|
||||
void HandleBattleWindow(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags);
|
||||
bool8 UproarWakeUpCheck(u8 battlerId);
|
||||
|
||||
@@ -737,6 +737,7 @@ extern const u8 BattleScript_WeakArmorActivates[];
|
||||
extern const u8 BattleScript_FellStingerRaisesStat[];
|
||||
extern const u8 BattleScript_SnowWarningActivatesHail[];
|
||||
extern const u8 BattleScript_SnowWarningActivatesSnow[];
|
||||
extern const u8 BattleScript_PickupActivates[];
|
||||
extern const u8 BattleScript_HarvestActivates[];
|
||||
extern const u8 BattleScript_ImposterActivates[];
|
||||
extern const u8 BattleScript_SelectingNotAllowedMoveAssaultVest[];
|
||||
@@ -1274,6 +1275,8 @@ extern const u8 BattleScript_EffectUpperHand[];
|
||||
extern const u8 BattleScript_EffectTidyUp[];
|
||||
extern const u8 BattleScript_EffectSpicyExtract[];
|
||||
extern const u8 BattleScript_DamageToQuarterTargetHP[];
|
||||
extern const u8 BattleScript_EffectFickleBeam[];
|
||||
extern const u8 BattleScript_FickleBeamDoubled[];
|
||||
|
||||
|
||||
#endif // GUARD_BATTLE_SCRIPTS_H
|
||||
|
||||
@@ -232,6 +232,8 @@ bool32 TryRoomService(u32 battler);
|
||||
void BufferStatChange(u32 battler, u8 statId, u8 stringId);
|
||||
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget);
|
||||
u16 GetUsedHeldItem(u32 battler);
|
||||
bool32 PickupHasValidTarget(u32 battler);
|
||||
bool32 CantPickupItem(u32 battler);
|
||||
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags);
|
||||
u32 GetBattlerMoveTargetType(u32 battler, u32 move);
|
||||
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move);
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
#define B_BURN_HIT_THAW GEN_LATEST // In Gen6+, damaging moves with a chance of burn will thaw the target, regardless if they're fire-type moves or not.
|
||||
#define B_HEALING_WISH_SWITCH GEN_LATEST // In Gen5+, the mon receiving Healing Wish is sent out at the end of the turn.
|
||||
// Additionally, in gen8+ the Healing Wish's effect will be stored until the user switches into a statused or hurt mon.
|
||||
#define B_DEFOG_CLEARS_TERRAIN GEN_LATEST // In Gen8+, Defog also clears active Terrain.
|
||||
#define B_DEFOG_EFFECT_CLEARING GEN_LATEST // In Gen6+, Defog clears Spikes, Toxic Spikes, Stealth Rock and Sticky Web from both sides. In Gen8+, Defog also clears active Terrain.
|
||||
#define B_STOCKPILE_RAISES_DEFS GEN_LATEST // In Gen4+, Stockpile also raises Defense and Sp. Defense stats. Once Spit Up / Swallow is used, these stat changes are lost.
|
||||
#define B_TRANSFORM_SHINY GEN_LATEST // In Gen4+, Transform will copy the shiny state of the opponent instead of maintaining its own shiny state.
|
||||
#define B_TRANSFORM_FORM_CHANGES GEN_LATEST // In Gen5+, Transformed Pokemon cannot change forms.
|
||||
@@ -219,7 +219,7 @@
|
||||
#define B_FAST_HP_DRAIN TRUE // If set to TRUE, HP bars will move faster.
|
||||
#define B_FAST_EXP_GROW TRUE // If set to TRUE, EXP bars will move faster.
|
||||
#define B_SHOW_TARGETS TRUE // If set to TRUE, all available targets, for moves hitting 2 or 3 Pokémon, will be shown before selecting a move.
|
||||
#define B_SHOW_CATEGORY_ICON TRUE // If set to TRUE, it will show an icon in the summary showing the move's category.
|
||||
#define B_SHOW_CATEGORY_ICON TRUE // If set to TRUE, it will show an icon in the summary and move relearner showing the move's category.
|
||||
#define B_HIDE_HEALTHBOX_IN_ANIMS TRUE // If set to TRUE, hides healthboxes during move animations.
|
||||
#define B_EXPANDED_MOVE_NAMES TRUE // If set to FALSE, move names are decreased from 16 characters to 12 characters.
|
||||
#define B_WAIT_TIME_MULTIPLIER 16 // This determines how long text pauses in battle last. Vanilla is 16. Lower values result in faster battles.
|
||||
@@ -251,26 +251,31 @@
|
||||
#define B_TRY_CATCH_TRAINER_BALL GEN_LATEST // In Gen4+, trying to catch a Trainer's Pokémon does not consume the Poké Ball.
|
||||
|
||||
// Animation Settings
|
||||
#define B_NEW_SWORD_PARTICLE TRUE // If set to TRUE, it updates Swords Dance's particle.
|
||||
#define B_NEW_LEECH_SEED_PARTICLE TRUE // If set to TRUE, it updates Leech Seed's animation particle.
|
||||
#define B_NEW_HORN_ATTACK_PARTICLE TRUE // If set to TRUE, it updates Horn Attack's horn particle.
|
||||
#define B_NEW_ROCKS_PARTICLE TRUE // If set to TRUE, it updates rock particles.
|
||||
#define B_NEW_LEAF_PARTICLE TRUE // If set to TRUE, it updates leaf particle.
|
||||
#define B_NEW_EMBER_PARTICLES TRUE // If set to TRUE, it updates Ember's fire particle.
|
||||
#define B_NEW_MEAN_LOOK_PARTICLE TRUE // If set to TRUE, it updates Mean Look's eye particle.
|
||||
#define B_NEW_TEETH_PARTICLE TRUE // If set to TRUE, it updates Bite/Crunch teeth particle.
|
||||
#define B_NEW_HANDS_FEET_PARTICLE TRUE // If set to TRUE, it updates chop/kick/punch particles.
|
||||
#define B_NEW_SPIKES_PARTICLE TRUE // If set to TRUE, it updates Spikes particle.
|
||||
#define B_NEW_FLY_BUBBLE_PARTICLE TRUE // If set to TRUE, it updates Fly's 'bubble' particle.
|
||||
#define B_NEW_CURSE_NAIL_PARTICLE TRUE // If set to TRUE, it updates Curse's nail.
|
||||
#define B_NEW_BATON_PASS_BALL_PARTICLE TRUE // If set to TRUE, it updates Baton Pass' Poké Ball sprite.
|
||||
#define B_NEW_MORNING_SUN_STAR_PARTICLE TRUE // If set to TRUE, it updates Morning Sun's star particles.
|
||||
#define B_NEW_IMPACT_PALETTE TRUE // If set to TRUE, it updates the basic 'hit' palette.
|
||||
#define B_NEW_SURF_PARTICLE_PALETTE TRUE // If set to TRUE, it updates Surf's wave palette.
|
||||
#define B_NEW_SWORD_PARTICLE FALSE // If set to TRUE, it updates Swords Dance's particle.
|
||||
#define B_NEW_LEECH_SEED_PARTICLE FALSE // If set to TRUE, it updates Leech Seed's animation particle.
|
||||
#define B_NEW_HORN_ATTACK_PARTICLE FALSE // If set to TRUE, it updates Horn Attack's horn particle.
|
||||
#define B_NEW_ROCKS_PARTICLE FALSE // If set to TRUE, it updates rock particles.
|
||||
#define B_NEW_LEAF_PARTICLE FALSE // If set to TRUE, it updates leaf particle.
|
||||
#define B_NEW_EMBER_PARTICLES FALSE // If set to TRUE, it updates Ember's fire particle.
|
||||
#define B_NEW_MEAN_LOOK_PARTICLE FALSE // If set to TRUE, it updates Mean Look's eye particle.
|
||||
#define B_NEW_TEETH_PARTICLE FALSE // If set to TRUE, it updates Bite/Crunch teeth particle.
|
||||
#define B_NEW_HANDS_FEET_PARTICLE FALSE // If set to TRUE, it updates chop/kick/punch particles.
|
||||
#define B_NEW_SPIKES_PARTICLE FALSE // If set to TRUE, it updates Spikes particle.
|
||||
#define B_NEW_FLY_BUBBLE_PARTICLE FALSE // If set to TRUE, it updates Fly's 'bubble' particle.
|
||||
#define B_NEW_CURSE_NAIL_PARTICLE FALSE // If set to TRUE, it updates Curse's nail.
|
||||
#define B_NEW_BATON_PASS_BALL_PARTICLE FALSE // If set to TRUE, it updates Baton Pass' Poké Ball sprite.
|
||||
#define B_NEW_MORNING_SUN_STAR_PARTICLE FALSE // If set to TRUE, it updates Morning Sun's star particles.
|
||||
#define B_NEW_IMPACT_PALETTE FALSE // If set to TRUE, it updates the basic 'hit' palette.
|
||||
#define B_NEW_SURF_PARTICLE_PALETTE FALSE // If set to TRUE, it updates Surf's wave palette.
|
||||
|
||||
// Poké Ball animation and sounds
|
||||
#define B_ENEMY_THROW_BALLS GEN_LATEST // In GEN_6+, enemy Trainers throw Poké Balls into battle instead of them just appearing on the ground and opening.
|
||||
#define B_ENEMY_THROW_BALLS_SOUND GEN_LATEST // In GEN_5+, enemy Trainer's Poké Balls make a sound when thrown to send out a Pokémon. This can only be used when B_ENEMY_THROW_BALLS is set to GEN_6 or later.
|
||||
#define B_PLAYER_THROW_BALLS_SOUND GEN_LATEST // In GEN_5+, the player's Poké Balls make a sound when thrown to send out a Pokémon.
|
||||
|
||||
#define SHOW_TYPES_NEVER 0
|
||||
#define SHOW_TYPES_ALWAYS 1
|
||||
#define SHOW_TYPES_CAUGHT 2
|
||||
#define B_SHOW_TYPES SHOW_TYPES_NEVER // When defined as SHOW_TYPES_ALWAYS, after selecting "Fight" in battle, the types of all Pokemon are revealed. Whe defined as SHOW_TYPES_OWN, types are only revealed if the player owns the mon in question.
|
||||
|
||||
#endif // GUARD_CONFIG_BATTLE_H
|
||||
|
||||
@@ -1336,8 +1336,9 @@
|
||||
#define STRINGID_FOGISDEEP 737
|
||||
#define STRINGID_FOGLIFTED 738
|
||||
#define STRINGID_PKMNMADESHELLGLEAM 739
|
||||
#define STRINGID_FICKLEBEAMDOUBLED 740
|
||||
|
||||
#define BATTLESTRINGS_COUNT 740
|
||||
#define BATTLESTRINGS_COUNT 741
|
||||
|
||||
// This is the string id that gBattleStringsTable starts with.
|
||||
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
|
||||
|
||||
@@ -7,25 +7,21 @@
|
||||
#define ISO_RANDOMIZE1(val)(RAND_MULT * (val) + 24691)
|
||||
#define ISO_RANDOMIZE2(val)(RAND_MULT * (val) + 12345)
|
||||
|
||||
/* Some functions have been added to support HQ_RANDOM.
|
||||
/* Some functions have been added to support Expansion's RNG implementation.
|
||||
*
|
||||
* If using HQ_RANDOM, you cannot call Random() in interrupt handlers safely.
|
||||
* AdvanceRandom() is provided to handle burning numbers in the VBlank handler
|
||||
* if you choose to do that, and can be used regardless of HQ_RANDOM setting.
|
||||
* LocalRandom(*val) provides a higher-quality replacement for uses of
|
||||
* ISO_RANDOMIZE in vanilla Emerald. You can use LocalRandomSeed(u32) to
|
||||
* create a local state.
|
||||
*
|
||||
* It is no longer possible to call Random() in interrupt handlers safely.
|
||||
* AdvanceRandom() is provided to handle burning numbers in VBlank handlers.
|
||||
* If you need to use random numbers in the VBlank handler, a local state
|
||||
* should be used instead.
|
||||
*
|
||||
* LocalRandom(*val) allows you to have local random states that are the same
|
||||
* type as the global states regardless of HQ_RANDOM setting, which is useful
|
||||
* if you want to be able to set them from or assign them to gRngValue.
|
||||
* LocalRandomSeed(u32) returns a properly seeded rng_value_t.
|
||||
*
|
||||
* Random2_32() was added to HQ_RANDOM because the output of the generator is
|
||||
* always 32 bits and Random()/Random2() are just wrappers in that mode. It is
|
||||
* also available in non-HQ mode for consistency.
|
||||
* Random2_32() was added, even though it is not used directly, because the
|
||||
* underlying RNG always outputs 32 bits.
|
||||
*/
|
||||
|
||||
#if HQ_RANDOM == TRUE
|
||||
struct Sfc32State {
|
||||
u32 a;
|
||||
u32 b;
|
||||
@@ -71,40 +67,6 @@ static inline u16 Random2(void)
|
||||
}
|
||||
|
||||
void AdvanceRandom(void);
|
||||
#else
|
||||
typedef u32 rng_value_t;
|
||||
|
||||
#define RNG_VALUE_EMPTY 0
|
||||
|
||||
//Returns a 16-bit pseudorandom number
|
||||
u16 Random(void);
|
||||
u16 Random2(void);
|
||||
|
||||
//Sets the initial seed value of the pseudorandom number generator
|
||||
void SeedRng(u16 seed);
|
||||
void SeedRng2(u16 seed);
|
||||
|
||||
//Returns a 32-bit pseudorandom number
|
||||
#define Random32() (Random() | (Random() << 16))
|
||||
#define Random2_32() (Random2() | (Random2() << 16))
|
||||
|
||||
static inline u16 LocalRandom(rng_value_t *val)
|
||||
{
|
||||
*val = ISO_RANDOMIZE1(*val);
|
||||
return *val >> 16;
|
||||
}
|
||||
|
||||
static inline void AdvanceRandom(void)
|
||||
{
|
||||
Random();
|
||||
}
|
||||
|
||||
static inline rng_value_t LocalRandomSeed(u32 seed)
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern rng_value_t gRngValue;
|
||||
extern rng_value_t gRng2Value;
|
||||
@@ -174,12 +136,14 @@ enum RandomTag
|
||||
RNG_G_MAX_BEFUDDLE,
|
||||
RNG_G_MAX_REPLENISH,
|
||||
RNG_G_MAX_SNOOZE,
|
||||
RNG_HARVEST,
|
||||
RNG_HITS,
|
||||
RNG_HOLD_EFFECT_FLINCH,
|
||||
RNG_INFATUATION,
|
||||
RNG_LOADED_DICE,
|
||||
RNG_METRONOME,
|
||||
RNG_PARALYSIS,
|
||||
RNG_PICKUP,
|
||||
RNG_POISON_POINT,
|
||||
RNG_POISON_TOUCH,
|
||||
RNG_RAMPAGE_TURNS,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "battle_ai_util.h"
|
||||
#include "battle_ai_main.h"
|
||||
#include "battle_controllers.h"
|
||||
// #include "battle_factory.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_z_move.h"
|
||||
#include "battle_terastal.h"
|
||||
@@ -107,7 +108,7 @@ void BattleAI_SetupItems(void)
|
||||
// Items are allowed to use in ONLY trainer battles.
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
||||
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_BATTLE_TOWER
|
||||
| BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED_LINK)
|
||||
)
|
||||
)
|
||||
@@ -167,13 +168,13 @@ static u32 GetAiFlags(u16 trainerId)
|
||||
flags = AI_FLAG_CHECK_BAD_MOVE;
|
||||
// else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
|
||||
// flags = AI_FLAG_FIRST_BATTLE;
|
||||
else if (gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_TOWER))
|
||||
else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE))
|
||||
flags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT;
|
||||
else
|
||||
flags = GetTrainerAIFlagsFromId(trainerId);
|
||||
}
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
flags |= AI_FLAG_DOUBLE_BATTLE;
|
||||
}
|
||||
@@ -223,7 +224,7 @@ void BattleAI_SetupFlags(void)
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE));
|
||||
}
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsAiVsAiBattle())
|
||||
else if (IsDoubleBattle() && IsAiVsAiBattle())
|
||||
{
|
||||
AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT];
|
||||
}
|
||||
@@ -261,7 +262,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
// Ignore moves that aren't possible to use.
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (gBitTable[i] & moveLimitations)
|
||||
if ((1u << i) & moveLimitations)
|
||||
SET_SCORE(battler, i, 0);
|
||||
}
|
||||
|
||||
@@ -274,7 +275,7 @@ u32 BattleAI_ChooseMoveOrAction(void)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||
if (!IsDoubleBattle())
|
||||
ret = ChooseMoveOrAction_Singles(sBattler_AI);
|
||||
else
|
||||
ret = ChooseMoveOrAction_Doubles(sBattler_AI);
|
||||
@@ -322,7 +323,7 @@ void Ai_InitPartyStruct(void)
|
||||
|
||||
// Save first 2 or 4(in doubles) mons
|
||||
CopyBattlerDataToAIParty(B_POSITION_PLAYER_LEFT, B_SIDE_PLAYER);
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
CopyBattlerDataToAIParty(B_POSITION_PLAYER_RIGHT, B_SIDE_PLAYER);
|
||||
|
||||
// If player's partner is AI, save opponent mons
|
||||
@@ -445,7 +446,7 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3
|
||||
if (move != 0
|
||||
&& move != 0xFFFF
|
||||
//&& gMovesInfo[move].power != 0 /* we want to get effectiveness and accuracy of status moves */
|
||||
&& !(aiData->moveLimitations[battlerAtk] & gBitTable[i]))
|
||||
&& !(aiData->moveLimitations[battlerAtk] & (1u << i)))
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_HIGHEST);
|
||||
@@ -505,12 +506,12 @@ static bool32 AI_SwitchMonIfSuitable(u32 battler, bool32 doubleBattle)
|
||||
if (doubleBattle)
|
||||
{
|
||||
u32 partner = BATTLE_PARTNER(battler);
|
||||
if (AI_DATA->shouldSwitchMon & gBitTable[partner] && AI_DATA->monToSwitchId[partner] == monToSwitchId)
|
||||
if (AI_DATA->shouldSwitchMon & (1u << partner) && AI_DATA->monToSwitchId[partner] == monToSwitchId)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
AI_DATA->shouldSwitchMon |= gBitTable[battler];
|
||||
AI_DATA->shouldSwitchMon |= 1 << battler;
|
||||
AI_DATA->monToSwitchId[battler] = monToSwitchId;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -523,6 +524,7 @@ static bool32 AI_ShouldSwitchIfBadMoves(u32 battler, bool32 doubleBattle)
|
||||
// If can switch.
|
||||
if (CountUsablePartyMons(battler) > 0
|
||||
&& !IsBattlerTrapped(battler, TRUE)
|
||||
&& !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE))
|
||||
&& AI_THINKING_STRUCT->aiFlags[battler] & (AI_FLAG_CHECK_VIABILITY | AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_PREFER_BATON_PASS)
|
||||
&& !(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SEQUENCE_SWITCHING))
|
||||
{
|
||||
@@ -1734,6 +1736,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_HIT_ESCAPE:
|
||||
break;
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
if (CountUsablePartyMons(battlerAtk) == 0)
|
||||
ADJUST_SCORE(-10);
|
||||
else if (weather & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY) || IsMoveEffectWeather(aiData->partnerMove))
|
||||
ADJUST_SCORE(-8);
|
||||
else if (weather & B_WEATHER_HAIL)
|
||||
ADJUST_SCORE(-2); // mainly to prevent looping between hail and snow
|
||||
break;
|
||||
case EFFECT_BELLY_DRUM:
|
||||
case EFFECT_FILLET_AWAY:
|
||||
if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY)
|
||||
@@ -2045,7 +2055,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
|
||||
/*if (AI_THINKING_STRUCT->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI
|
||||
&& IS_DOUBLE_BATTLE) //Make the regular AI know how to use Protect minimally in Doubles
|
||||
&& IsDoubleBattle()) //Make the regular AI know how to use Protect minimally in Doubles
|
||||
{
|
||||
u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move);
|
||||
if (shouldProtect == USE_PROTECT || shouldProtect == PROTECT_FROM_FOES)
|
||||
@@ -2768,6 +2778,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_SNOWSCAPE:
|
||||
case EFFECT_RAIN_DANCE:
|
||||
case EFFECT_SANDSTORM:
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
if (IsMoveEffectWeather(move))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
@@ -2847,6 +2858,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
break;
|
||||
case EFFECT_SNOWSCAPE:
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
if (IsBattlerAlive(battlerAtkPartner)
|
||||
&& ShouldSetSnow(battlerAtkPartner, atkPartnerAbility, atkPartnerHoldEffect))
|
||||
{
|
||||
@@ -3616,6 +3628,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
//fallthrough
|
||||
case EFFECT_HIT_ESCAPE:
|
||||
case EFFECT_PARTING_SHOT:
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
if (!IsDoubleBattle())
|
||||
{
|
||||
switch (ShouldPivot(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, movesetIndex))
|
||||
@@ -4051,7 +4064,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT); // Force 'em out next turn
|
||||
break;
|
||||
default:
|
||||
if (move != MOVE_BESTOW && aiData->items[battlerAtk] == ITEM_NONE)
|
||||
if (gMovesInfo[gCurrentMove].effect != EFFECT_BESTOW && aiData->items[battlerAtk] == ITEM_NONE)
|
||||
{
|
||||
switch (aiData->holdEffects[battlerDef])
|
||||
{
|
||||
@@ -4874,6 +4887,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
case EFFECT_SANDSTORM:
|
||||
case EFFECT_HAIL:
|
||||
case EFFECT_SNOWSCAPE:
|
||||
case EFFECT_CHILLY_RECEPTION:
|
||||
case EFFECT_GEOMANCY:
|
||||
case EFFECT_VICTORY_DANCE:
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
@@ -5042,7 +5056,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor
|
||||
static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
u32 effect = gMovesInfo[move].effect;
|
||||
u32 moveType = TYPE_NONE;
|
||||
u32 moveType = 0;
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
|
||||
@@ -40,7 +40,7 @@ static void InitializeSwitchinCandidate(struct Pokemon *mon)
|
||||
static bool32 IsAceMon(u32 battler, u32 monPartyId)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON
|
||||
&& !(gBattleStruct->forcedSwitch & gBitTable[battler])
|
||||
&& !(gBattleStruct->forcedSwitch & (1u << battler))
|
||||
&& monPartyId == CalculateEnemyPartyCount()-1)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
@@ -82,7 +82,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
|
||||
return FALSE;
|
||||
|
||||
// Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler));
|
||||
@@ -218,9 +218,9 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
|
||||
|
||||
static bool32 ShouldSwitchIfAllBadMoves(u32 battler, bool32 emitResult)
|
||||
{
|
||||
if (AI_DATA->shouldSwitchMon & gBitTable[battler])
|
||||
if (AI_DATA->shouldSwitchMon & (1u << battler))
|
||||
{
|
||||
AI_DATA->shouldSwitchMon &= ~(gBitTable[battler]);
|
||||
AI_DATA->shouldSwitchMon &= ~(1u << battler);
|
||||
gBattleStruct->AI_monToSwitchIntoId[battler] = AI_DATA->monToSwitchId[battler];
|
||||
if (emitResult)
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SWITCH, 0);
|
||||
@@ -242,7 +242,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler, bool32 emitResult)
|
||||
struct Pokemon *party = NULL;
|
||||
u16 move;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler));
|
||||
@@ -318,10 +318,10 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler, bool32 emitResult)
|
||||
if (IS_MOVE_STATUS(gLastLandedMoves[battler]))
|
||||
return FALSE;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerIn1 = battler;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))])
|
||||
if (gAbsentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))))
|
||||
battlerIn2 = battler;
|
||||
else
|
||||
battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)));
|
||||
@@ -690,7 +690,7 @@ static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng)
|
||||
u32 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler));
|
||||
u32 opposingBattler = GetBattlerAtPosition(opposingPosition);
|
||||
|
||||
if (!(gAbsentBattlerFlags & gBitTable[opposingBattler]))
|
||||
if (!(gAbsentBattlerFlags & (1u << opposingBattler)))
|
||||
{
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
@@ -707,12 +707,12 @@ static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||
if (!IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
opposingBattler = GetBattlerAtPosition(BATTLE_PARTNER(opposingPosition));
|
||||
|
||||
if (!(gAbsentBattlerFlags & gBitTable[opposingBattler]))
|
||||
if (!(gAbsentBattlerFlags & (1u << opposingBattler)))
|
||||
{
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
@@ -765,10 +765,10 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 modu
|
||||
if (IS_MOVE_STATUS(gLastLandedMoves[battler]))
|
||||
return FALSE;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerIn1 = battler;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))])
|
||||
if (gAbsentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))))
|
||||
battlerIn2 = battler;
|
||||
else
|
||||
battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)));
|
||||
@@ -846,10 +846,10 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
|
||||
// Battler will faint to hazards, check to see if another mon can clear them
|
||||
if (hazardDamage > battlerHp)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerIn1 = battler;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))])
|
||||
if (gAbsentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))))
|
||||
battlerIn2 = battler;
|
||||
else
|
||||
battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)));
|
||||
@@ -881,7 +881,9 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL);
|
||||
if (aiMove == MOVE_RAPID_SPIN || aiMove == MOVE_DEFOG || aiMove == MOVE_MORTAL_SPIN || aiMove == MOVE_TIDY_UP)
|
||||
if (MoveHasAdditionalEffectSelf(aiMove, MOVE_EFFECT_RAPID_SPIN)
|
||||
|| (B_DEFOG_EFFECT_CLEARING >= GEN_6 && gMovesInfo[aiMove].effect == EFFECT_DEFOG)
|
||||
|| gMovesInfo[aiMove].effect == EFFECT_TIDY_UP)
|
||||
{
|
||||
// Have a mon that can clear the hazards, so switching out is okay
|
||||
return TRUE;
|
||||
@@ -1014,6 +1016,8 @@ bool32 ShouldSwitch(u32 battler, bool32 emitResult)
|
||||
return FALSE;
|
||||
if (IsAbilityPreventingEscape(battler))
|
||||
return FALSE;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
||||
return FALSE;
|
||||
|
||||
// Sequence Switching AI never switches mid-battle
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SEQUENCE_SWITCHING)
|
||||
@@ -1021,10 +1025,10 @@ bool32 ShouldSwitch(u32 battler, bool32 emitResult)
|
||||
|
||||
availableToSwitch = 0;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerIn1 = battler;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))])
|
||||
if (gAbsentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))))
|
||||
battlerIn2 = battler;
|
||||
else
|
||||
battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)));
|
||||
@@ -1138,7 +1142,7 @@ void AI_TrySwitchOrUseItem(u32 battler)
|
||||
s32 monToSwitchId = AI_DATA->mostSuitableMonId[battler];
|
||||
if (monToSwitchId == PARTY_SIZE)
|
||||
{
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||
if (!IsDoubleBattle())
|
||||
{
|
||||
battlerIn1 = GetBattlerAtPosition(battlerPosition);
|
||||
battlerIn2 = battlerIn1;
|
||||
@@ -1193,14 +1197,14 @@ static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u
|
||||
|
||||
for (i = firstId; i < lastId; i++)
|
||||
{
|
||||
if (invalidMons & gBitTable[i])
|
||||
if (invalidMons & (1u << i))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
if (GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL) == MOVE_BATON_PASS)
|
||||
{
|
||||
bits |= gBitTable[i];
|
||||
bits |= 1u << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1211,7 +1215,7 @@ static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u
|
||||
do
|
||||
{
|
||||
i = (Random() % (lastId - firstId)) + firstId;
|
||||
} while (!(bits & gBitTable[i]));
|
||||
} while (!(bits & (1 << i)));
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -1229,7 +1233,7 @@ static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId,
|
||||
// Find the mon whose type is the most suitable defensively.
|
||||
for (i = firstId; i < lastId; i++)
|
||||
{
|
||||
if (!(gBitTable[i] & invalidMons) && !(gBitTable[i] & bits))
|
||||
if (!((1u << i) & invalidMons) && !((1u << i) & bits))
|
||||
{
|
||||
u16 species = GetMonData(&party[i], MON_DATA_SPECIES);
|
||||
uq4_12_t typeEffectiveness = UQ_4_12(1.0);
|
||||
@@ -1269,7 +1273,7 @@ static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId,
|
||||
if (i != MAX_MON_MOVES)
|
||||
return bestMonId; // Has both the typing and at least one super effective move.
|
||||
|
||||
bits |= gBitTable[bestMonId]; // Sorry buddy, we want something better.
|
||||
bits |= (1u << bestMonId); // Sorry buddy, we want something better.
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1291,7 +1295,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
|
||||
// If we couldn't find the best mon in terms of typing, find the one that deals most damage.
|
||||
for (i = firstId; i < lastId; i++)
|
||||
{
|
||||
if (gBitTable[i] & invalidMons)
|
||||
if ((1 << (i)) & invalidMons)
|
||||
continue;
|
||||
InitializeSwitchinCandidate(&party[i]);
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
@@ -1562,9 +1566,9 @@ static u32 GetSwitchinStatusDamage(u32 battler)
|
||||
if ((status & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns
|
||||
AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1);
|
||||
statusDamage = maxHP / 16;
|
||||
statusDamage *= AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8;
|
||||
if (statusDamage == 0)
|
||||
statusDamage = 1;
|
||||
statusDamage *= AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1731,7 +1735,7 @@ static int GetRandomSwitchinWithBatonPass(int aliveCount, int bits, int firstId,
|
||||
do
|
||||
{
|
||||
return (Random() % (lastId - firstId)) + firstId;
|
||||
} while (!(bits & gBitTable[currentMonId]));
|
||||
} while (!(bits & (1 << (currentMonId))));
|
||||
}
|
||||
|
||||
// Catch any other cases (such as only one mon alive and it has Baton Pass)
|
||||
@@ -1871,7 +1875,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
|
||||
// Check for Baton Pass; hitsToKO requirements mean mon can boost and BP without dying whether it's slower or not
|
||||
if (aiMove == MOVE_BATON_PASS && ((hitsToKOAI > hitsToKOAIThreshold + 1 && AI_DATA->switchinCandidate.battleMon.speed < playerMonSpeed) || (hitsToKOAI > hitsToKOAIThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed)))
|
||||
bits |= gBitTable[i];
|
||||
bits |= 1u << i;
|
||||
|
||||
// Check for mon with resistance and super effective move for GetBestMonTypeMatchup
|
||||
if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0)
|
||||
@@ -1998,7 +2002,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
}
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE
|
||||
&& (gMovesInfo[gLastUsedMove].effect == EFFECT_HIT_ESCAPE || gMovesInfo[gLastUsedMove].effect == EFFECT_PARTING_SHOT || gMovesInfo[gLastUsedMove].effect == EFFECT_BATON_PASS))
|
||||
&& (gMovesInfo[gLastUsedMove].effect == EFFECT_HIT_ESCAPE || gMovesInfo[gLastUsedMove].effect == EFFECT_PARTING_SHOT || gMovesInfo[gLastUsedMove].effect == EFFECT_BATON_PASS || gMovesInfo[gLastUsedMove].effect == EFFECT_CHILLY_RECEPTION))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
@@ -2035,17 +2039,19 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
||||
|
||||
if (*(gBattleStruct->monToSwitchIntoId + battler) != PARTY_SIZE)
|
||||
return *(gBattleStruct->monToSwitchIntoId + battler);
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
||||
return gBattlerPartyIndexes[battler] + 1;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerIn1 = battler;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))])
|
||||
if (gAbsentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))))
|
||||
battlerIn2 = battler;
|
||||
else
|
||||
battlerIn2 = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)));
|
||||
|
||||
opposingBattler = BATTLE_OPPOSITE(battlerIn1);
|
||||
if (gAbsentBattlerFlags & gBitTable[opposingBattler])
|
||||
if (gAbsentBattlerFlags & (1u << opposingBattler))
|
||||
opposingBattler ^= BIT_FLANK;
|
||||
}
|
||||
else
|
||||
@@ -2070,7 +2076,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
||||
|
||||
// Split ideal mon decision between after previous mon KO'd (prioritize offensive options) and after switching active mon out (prioritize defensive options), and expand the scope of both.
|
||||
// Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer.
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES && !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic
|
||||
{
|
||||
bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchAfterMonKOd);
|
||||
return bestMonId;
|
||||
@@ -2091,12 +2097,12 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
||||
|| i == gBattleStruct->monToSwitchIntoId[battlerIn2]
|
||||
|| (GetMonAbility(&party[i]) == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))) // While not really invalid per se, not really wise to switch into this mon.)
|
||||
{
|
||||
invalidMons |= gBitTable[i];
|
||||
invalidMons |= 1u << i;
|
||||
}
|
||||
else if (IsAceMon(battler, i))// Save Ace Pokemon for last.
|
||||
{
|
||||
aceMonId = i;
|
||||
invalidMons |= gBitTable[i];
|
||||
invalidMons |= 1u << i;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "battle_ai_util.h"
|
||||
#include "battle_ai_main.h"
|
||||
#include "battle_ai_switch_items.h"
|
||||
// #include "battle_factory.h"
|
||||
#include "battle_setup.h"
|
||||
#include "event_data.h"
|
||||
#include "data.h"
|
||||
@@ -350,12 +351,12 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category)
|
||||
if (moves[i] != MOVE_NONE
|
||||
&& moves[i] != MOVE_UNAVAILABLE
|
||||
&& GetBattleMoveCategory(moves[i]) == category
|
||||
&& !(unusable & gBitTable[i]))
|
||||
&& !(unusable & (1u << i)))
|
||||
{
|
||||
SetTypeBeforeUsingMove(moves[i], attacker);
|
||||
moveType = GetMoveType(moves[i]);
|
||||
if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, AI_DATA->abilities[target], FALSE) != 0)
|
||||
usable |= gBitTable[i];
|
||||
usable |= 1u << i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,7 +482,7 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_POLTERGEIST:
|
||||
if (AI_DATA->items[battlerDef] == ITEM_NONE)
|
||||
if (AI_DATA->items[battlerDef] == ITEM_NONE || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM || battlerDefAbility == ABILITY_KLUTZ)
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_FIRST_TURN_ONLY:
|
||||
@@ -575,13 +576,13 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
if (critChanceIndex > 1) // Consider crit damage only if a move has at least +2 crit chance
|
||||
{
|
||||
s32 nonCritDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||
effectivenessMultiplier, weather, FALSE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
effectivenessMultiplier, weather, FALSE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||
effectivenessMultiplier, weather, TRUE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
effectivenessMultiplier, weather, TRUE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
|
||||
u32 critOdds = GetCritHitOdds(critChanceIndex);
|
||||
// With critOdds getting closer to 1, dmg gets closer to critDmg.
|
||||
@@ -594,20 +595,33 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
else if (critChanceIndex == -2) // Guaranteed critical
|
||||
{
|
||||
s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||
effectivenessMultiplier, weather, TRUE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
effectivenessMultiplier, weather, TRUE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
|
||||
simDamage.expected = GetDamageByRollType(critDmg, rollType);
|
||||
simDamage.minimum = LowestRollDmg(critDmg);
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 nonCritDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||
effectivenessMultiplier, weather, FALSE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
|
||||
s32 nonCritDmg = 0;
|
||||
if (gMovesInfo[move].effect == EFFECT_TRIPLE_KICK)
|
||||
{
|
||||
for (gMultiHitCounter = gMovesInfo[move].strikeCount; gMultiHitCounter > 0; gMultiHitCounter--) // The global is used to simulate actual damage done
|
||||
{
|
||||
nonCritDmg += CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||
effectivenessMultiplier, weather, FALSE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCritDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||
effectivenessMultiplier, weather, FALSE,
|
||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
}
|
||||
simDamage.expected = GetDamageByRollType(nonCritDmg, rollType);
|
||||
simDamage.minimum = LowestRollDmg(nonCritDmg);
|
||||
}
|
||||
@@ -1091,7 +1105,7 @@ bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i])
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & (1u << i))
|
||||
&& AI_DATA->simulatedDmg[battlerDef][battlerAtk][i].expected >= gBattleMons[battlerAtk].hp)
|
||||
{
|
||||
return TRUE;
|
||||
@@ -1129,7 +1143,7 @@ u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i])
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & (1u << i))
|
||||
&& bestDmg < AI_DATA->simulatedDmg[battlerAtk][battlerDef][i].expected)
|
||||
{
|
||||
bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i].expected;
|
||||
@@ -1150,7 +1164,7 @@ u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE
|
||||
&& moves[i] != MOVE_UNAVAILABLE
|
||||
&& !(unusable & gBitTable[i])
|
||||
&& !(unusable & (1u << i))
|
||||
&& bestDmg < AI_DATA->simulatedDmg[battler][battlerTarget][i].expected)
|
||||
{
|
||||
bestDmg = AI_DATA->simulatedDmg[battler][battlerTarget][i].expected;
|
||||
@@ -1170,7 +1184,7 @@ bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(moveLimitations & gBitTable[i]))
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(moveLimitations & (1u << i)))
|
||||
{
|
||||
// Use the pre-calculated value in simulatedDmg instead of re-calculating it
|
||||
dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i].expected;
|
||||
@@ -1215,7 +1229,7 @@ bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dm
|
||||
if (dmgMod)
|
||||
dmg *= dmgMod;
|
||||
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i]) && dmg >= hpCheck)
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & (1u << i)) && dmg >= hpCheck)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -2077,7 +2091,7 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool
|
||||
if (moves[i] == MOVE_NONE || moves[i] == MOVE_UNAVAILABLE)
|
||||
continue;
|
||||
|
||||
if (!(gBitTable[i] & moveLimitations))
|
||||
if (!((1u << i) & moveLimitations))
|
||||
{
|
||||
if (ignoreStatus && IS_MOVE_STATUS(moves[i]))
|
||||
continue;
|
||||
@@ -2103,7 +2117,7 @@ bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
if (moves[i] == MOVE_NONE)
|
||||
break;
|
||||
if (!(gBitTable[i] & moveLimitations))
|
||||
if (!((1u << i) & moveLimitations))
|
||||
{
|
||||
if (gMovesInfo[moves[i]].effect == EFFECT_SLEEP
|
||||
&& AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] < 85)
|
||||
@@ -2499,7 +2513,7 @@ u32 GetBattlerSecondaryDamage(u32 battlerId)
|
||||
bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability)
|
||||
{
|
||||
if ((BattlerAffectedBySandstorm(battler, ability) || BattlerAffectedByHail(battler, ability))
|
||||
&& gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16)
|
||||
&& gBattleMons[battler].hp <= max(1, gBattleMons[battler].maxHP / 16))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
@@ -2508,7 +2522,7 @@ bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability)
|
||||
bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability)
|
||||
{
|
||||
if (GetBattlerSecondaryDamage(battler) != 0
|
||||
&& gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16)
|
||||
&& gBattleMons[battler].hp <= max(1, gBattleMons[battler].maxHP / 16))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2778,6 +2792,7 @@ bool32 CanKnockOffItem(u32 battler, u32 item)
|
||||
| BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| BATTLE_TYPE_SECRET_BASE
|
||||
| (B_TRAINERS_KNOCK_OFF_ITEMS == TRUE ? BATTLE_TYPE_TRAINER : 0)
|
||||
)) && GetBattlerSide(battler) == B_SIDE_PLAYER)
|
||||
return FALSE;
|
||||
@@ -3024,7 +3039,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
|
||||
else
|
||||
party = gEnemyParty;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerOnField1 = gBattlerPartyIndexes[battlerId];
|
||||
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))];
|
||||
@@ -3247,7 +3262,8 @@ bool32 IsMoveEffectWeather(u32 move)
|
||||
|| gMovesInfo[move].effect == EFFECT_RAIN_DANCE
|
||||
|| gMovesInfo[move].effect == EFFECT_SANDSTORM
|
||||
|| gMovesInfo[move].effect == EFFECT_HAIL
|
||||
|| gMovesInfo[move].effect == EFFECT_SNOWSCAPE))
|
||||
|| gMovesInfo[move].effect == EFFECT_SNOWSCAPE
|
||||
|| gMovesInfo[move].effect == EFFECT_CHILLY_RECEPTION))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -3415,7 +3431,7 @@ s32 CountUsablePartyMons(u32 battlerId)
|
||||
else
|
||||
party = gEnemyParty;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (IsDoubleBattle())
|
||||
{
|
||||
battlerOnField1 = gBattlerPartyIndexes[battlerId];
|
||||
battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))];
|
||||
@@ -3826,7 +3842,7 @@ bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move)
|
||||
bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove)
|
||||
{
|
||||
// simple logic. just upgrades chosen move to z move if possible, unless regular move would kill opponent
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && battlerDef == BATTLE_PARTNER(battlerAtk))
|
||||
if ((IsDoubleBattle()) && battlerDef == BATTLE_PARTNER(battlerAtk))
|
||||
return FALSE; // don't use z move on partner
|
||||
if (HasTrainerUsedGimmick(battlerAtk, GIMMICK_Z_MOVE))
|
||||
return FALSE; // can't use z move twice
|
||||
|
||||
@@ -2593,8 +2593,6 @@ static void BattleStartClearSetData(void)
|
||||
gBattleStruct->itemLost[B_SIDE_PLAYER][i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
||||
gBattleStruct->itemLost[B_SIDE_OPPONENT][i].originalItem = GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM);
|
||||
gPartyCriticalHits[i] = 0;
|
||||
gBattleStruct->allowedToChangeFormInWeather[i][B_SIDE_PLAYER] = FALSE;
|
||||
gBattleStruct->allowedToChangeFormInWeather[i][B_SIDE_OPPONENT] = FALSE;
|
||||
}
|
||||
|
||||
gBattleStruct->swapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
||||
|
||||
@@ -973,6 +973,7 @@ const u8 gText_Unused_6F[] = _("6F");
|
||||
const u8 gText_Unused_7F[] = _("7F");
|
||||
const u8 gText_Unused_8F[] = _("8F");
|
||||
static const u8 sText_PkmnTerastallizedInto[] = _("{B_ATK_NAME_WITH_PREFIX} terastallized\ninto the {B_BUFF1} type!");
|
||||
static const u8 sText_FickleBeamDoubled[] = _("{B_ATK_NAME_WITH_PREFIX} is going all\nout for this attack!");
|
||||
|
||||
|
||||
const u8 *const gStatNamesTable[] = {
|
||||
@@ -994,7 +995,9 @@ const u8 *const gPokeblockWasTooXStringTable[] = {
|
||||
sText_PokeblockWasTooSour
|
||||
};
|
||||
|
||||
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_START] = {
|
||||
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_START] =
|
||||
{
|
||||
[STRINGID_FICKLEBEAMDOUBLED - BATTLESTRINGS_TABLE_START] = sText_FickleBeamDoubled,
|
||||
[STRINGID_PKMNTERASTALLIZEDINTO - BATTLESTRINGS_TABLE_START] = sText_PkmnTerastallizedInto,
|
||||
[STRINGID_TIDYINGUPCOMPLETE - BATTLESTRINGS_TABLE_START] = sText_TidyingUpComplete,
|
||||
[STRINGID_SUPERSWEETAROMAWAFTS - BATTLESTRINGS_TABLE_START] = sText_SupersweetAromaWafts,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1831,7 +1831,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_FICKLE_BEAM] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleScript = BattleScript_EffectFickleBeam,
|
||||
},
|
||||
|
||||
[EFFECT_BLIZZARD] =
|
||||
|
||||
@@ -930,7 +930,7 @@ static void Task_EvolutionScene(u8 taskId)
|
||||
BattlePutTextOnWindow(gText_BattleYesNoChoice, B_WIN_YESNO);
|
||||
gTasks[taskId].tLearnMoveState++;
|
||||
sEvoCursorPos = 0;
|
||||
BattleCreateYesNoCursorAt();
|
||||
BattleCreateYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
||||
}
|
||||
break;
|
||||
case MVSTATE_HANDLE_YES_NO:
|
||||
@@ -941,17 +941,17 @@ static void Task_EvolutionScene(u8 taskId)
|
||||
{
|
||||
// Moved onto YES
|
||||
PlaySE(SE_SELECT);
|
||||
BattleDestroyYesNoCursorAt();
|
||||
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
||||
sEvoCursorPos = 0;
|
||||
BattleCreateYesNoCursorAt();
|
||||
BattleCreateYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
||||
}
|
||||
if (JOY_NEW(DPAD_DOWN) && sEvoCursorPos == 0)
|
||||
{
|
||||
// Moved onto NO
|
||||
PlaySE(SE_SELECT);
|
||||
BattleDestroyYesNoCursorAt();
|
||||
BattleDestroyYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
||||
sEvoCursorPos = 1;
|
||||
BattleCreateYesNoCursorAt();
|
||||
BattleCreateYesNoCursorAt(gBattleCommunication[CURSOR_POSITION]);
|
||||
}
|
||||
if (JOY_NEW(A_BUTTON))
|
||||
{
|
||||
|
||||
30
src/main.c
30
src/main.c
@@ -248,12 +248,8 @@ void SetMainCallback2(MainCallback callback)
|
||||
|
||||
void StartTimer1(void)
|
||||
{
|
||||
if (HQ_RANDOM)
|
||||
{
|
||||
REG_TM2CNT_L = 0;
|
||||
REG_TM2CNT_H = TIMER_ENABLE | TIMER_COUNTUP;
|
||||
}
|
||||
|
||||
REG_TM2CNT_L = 0;
|
||||
REG_TM2CNT_H = TIMER_ENABLE | TIMER_COUNTUP;
|
||||
REG_TM1CNT_H = TIMER_ENABLE;
|
||||
}
|
||||
|
||||
@@ -261,22 +257,12 @@ void SeedRngAndSetTrainerId(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (HQ_RANDOM)
|
||||
{
|
||||
REG_TM1CNT_H = 0;
|
||||
REG_TM2CNT_H = 0;
|
||||
val = ((u32)REG_TM2CNT_L) << 16;
|
||||
val |= REG_TM1CNT_L;
|
||||
SeedRng(val);
|
||||
gTrainerId = Random();
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 val = REG_TM1CNT_L;
|
||||
SeedRng(val);
|
||||
REG_TM1CNT_H = 0;
|
||||
gTrainerId = val;
|
||||
}
|
||||
REG_TM1CNT_H = 0;
|
||||
REG_TM2CNT_H = 0;
|
||||
val = ((u32)REG_TM2CNT_L) << 16;
|
||||
val |= REG_TM1CNT_L;
|
||||
SeedRng(val);
|
||||
gTrainerId = Random();
|
||||
}
|
||||
|
||||
u16 GetGeneratedTrainerIdLower(void)
|
||||
|
||||
34
src/random.c
34
src/random.c
@@ -8,7 +8,6 @@
|
||||
rng_value_t gRngValue;
|
||||
rng_value_t gRng2Value;
|
||||
|
||||
#if HQ_RANDOM == TRUE
|
||||
|
||||
EWRAM_DATA static volatile bool8 sRngLoopUnlocked;
|
||||
|
||||
@@ -112,39 +111,6 @@ void AdvanceRandom(void)
|
||||
|
||||
#define LOOP_RANDOM ((u16)(_SFC32_Next(state) >> 16))
|
||||
|
||||
#else
|
||||
EWRAM_DATA static u32 sRandCount = 0;
|
||||
|
||||
u16 Random(void)
|
||||
{
|
||||
gRngValue = ISO_RANDOMIZE1(gRngValue);
|
||||
sRandCount++;
|
||||
return gRngValue >> 16;
|
||||
}
|
||||
|
||||
void SeedRng(u16 seed)
|
||||
{
|
||||
gRngValue = seed;
|
||||
}
|
||||
|
||||
void SeedRng2(u16 seed)
|
||||
{
|
||||
gRng2Value = seed;
|
||||
}
|
||||
|
||||
u16 Random2(void)
|
||||
{
|
||||
gRng2Value = ISO_RANDOMIZE1(gRng2Value);
|
||||
return gRng2Value >> 16;
|
||||
}
|
||||
|
||||
#define LOOP_RANDOM_START
|
||||
#define LOOP_RANDOM_END
|
||||
|
||||
#define LOOP_RANDOM (Random())
|
||||
|
||||
#endif
|
||||
|
||||
#define SHUFFLE_IMPL \
|
||||
u32 tmp; \
|
||||
LOOP_RANDOM_START; \
|
||||
|
||||
Reference in New Issue
Block a user