mirror of
https://github.com/rh-hideout/pokeemerald-expansion.git
synced 2026-03-21 18:04:50 -05:00
1194 lines
40 KiB
C
1194 lines
40 KiB
C
#ifndef GUARD_BATTLE_H
|
|
#define GUARD_BATTLE_H
|
|
|
|
// should they be included here or included individually by every file?
|
|
#include "constants/battle_end_turn.h"
|
|
#include "constants/battle_switch_in.h"
|
|
#include "constants/abilities.h"
|
|
#include "constants/battle.h"
|
|
#include "constants/battle_move_resolution.h"
|
|
#include "constants/form_change_types.h"
|
|
#include "constants/hold_effects.h"
|
|
#include "constants/moves.h"
|
|
#include "battle_main.h"
|
|
#include "battle_message.h"
|
|
#include "battle_util.h"
|
|
#include "battle_script_commands.h"
|
|
#include "battle_gfx_sfx_util.h"
|
|
#include "battle_util2.h"
|
|
#include "battle_bg.h"
|
|
#include "pokeball.h"
|
|
#include "main.h"
|
|
#include "battle_debug.h"
|
|
#include "battle_dynamax.h"
|
|
#include "battle_terastal.h"
|
|
#include "battle_gimmick.h"
|
|
#include "generational_changes.h"
|
|
#include "item.h"
|
|
#include "move.h"
|
|
#include "random.h" // for rng_value_t
|
|
#include "trainer_slide.h"
|
|
|
|
// Used to exclude moves learned temporarily by Transform or Mimic
|
|
#define MOVE_IS_PERMANENT(battler, moveSlot) \
|
|
(!(gBattleMons[battler].volatiles.transformed) \
|
|
&& !(gBattleMons[battler].volatiles.mimickedMoves & (1u << moveSlot)))
|
|
|
|
// Battle Actions
|
|
// These determine what each battler will do in a turn
|
|
#define B_ACTION_USE_MOVE 0
|
|
#define B_ACTION_USE_ITEM 1
|
|
#define B_ACTION_SWITCH 2
|
|
#define B_ACTION_RUN 3
|
|
#define B_ACTION_SAFARI_WATCH_CAREFULLY 4
|
|
#define B_ACTION_SAFARI_BALL 5
|
|
#define B_ACTION_SAFARI_POKEBLOCK 6
|
|
#define B_ACTION_SAFARI_GO_NEAR 7
|
|
#define B_ACTION_SAFARI_RUN 8
|
|
#define B_ACTION_WALLY_THROW 9
|
|
#define B_ACTION_EXEC_SCRIPT 10
|
|
#define B_ACTION_TRY_FINISH 11
|
|
#define B_ACTION_FINISHED 12
|
|
#define B_ACTION_CANCEL_PARTNER 12 // when choosing an action
|
|
#define B_ACTION_NOTHING_FAINTED 13 // when choosing an action
|
|
#define B_ACTION_UNK_14 14
|
|
#define B_ACTION_DEBUG 20
|
|
#define B_ACTION_THROW_BALL 21 // R to throw last used ball
|
|
#define B_ACTION_NONE 0xFF
|
|
|
|
#define BATTLE_BUFFER_LINK_SIZE 0x1000
|
|
|
|
// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects
|
|
struct ProtectStruct
|
|
{
|
|
u32 protected:7; // 126 protect options
|
|
u32 noValidMoves:1;
|
|
u32 bounceMove:1;
|
|
u32 stealMove:1;
|
|
u32 chargingTurn:1;
|
|
u32 fleeType:2; // 0: Normal, 1: FLEE_ITEM, 2: FLEE_ABILITY
|
|
u32 laggingTail:1;
|
|
u32 palaceUnableToUseMove:1;
|
|
u32 statRaised:1;
|
|
u32 usedCustapBerry:1; // also quick claw
|
|
u32 disableEjectPack:1;
|
|
u32 pranksterElevated:1;
|
|
u32 quickDraw:1;
|
|
u32 quash:1;
|
|
u32 shellTrap:1;
|
|
u32 eatMirrorHerb:1;
|
|
u32 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
|
|
u32 usedAllySwitch:1;
|
|
u32 lashOutAffected:1;
|
|
u32 assuranceDoubled:1;
|
|
u32 forcedSwitch:1;
|
|
u32 myceliumMight:1;
|
|
u32 survivedOHKO:1; // Used to keep track of effects that allow focus punch when surviving moves like Fissure
|
|
u32 padding1:1;
|
|
// End of 32-bit bitfield
|
|
u16 helpingHand:3;
|
|
u16 revengeDoubled:4;
|
|
u16 padding2:9;
|
|
// End of 16-bit bitfield
|
|
u16 physicalDmg;
|
|
u16 specialDmg;
|
|
u8 physicalBattlerId:3;
|
|
u8 specialBattlerId:3;
|
|
u8 lastHitBySpecialMove:1;
|
|
u8 padding3:1;
|
|
};
|
|
|
|
// Cleared at the start of HandleAction_ActionFinished
|
|
struct SpecialStatus
|
|
{
|
|
u8 changedStatsBattlerId; // Battler that was responsible for the latest stat change. Can be self.
|
|
u8 statLowered:1;
|
|
u8 abilityRedirected:1;
|
|
u8 restoredBattlerSprite: 1;
|
|
u8 faintedHasReplacement:1;
|
|
u8 afterYou:1;
|
|
u8 damagedByAttack:1;
|
|
u8 dancerUsedMove:1;
|
|
u8 criticalHit:1;
|
|
// End of byte
|
|
u8 instructedChosenTarget:3;
|
|
u8 neutralizingGasRemoved:1;
|
|
u8 berryReduced:1;
|
|
u8 mindBlownRecoil:1;
|
|
u8 padding2:2;
|
|
// End of byte
|
|
u8 gemParam:7;
|
|
u8 gemBoost:1;
|
|
// End of byte
|
|
u8 parentalBondState:2;
|
|
u8 multiHitOn:1;
|
|
u8 distortedTypeMatchups:1;
|
|
u8 teraShellAbilityDone:1;
|
|
u8 dancerOriginalTarget:3;
|
|
// End of byte
|
|
};
|
|
|
|
struct SideTimer
|
|
{
|
|
u16 reflectTimer;
|
|
u16 lightscreenTimer;
|
|
u16 mistTimer;
|
|
u16 safeguardTimer;
|
|
u8 spikesAmount:4;
|
|
u8 toxicSpikesAmount:4;
|
|
u8 stickyWebBattlerId;
|
|
u8 stickyWebBattlerSide; // Used for Court Change
|
|
u16 auroraVeilTimer;
|
|
u16 tailwindTimer;
|
|
u16 luckyChantTimer;
|
|
// Timers below this point are not swapped by Court Change
|
|
u8 followmeTimer:4;
|
|
u8 followmeTarget:3;
|
|
u8 followmePowder:1; // Rage powder, does not affect grass type pokemon.
|
|
u8 retaliateTimer;
|
|
u16 damageNonTypesTimer;
|
|
enum Type damageNonTypesType;
|
|
u16 rainbowTimer;
|
|
u16 seaOfFireTimer;
|
|
u16 swampTimer;
|
|
};
|
|
|
|
struct FieldTimer
|
|
{
|
|
u16 mudSportTimer;
|
|
u16 waterSportTimer;
|
|
u16 wonderRoomTimer;
|
|
u16 magicRoomTimer;
|
|
u16 trickRoomTimer;
|
|
u16 terrainTimer;
|
|
u16 gravityTimer;
|
|
u16 fairyLockTimer;
|
|
};
|
|
|
|
struct AI_SavedBattleMon
|
|
{
|
|
enum Ability ability;
|
|
enum Move moves[MAX_MON_MOVES];
|
|
u16 heldItem;
|
|
u16 species:15;
|
|
u16 saved:1;
|
|
enum Type types[3];
|
|
};
|
|
|
|
struct AiPartyMon
|
|
{
|
|
u16 species;
|
|
enum Item item;
|
|
enum HoldEffect heldEffect;
|
|
enum Ability ability;
|
|
u16 level;
|
|
enum Move moves[MAX_MON_MOVES];
|
|
u32 status;
|
|
u8 switchInCount; // Counts how many times this Pokemon has been sent out or switched into in a battle.
|
|
u8 gender:2;
|
|
u8 isFainted:1;
|
|
u8 wasSentInBattle:1;
|
|
u8 padding:4;
|
|
};
|
|
|
|
struct AiPartyData // Opposing battlers - party mons.
|
|
{
|
|
struct AiPartyMon mons[NUM_BATTLE_SIDES][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party.
|
|
u8 count[NUM_BATTLE_SIDES];
|
|
};
|
|
|
|
struct SimulatedDamage
|
|
{
|
|
u16 minimum;
|
|
u16 median;
|
|
u16 maximum;
|
|
};
|
|
|
|
// Ai Data used when deciding which move to use, computed only once before each turn's start.
|
|
struct AiLogicData
|
|
{
|
|
enum Ability abilities[MAX_BATTLERS_COUNT];
|
|
enum Item items[MAX_BATTLERS_COUNT];
|
|
enum HoldEffect holdEffects[MAX_BATTLERS_COUNT];
|
|
u8 holdEffectParams[MAX_BATTLERS_COUNT];
|
|
enum Move lastUsedMove[MAX_BATTLERS_COUNT];
|
|
u8 hpPercents[MAX_BATTLERS_COUNT];
|
|
enum Move partnerMove;
|
|
u16 speedStats[MAX_BATTLERS_COUNT]; // Speed stats for all battles, calculated only once, same way as damages
|
|
struct SimulatedDamage simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
|
|
uq4_12_t effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
|
|
u8 moveAccuracy[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
|
|
u8 moveLimitations[MAX_BATTLERS_COUNT];
|
|
u8 monToSwitchInId[MAX_BATTLERS_COUNT]; // ID of the mon to switch in.
|
|
u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId.
|
|
enum Move predictedMove[MAX_BATTLERS_COUNT];
|
|
u8 resistBerryAffected[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // Tracks whether currently calc'd move is affected by a resist berry into given target
|
|
|
|
// Flags
|
|
u32 weatherHasEffect:1; // The same as HasWeatherEffect(). Stored here, so it's called only once.
|
|
u32 ejectButtonSwitch:1; // Tracks whether current switch out was from Eject Button
|
|
u32 ejectPackSwitch:1; // Tracks whether current switch out was from Eject Pack
|
|
u32 predictingSwitch:1; // Determines whether AI will use switch predictions this turn or not
|
|
u32 aiPredictionInProgress:1; // Tracks whether the AI is in the middle of running prediction calculations
|
|
u32 aiCalcInProgress:1;
|
|
u32 predictingMove:1; // Determines whether AI will use move predictions this turn or not
|
|
u32 shouldConsiderExplosion:1; // Determines whether AI should consider explosion moves this turn
|
|
u32 shouldSwitch:4; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
|
|
u32 shouldConsiderFinalGambit:1; // Determines whether AI should consider Final Gambit this turn
|
|
u32 switchInCalc:1; // Indicates if we're doing switch in calcs, this is purely for Retaliate damage calcs
|
|
u32 padding2:18;
|
|
};
|
|
|
|
struct AiThinkingStruct
|
|
{
|
|
u8 aiState;
|
|
u8 movesetIndex;
|
|
u16 moveConsidered;
|
|
s32 score[MAX_MON_MOVES];
|
|
u64 aiFlags[MAX_BATTLERS_COUNT];
|
|
u8 aiAction;
|
|
u8 aiLogicId;
|
|
struct AI_SavedBattleMon saved[MAX_BATTLERS_COUNT];
|
|
};
|
|
|
|
#define AI_MOVE_HISTORY_COUNT 3
|
|
|
|
struct BattleHistory
|
|
{
|
|
enum Ability abilities[MAX_BATTLERS_COUNT];
|
|
u8 itemEffects[MAX_BATTLERS_COUNT];
|
|
u16 usedMoves[MAX_BATTLERS_COUNT][MAX_MON_MOVES];
|
|
u16 moveHistory[MAX_BATTLERS_COUNT][AI_MOVE_HISTORY_COUNT]; // 3 last used moves for each battler
|
|
u8 moveHistoryIndex[MAX_BATTLERS_COUNT];
|
|
u16 trainerItems[MAX_BATTLERS_COUNT];
|
|
u8 itemsNo;
|
|
u16 heldItems[MAX_BATTLERS_COUNT];
|
|
};
|
|
|
|
struct BattleScriptsStack
|
|
{
|
|
const u8 *ptr[8];
|
|
u8 size;
|
|
};
|
|
|
|
struct BattleCallbacksStack
|
|
{
|
|
void (*function[8])(void);
|
|
u8 size;
|
|
};
|
|
|
|
struct StatsArray
|
|
{
|
|
u16 stats[NUM_STATS];
|
|
u16 level:15;
|
|
u16 learnMultipleMoves:1;
|
|
};
|
|
|
|
struct BattleResources
|
|
{
|
|
struct SecretBase *secretBase;
|
|
struct BattleScriptsStack *battleScriptsStack;
|
|
struct BattleCallbacksStack *battleCallbackStack;
|
|
struct StatsArray *beforeLvlUp;
|
|
u8 bufferA[MAX_BATTLERS_COUNT][0x200];
|
|
u8 bufferB[MAX_BATTLERS_COUNT][0x200];
|
|
u8 transferBuffer[0x100];
|
|
};
|
|
|
|
struct BattleResults
|
|
{
|
|
u8 playerFaintCounter; // 0x0
|
|
u8 opponentFaintCounter; // 0x1
|
|
u8 playerSwitchesCounter; // 0x2
|
|
u8 numHealingItemsUsed; // 0x3
|
|
u8 numRevivesUsed; // 0x4
|
|
u8 playerMonWasDamaged:1; // 0x5
|
|
u8 caughtMonBall:4; // 0x5
|
|
u8 shinyWildMon:1; // 0x5
|
|
u16 playerMon1Species; // 0x6
|
|
u8 playerMon1Name[POKEMON_NAME_LENGTH + 1]; // 0x8
|
|
u8 battleTurnCounter; // 0x13
|
|
u8 playerMon2Name[POKEMON_NAME_LENGTH + 1]; // 0x14
|
|
u8 pokeblockThrows; // 0x1F
|
|
u16 lastOpponentSpecies; // 0x20
|
|
u16 lastUsedMovePlayer; // 0x22
|
|
u16 lastUsedMoveOpponent; // 0x24
|
|
u16 playerMon2Species; // 0x26
|
|
u16 caughtMonSpecies; // 0x28
|
|
u8 caughtMonNick[POKEMON_NAME_LENGTH + 1]; // 0x2A
|
|
u8 filler35; // 0x35
|
|
u8 catchAttempts[POKEBALL_COUNT]; // 0x36
|
|
};
|
|
|
|
struct BattleTv_Side
|
|
{
|
|
u32 spikesMonId:3;
|
|
u32 reflectMonId:3;
|
|
u32 lightScreenMonId:3;
|
|
u32 safeguardMonId:3;
|
|
u32 mistMonId:3;
|
|
u32 futureSightMonId:3;
|
|
u32 doomDesireMonId:3;
|
|
u32 perishSongMonId:3;
|
|
u32 wishMonId:3;
|
|
u32 grudgeMonId:3;
|
|
u32 usedMoveSlot:2;
|
|
u32 spikesMoveSlot:2;
|
|
u32 reflectMoveSlot:2;
|
|
u32 lightScreenMoveSlot:2;
|
|
u32 safeguardMoveSlot:2;
|
|
u32 mistMoveSlot:2;
|
|
u32 futureSightMoveSlot:2;
|
|
u32 doomDesireMoveSlot:2;
|
|
u32 perishSongMoveSlot:2;
|
|
u32 wishMoveSlot:2;
|
|
u32 grudgeMoveSlot:2;
|
|
u32 destinyBondMonId:3;
|
|
u32 destinyBondMoveSlot:2;
|
|
u32 faintCause:4;
|
|
u32 faintCauseMonId:3;
|
|
u32 explosion:1;
|
|
u32 explosionMoveSlot:2;
|
|
u32 explosionMonId:3;
|
|
u32 perishSong:1;
|
|
};
|
|
|
|
struct BattleTv_Position
|
|
{
|
|
u32 curseMonId:3;
|
|
u32 leechSeedMonId:3;
|
|
u32 nightmareMonId:3;
|
|
u32 wrapMonId:3;
|
|
u32 attractMonId:3;
|
|
u32 confusionMonId:3;
|
|
u32 curseMoveSlot:2;
|
|
u32 leechSeedMoveSlot:2;
|
|
u32 nightmareMoveSlot:2;
|
|
u32 wrapMoveSlot:2;
|
|
u32 attractMoveSlot:2;
|
|
u32 confusionMoveSlot:2;
|
|
u32 waterSportMoveSlot:2;
|
|
u32 waterSportMonId:3;
|
|
u32 mudSportMonId:3;
|
|
u32 mudSportMoveSlot:2;
|
|
u32 ingrainMonId:3;
|
|
u32 ingrainMoveSlot:2;
|
|
u32 attackedByMonId:3;
|
|
u32 attackedByMoveSlot:2;
|
|
};
|
|
|
|
struct BattleTv_Mon
|
|
{
|
|
u32 psnMonId:3;
|
|
u32 badPsnMonId:3;
|
|
u32 brnMonId:3;
|
|
u32 prlzMonId:3;
|
|
u32 slpMonId:3;
|
|
u32 frzMonId:3;
|
|
u32 psnMoveSlot:2;
|
|
u32 badPsnMoveSlot:2;
|
|
u32 brnMoveSlot:2;
|
|
u32 prlzMoveSlot:2;
|
|
u32 slpMoveSlot:2;
|
|
u32 frzMoveSlot:2;
|
|
};
|
|
|
|
struct BattleTv
|
|
{
|
|
struct BattleTv_Mon mon[NUM_BATTLE_SIDES][PARTY_SIZE];
|
|
struct BattleTv_Position pos[NUM_BATTLE_SIDES][2]; // [side][flank]
|
|
struct BattleTv_Side side[NUM_BATTLE_SIDES];
|
|
};
|
|
|
|
struct BattleTvMovePoints
|
|
{
|
|
s16 points[2][PARTY_SIZE * 4];
|
|
};
|
|
|
|
struct LinkBattlerHeader
|
|
{
|
|
u8 versionSignatureLo;
|
|
u8 versionSignatureHi;
|
|
u8 vsScreenHealthFlagsLo;
|
|
u8 vsScreenHealthFlagsHi;
|
|
struct BattleEnigmaBerry battleEnigmaBerry;
|
|
};
|
|
|
|
enum IllusionState
|
|
{
|
|
ILLUSION_NOT_SET,
|
|
ILLUSION_OFF,
|
|
ILLUSION_ON
|
|
};
|
|
|
|
struct Illusion
|
|
{
|
|
enum IllusionState state;
|
|
struct Pokemon *mon;
|
|
};
|
|
|
|
struct ZMoveData
|
|
{
|
|
u8 viable:1; // current move can become a z move
|
|
u8 viewing:1; // if player is viewing the z move name instead of regular moves
|
|
u8 healReplacement:6;
|
|
u8 possibleZMoves[MAX_BATTLERS_COUNT];
|
|
u16 baseMoves[MAX_BATTLERS_COUNT];
|
|
};
|
|
|
|
struct DynamaxData
|
|
{
|
|
u16 dynamaxTurns[MAX_BATTLERS_COUNT];
|
|
u16 baseMoves[MAX_BATTLERS_COUNT]; // base move of Max Move
|
|
u16 lastUsedBaseMove;
|
|
};
|
|
|
|
struct BattleGimmickData
|
|
{
|
|
u8 usableGimmick[MAX_BATTLERS_COUNT]; // first usable gimmick that can be selected for each battler
|
|
bool8 playerSelect; // used to toggle trigger and update battle UI
|
|
u8 triggerSpriteId;
|
|
u8 indicatorSpriteId[MAX_BATTLERS_COUNT];
|
|
u8 toActivate; // stores whether a battler should transform at start of turn as bitfield
|
|
u8 activeGimmick[NUM_BATTLE_SIDES][PARTY_SIZE]; // stores the active gimmick for each party member
|
|
bool8 activated[MAX_BATTLERS_COUNT][GIMMICKS_COUNT]; // stores whether a trainer has used gimmick
|
|
};
|
|
|
|
struct LostItem
|
|
{
|
|
u16 originalItem:15;
|
|
u16 stolen:1;
|
|
};
|
|
|
|
struct BattleVideo {
|
|
u32 battleTypeFlags;
|
|
rng_value_t rngSeed;
|
|
};
|
|
|
|
struct Wish
|
|
{
|
|
u16 counter;
|
|
u8 partyId;
|
|
};
|
|
|
|
struct FutureSight
|
|
{
|
|
u16 move;
|
|
u16 counter:10;
|
|
u16 battlerIndex:3;
|
|
u16 partyIndex:3;
|
|
};
|
|
|
|
struct BattlerState
|
|
{
|
|
u8 targetsDone[MAX_BATTLERS_COUNT];
|
|
|
|
u32 commandingDondozo:1;
|
|
u32 focusPunchBattlers:1;
|
|
u32 multipleSwitchInBattlers:1;
|
|
u32 alreadyStatusedMoveAttempt:1; // For example when using Thunder Wave on an already paralyzed Pokémon.
|
|
u32 activeAbilityPopUps:1;
|
|
u32 forcedSwitch:1;
|
|
u32 storedHealingWish:1;
|
|
u32 storedLunarDance:1;
|
|
u32 usedEjectItem:1;
|
|
u32 sleepClauseEffectExempt:1; // Stores whether effect should be exempt from triggering Sleep Clause (Effect Spore)
|
|
u32 usedMicleBerry:1;
|
|
u32 pursuitTarget:1;
|
|
u32 stompingTantrumTimer:2;
|
|
u32 canPickupItem:1;
|
|
u32 ateBoost:1;
|
|
u32 wasAboveHalfHp:1; // For Berserk, Emergency Exit, Wimp Out and Anger Shell.
|
|
u32 commanderSpecies:11;
|
|
u32 selectionScriptFinished:1;
|
|
u32 lastMoveTarget:3; // The last target on which each mon used a move, for the sake of Instruct
|
|
// End of Word
|
|
u16 hpOnSwitchout;
|
|
u16 switchIn:1;
|
|
u16 fainted:1;
|
|
u16 isFirstTurn:2;
|
|
u16 padding:12;
|
|
};
|
|
|
|
struct PartyState
|
|
{
|
|
u32 intrepidSwordBoost:1;
|
|
u32 dauntlessShieldBoost:1;
|
|
u32 ateBerry:1;
|
|
u32 battleBondBoost:1;
|
|
u32 transformZeroToHero:1;
|
|
u32 supersweetSyrup:1;
|
|
u32 timesGotHit:5;
|
|
u32 changedSpecies:11; // For forms when multiple mons can change into the same pokemon.
|
|
u32 sentOut:1;
|
|
u32 isKnockedOff:1;
|
|
u32 padding:8;
|
|
u16 usedHeldItem;
|
|
};
|
|
|
|
struct EventStates
|
|
{
|
|
enum EndTurnResolutionOrder endTurn:8;
|
|
u32 endTurnBlock:8; // FirstEventBlock, SecondEventBlock, ThirdEventBlock
|
|
enum BattlerId endTurnBattler:4;
|
|
u32 arenaTurn:8;
|
|
enum BattleSide battlerSide:4;
|
|
enum BattlerId moveEndBattler:4;
|
|
enum FirstTurnEventsStates beforeFirstTurn:8;
|
|
enum FaintedActions faintedAction:8;
|
|
enum BattlerId faintedActionBattler:4;
|
|
enum CancelerState atkCanceler:8;
|
|
enum BattlerId atkCancelerBattler:4;
|
|
enum BattleIntroStates battleIntro:8;
|
|
enum SwitchInEvents switchIn:8;
|
|
u32 battlerSwitchIn:8; // SwitchInFirstEventBlock, SwitchInSecondEventBlock
|
|
u32 moveEndBlock:8;
|
|
};
|
|
|
|
// Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise.
|
|
struct BattleStruct
|
|
{
|
|
struct BattlerState battlerState[MAX_BATTLERS_COUNT];
|
|
struct PartyState partyState[NUM_BATTLE_SIDES][PARTY_SIZE];
|
|
struct EventStates eventState;
|
|
struct FutureSight futureSight[MAX_BATTLERS_COUNT];
|
|
struct Wish wish[MAX_BATTLERS_COUNT];
|
|
u16 moveTarget[MAX_BATTLERS_COUNT];
|
|
u32 expShareExpValue;
|
|
u32 expValue;
|
|
u8 weatherDuration;
|
|
u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share
|
|
u8 expGetterMonId;
|
|
u8 expOrderId:3;
|
|
u8 expGetterBattlerId:2;
|
|
u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed.
|
|
u8 givenExpMons; // Bits for enemy party's pokemon that gave exp to player's party.
|
|
u8 expSentInMons; // As bits for player party mons - not including exp share mons.
|
|
u8 wildVictorySong;
|
|
enum Type dynamicMoveType;
|
|
enum BattlerId battlerPreventingSwitchout;
|
|
u8 moneyMultiplier:6;
|
|
u8 moneyMultiplierItem:1;
|
|
u8 moneyMultiplierMove:1;
|
|
u8 savedTurnActionNumber;
|
|
u8 scriptPartyIdx; // for printing the nickname
|
|
u8 battlerPartyIndexes[MAX_BATTLERS_COUNT];
|
|
u8 monToSwitchIntoId[MAX_BATTLERS_COUNT];
|
|
u8 battlerPartyOrders[MAX_BATTLERS_COUNT][PARTY_SIZE / 2];
|
|
u8 runTries;
|
|
u8 caughtMonNick[POKEMON_NAME_LENGTH + 1];
|
|
u8 safariGoNearCounter;
|
|
u8 safariPkblThrowCounter;
|
|
u8 safariEscapeFactor;
|
|
u8 safariCatchFactor;
|
|
u8 linkBattleVsSpriteId_V; // The letter "V"
|
|
u8 linkBattleVsSpriteId_S; // The letter "S"
|
|
u8 chosenMovePositions[MAX_BATTLERS_COUNT];
|
|
u8 stateIdAfterSelScript[MAX_BATTLERS_COUNT];
|
|
u8 prevSelectedPartySlot;
|
|
u8 stringMoveType;
|
|
u8 palaceFlags; // First 4 bits are "is <= 50% HP and not asleep" for each battler, last 4 bits are selected moves to pass to AI
|
|
u8 field_93; // related to choosing pokemon?
|
|
u8 wallyBattleState;
|
|
u8 wallyMovesState;
|
|
u8 wallyWaitFrames;
|
|
u8 wallyMoveFrames;
|
|
u16 lastTakenMove[MAX_BATTLERS_COUNT]; // Last move that a battler was hit with.
|
|
u32 savedBattleTypeFlags;
|
|
u16 abilityPreventingSwitchout;
|
|
u8 hpScale;
|
|
u16 synchronizeMoveEffect;
|
|
u8 anyMonHasTransformed:1; // Only used in battle_tv.c
|
|
u8 sleepClauseNotBlocked:1;
|
|
u8 isSkyBattle:1;
|
|
u8 unableToUseMove:1; // for the current action only, to check if the battler failed to act at end turn use the DisableStruct member
|
|
u8 triAttackBurn:1;
|
|
u8 unused:3;
|
|
void (*savedCallback)(void);
|
|
u16 chosenItem[MAX_BATTLERS_COUNT];
|
|
u16 choicedMove[MAX_BATTLERS_COUNT];
|
|
u8 switchInBattlerCounter;
|
|
u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker]
|
|
union {
|
|
struct LinkBattlerHeader linkBattlerHeader;
|
|
struct BattleVideo battleVideo;
|
|
} multiBuffer;
|
|
u8 battlerKOAnimsRunning:3;
|
|
u8 friskedAbility:1; // If identifies two mons, show the ability pop-up only once.
|
|
u8 fickleBeamBoosted:1;
|
|
u8 poisonPuppeteerConfusion:1;
|
|
u8 toxicChainPriority:1; // If Toxic Chain will trigger on target, all other non volatiles will be blocked
|
|
u8 battlersSorted:1; // To avoid unnessasery computation
|
|
struct BattleTvMovePoints tvMovePoints;
|
|
struct BattleTv tv;
|
|
u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT];
|
|
s8 arenaMindPoints[NUM_BATTLE_SIDES];
|
|
s8 arenaSkillPoints[NUM_BATTLE_SIDES];
|
|
u16 arenaStartHp[NUM_BATTLE_SIDES];
|
|
u8 arenaLostPlayerMons; // Bits for party member, lost as in referee's decision, not by fainting.
|
|
u8 arenaLostOpponentMons;
|
|
u8 debugBattler;
|
|
u8 magnitudeBasePower;
|
|
u8 presentBasePower;
|
|
u8 savedBattlerTarget[5];
|
|
u8 savedBattlerAttacker[5];
|
|
u8 savedTargetCount:4;
|
|
u8 savedAttackerCount:4;
|
|
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; // two per battler
|
|
struct ZMoveData zmove;
|
|
struct DynamaxData dynamax;
|
|
struct BattleGimmickData gimmick;
|
|
const u8 *trainerSlideMsg;
|
|
u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages
|
|
enum Ability tracedAbility[MAX_BATTLERS_COUNT];
|
|
struct Illusion illusion[MAX_BATTLERS_COUNT];
|
|
enum BattlerId soulheartBattlerId;
|
|
enum BattlerId friskedBattler; // Frisk needs to identify 2 battlers in double battles.
|
|
enum BattlerId quickClawBattlerId;
|
|
struct LostItem itemLost[NUM_BATTLE_SIDES][PARTY_SIZE]; // Pokemon that had items consumed or stolen (two bytes per party member per side)
|
|
u8 blunderPolicy:1; // should blunder policy activate
|
|
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
|
u8 bouncedMoveIsUsed:1;
|
|
u8 snatchedMoveIsUsed:1;
|
|
u8 descriptionSubmenu:1; // For Move Description window in move selection screen
|
|
u8 ackBallUseBtn:1; // Used for the last used ball feature
|
|
u8 ballSwapped:1; // Used for the last used ball feature
|
|
u8 throwingPokeBall:1;
|
|
u8 ballSpriteIds[2]; // item gfx, window gfx
|
|
u8 moveInfoSpriteId; // move info, window gfx
|
|
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
|
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
|
u16 beatUpSpecies[PARTY_SIZE]; // Species for Gen5+ Beat Up, otherwise party indexes
|
|
u8 attackerBeforeBounce:2;
|
|
u8 beatUpSlot:3;
|
|
u8 pledgeMove:1;
|
|
u8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects.
|
|
u8 padding3:1;
|
|
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
|
|
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
|
|
s32 aiDelayTimer; // Counts number of frames AI takes to choose an action.
|
|
s32 aiDelayFrames; // Number of frames it took to choose an action.
|
|
s32 aiDelayCycles; // Number of cycles it took to choose an action.
|
|
u8 supremeOverlordCounter[MAX_BATTLERS_COUNT];
|
|
u8 shellSideArmCategory[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT];
|
|
u8 speedTieBreaks; // MAX_BATTLERS_COUNT! values.
|
|
enum DamageCategory categoryOverride:8; // for Z-Moves and Max Moves
|
|
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
|
|
u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party
|
|
u16 opponentMonCanTera:6;
|
|
u16 opponentMonCanDynamax:6;
|
|
u16 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
|
|
u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch
|
|
s32 battlerExpReward;
|
|
u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn
|
|
s16 passiveHpUpdate[MAX_BATTLERS_COUNT]; // non-move damage and healing
|
|
s16 moveDamage[MAX_BATTLERS_COUNT];
|
|
u16 moveResultFlags[MAX_BATTLERS_COUNT];
|
|
enum CalcDamageState noResultString[MAX_BATTLERS_COUNT];
|
|
u8 doneDoublesSpreadHit:1;
|
|
u8 calculatedDamageDone:1;
|
|
u8 calculatedSpreadMoveAccuracy:1;
|
|
u8 printedStrongWindsWeakenedAttack:1;
|
|
u8 numSpreadTargets:3;
|
|
u8 moldBreakerActive:1;
|
|
struct MessageStatus slideMessageStatus;
|
|
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
|
|
u8 hazardsQueue[NUM_BATTLE_SIDES][HAZARDS_MAX_COUNT];
|
|
u8 numHazards[NUM_BATTLE_SIDES];
|
|
u8 hazardsCounter:4; // Counter for applying hazard on switch in
|
|
enum SubmoveState submoveAnnouncement:2;
|
|
u8 tryDestinyBond:1;
|
|
u8 tryGrudge:1;
|
|
u16 flingItem;
|
|
u8 incrementEchoedVoice:1;
|
|
u8 echoedVoiceCounter:3;
|
|
u8 attackAnimPlayed:1;
|
|
u8 preAttackEffectHappened:1;
|
|
u8 magicCoatActive:1;
|
|
u8 magicBounceActive:1;
|
|
u8 moveBouncer;
|
|
u8 dancerSavedAttacker:3;
|
|
u8 dancerSavedTarget:3;
|
|
u8 padding:2;
|
|
};
|
|
|
|
struct AiBattleData
|
|
{
|
|
s32 finalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier
|
|
u8 playerStallMons[PARTY_SIZE];
|
|
u8 chosenMoveIndex[MAX_BATTLERS_COUNT];
|
|
u8 chosenTarget[MAX_BATTLERS_COUNT];
|
|
u16 aiUsingGimmick:6;
|
|
u8 actionFlee:1;
|
|
u8 choiceWatch:1;
|
|
u8 padding:6;
|
|
};
|
|
|
|
// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,
|
|
// and 1 flag per battler to indicate whether the battler is awake and at <= 50% HP (which affects move choice).
|
|
// The assert below is to ensure palaceFlags is large enough to store these flags without overlap.
|
|
STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLERS_COUNT + MAX_MON_MOVES, PalaceFlagsTooSmall)
|
|
|
|
#define DYNAMIC_TYPE_MASK ((1 << 6) - 1)
|
|
#define F_DYNAMIC_TYPE_IGNORE_PHYSICALITY (1 << 6) // If set, the dynamic type's physicality won't be used for certain move effects.
|
|
#define F_DYNAMIC_TYPE_SET (1 << 7) // Set for all dynamic types to distinguish a dynamic type of Normal (0) from no dynamic type.
|
|
|
|
static inline bool32 IsBattleMovePhysical(enum Move move)
|
|
{
|
|
return GetBattleMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL;
|
|
}
|
|
|
|
static inline bool32 IsBattleMoveSpecial(enum Move move)
|
|
{
|
|
return GetBattleMoveCategory(move) == DAMAGE_CATEGORY_SPECIAL;
|
|
}
|
|
|
|
static inline bool32 IsBattleMoveStatus(enum Move move)
|
|
{
|
|
return GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS;
|
|
}
|
|
|
|
/* Checks if 'battler' is any of the types.
|
|
* Passing multiple types is more efficient than calling this multiple
|
|
* times with one type because it shares the 'GetBattlerTypes' result. */
|
|
#define _IS_BATTLER_ANY_TYPE(battler, ignoreTera, ...) \
|
|
({ \
|
|
enum Type types[3]; \
|
|
GetBattlerTypes(battler, ignoreTera, types); \
|
|
RECURSIVELY(R_FOR_EACH(_IS_BATTLER_ANY_TYPE_HELPER, __VA_ARGS__)) FALSE; \
|
|
})
|
|
|
|
#define _IS_BATTLER_ANY_TYPE_HELPER(type) (types[0] == type) || (types[1] == type) || (types[2] == type) ||
|
|
|
|
#define IS_BATTLER_ANY_TYPE(battler, ...) _IS_BATTLER_ANY_TYPE(battler, FALSE, __VA_ARGS__)
|
|
#define IS_BATTLER_OF_TYPE IS_BATTLER_ANY_TYPE
|
|
#define IS_BATTLER_ANY_BASE_TYPE(battler, ...) _IS_BATTLER_ANY_TYPE(battler, TRUE, __VA_ARGS__)
|
|
#define IS_BATTLER_OF_BASE_TYPE IS_BATTLER_ANY_BASE_TYPE
|
|
|
|
#define IS_BATTLER_TYPELESS(battlerId) \
|
|
({ \
|
|
enum Type types[3]; \
|
|
GetBattlerTypes(battlerId, FALSE, types); \
|
|
types[0] == TYPE_MYSTERY && types[1] == TYPE_MYSTERY && types[2] == TYPE_MYSTERY; \
|
|
})
|
|
|
|
#define SET_BATTLER_TYPE(battler, type) \
|
|
{ \
|
|
gBattleMons[battler].types[0] = type; \
|
|
gBattleMons[battler].types[1] = type; \
|
|
gBattleMons[battler].types[2] = TYPE_MYSTERY; \
|
|
}
|
|
|
|
#define RESTORE_BATTLER_TYPE(battler) \
|
|
{ \
|
|
gBattleMons[battler].types[0] = GetSpeciesType(gBattleMons[battler].species, 0); \
|
|
gBattleMons[battler].types[1] = GetSpeciesType(gBattleMons[battler].species, 1); \
|
|
gBattleMons[battler].types[2] = TYPE_MYSTERY; \
|
|
}
|
|
|
|
#define GET_STAT_BUFF_ID(n) ((n & 7)) // first three bits 0x1, 0x2, 0x4
|
|
#define GET_STAT_BUFF_VALUE_WITH_SIGN(n) ((n & 0xF8))
|
|
#define GET_STAT_BUFF_VALUE(n) (((n >> 3) & 0xF)) // 0x8, 0x10, 0x20, 0x40
|
|
#define STAT_BUFF_NEGATIVE 0x80 // 0x80, the sign bit
|
|
|
|
#define SET_STAT_BUFF_VALUE(n) ((((n) << 3) & 0xF8))
|
|
|
|
#define SET_STATCHANGER(statId, stage, goesDown) (gBattleScripting.statChanger = (statId) + ((stage) << 3) + (goesDown << 7))
|
|
#define SET_STATCHANGER2(dst, statId, stage, goesDown)(dst = (statId) + ((stage) << 3) + (goesDown << 7))
|
|
|
|
// NOTE: The members of this struct have hard-coded offsets
|
|
// in include/constants/battle_script_commands.h
|
|
struct BattleScripting
|
|
{
|
|
s32 unused1;
|
|
s32 bideDmg;
|
|
u8 multihitString[6];
|
|
bool8 expOnCatch;
|
|
u8 unused2;
|
|
u8 animArg1;
|
|
u8 animArg2;
|
|
u16 savedStringId;
|
|
u8 moveendState;
|
|
u8 savedStatChanger; // For further use, if attempting to change stat two times(ex. Moody)
|
|
u8 shiftSwitched; // When the game tells you the next enemy's pokemon and you switch. Option for noobs but oh well.
|
|
enum BattlerId battler;
|
|
u8 animTurn;
|
|
u8 animTargetsHit;
|
|
u8 statChanger;
|
|
bool8 statAnimPlayed;
|
|
u8 getexpState;
|
|
u8 battleStyle;
|
|
u8 drawlvlupboxState;
|
|
u8 learnMoveState;
|
|
u8 savedBattler;
|
|
u8 reshowMainState;
|
|
u8 reshowHelperState;
|
|
u8 levelUpHP;
|
|
u8 windowsType; // B_WIN_TYPE_*
|
|
u8 multiplayerId;
|
|
u8 specialTrainerBattleType;
|
|
bool8 monCaught;
|
|
s32 savedDmg;
|
|
u16 unused_0x2c;
|
|
u16 moveEffect;
|
|
u16 unused_0x30;
|
|
u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN.
|
|
bool8 fixedPopup; // Force ability popup to stick until manually called back
|
|
u16 abilityPopupOverwrite;
|
|
u8 switchCase; // Special switching conditions, eg. red card
|
|
u8 overrideBerryRequirements;
|
|
u8 stickyWebStatDrop; // To prevent Defiant activating on a Court Change'd Sticky Web
|
|
};
|
|
|
|
struct BattleSpriteInfo
|
|
{
|
|
u16 invisible:1; // 0x1
|
|
u16 lowHpSong:1; // 0x2
|
|
u16 behindSubstitute:1; // 0x4
|
|
u16 flag_x8:1; // 0x8
|
|
u16 hpNumbersNoBars:1; // 0x10
|
|
u16 transformSpecies;
|
|
};
|
|
|
|
struct BattleAnimationInfo
|
|
{
|
|
u16 animArg; // to fill up later
|
|
u8 field_2;
|
|
u8 field_3;
|
|
u8 field_4;
|
|
u8 field_5;
|
|
u8 field_6;
|
|
u8 field_7;
|
|
u8 ballThrowCaseId:6;
|
|
u8 isCriticalCapture:1;
|
|
u8 criticalCaptureSuccess:1;
|
|
u8 introAnimActive:1;
|
|
u8 wildMonInvisible:1;
|
|
u8 field_9_x1C:3;
|
|
u8 field_9_x20:1;
|
|
u8 field_9_x40:1;
|
|
u8 field_9_x80:1;
|
|
u8 numBallParticles;
|
|
u8 field_B;
|
|
s16 ballSubpx;
|
|
u8 field_E;
|
|
u8 field_F;
|
|
};
|
|
|
|
struct BattleHealthboxInfo
|
|
{
|
|
u8 partyStatusSummaryShown:1;
|
|
u8 healthboxIsBouncing:1;
|
|
u8 battlerIsBouncing:1;
|
|
u8 ballAnimActive:1; // 0x8
|
|
u8 statusAnimActive:1; // x10
|
|
u8 animFromTableActive:1; // x20
|
|
u8 specialAnimActive:1; // x40
|
|
u8 triedShinyMonAnim:1;
|
|
u8 finishedShinyMonAnim:1;
|
|
u8 opponentDrawPartyStatusSummaryDelay:4;
|
|
u8 bgmRestored:1;
|
|
u8 waitForCry:1;
|
|
u8 healthboxSlideInStarted:1;
|
|
u8 healthboxBounceSpriteId;
|
|
u8 battlerBounceSpriteId;
|
|
u8 animationState;
|
|
u8 partyStatusDelayTimer;
|
|
u8 matrixNum;
|
|
|
|
u8 shadowSpriteIdPrimary;
|
|
u8 shadowSpriteIdSecondary;
|
|
|
|
u8 soundTimer;
|
|
u8 introEndDelay;
|
|
u8 field_A;
|
|
u8 field_B;
|
|
};
|
|
|
|
struct BattleBarInfo
|
|
{
|
|
u8 healthboxSpriteId;
|
|
s32 maxValue;
|
|
s32 oldValue;
|
|
s32 receivedValue;
|
|
s32 currValue;
|
|
};
|
|
|
|
struct BattleSpriteData
|
|
{
|
|
struct BattleSpriteInfo *battlerData;
|
|
struct BattleHealthboxInfo *healthBoxesData;
|
|
struct BattleAnimationInfo *animationData;
|
|
struct BattleBarInfo *battleBars;
|
|
};
|
|
|
|
#include "sprite.h"
|
|
|
|
struct MonSpritesGfx
|
|
{
|
|
void *firstDecompressed; // ptr to the decompressed sprite of the first Pokémon
|
|
u8 *spritesGfx[MAX_BATTLERS_COUNT];
|
|
struct SpriteTemplate templates[MAX_BATTLERS_COUNT];
|
|
struct SpriteFrameImage frameImages[MAX_BATTLERS_COUNT][MAX_MON_PIC_FRAMES];
|
|
u8 *barFontGfx;
|
|
u16 *buffer;
|
|
};
|
|
|
|
struct QueuedStatBoost
|
|
{
|
|
u8 stats; // bitfield for each battle stat that is set if the stat changes
|
|
s8 statChanges[NUM_BATTLE_STATS - 1]; // highest bit being set decreases the stat
|
|
}; /* size = 8 */
|
|
|
|
// All battle variables are declared in battle_main.c
|
|
extern u16 gBattle_BG0_X;
|
|
extern u16 gBattle_BG0_Y;
|
|
extern u16 gBattle_BG1_X;
|
|
extern u16 gBattle_BG1_Y;
|
|
extern u16 gBattle_BG2_X;
|
|
extern u16 gBattle_BG2_Y;
|
|
extern u16 gBattle_BG3_X;
|
|
extern u16 gBattle_BG3_Y;
|
|
extern u16 gBattle_WIN0H;
|
|
extern u16 gBattle_WIN0V;
|
|
extern u16 gBattle_WIN1H;
|
|
extern u16 gBattle_WIN1V;
|
|
extern u8 gDisplayedStringBattle[425];
|
|
extern u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT];
|
|
extern u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT];
|
|
extern u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT + 13]; //to handle stupidly large z move names
|
|
extern u32 gBattleTypeFlags;
|
|
extern u8 gBattleEnvironment;
|
|
extern u8 *gBattleAnimBgTileBuffer;
|
|
extern u8 *gBattleAnimBgTilemapBuffer;
|
|
extern u32 gBattleControllerExecFlags;
|
|
extern u8 gBattlersCount;
|
|
extern u16 gBattlerPartyIndexes[MAX_BATTLERS_COUNT];
|
|
extern u8 gBattlerPositions[MAX_BATTLERS_COUNT];
|
|
extern u8 gActionsByTurnOrder[MAX_BATTLERS_COUNT];
|
|
extern enum BattlerId gBattlerByTurnOrder[MAX_BATTLERS_COUNT];
|
|
extern enum BattlerId gBattlersBySpeed[MAX_BATTLERS_COUNT];
|
|
extern u8 gCurrentTurnActionNumber;
|
|
extern u8 gCurrentActionFuncId;
|
|
extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT];
|
|
extern u8 gBattlerSpriteIds[MAX_BATTLERS_COUNT];
|
|
extern u8 gCurrMovePos;
|
|
extern u8 gChosenMovePos;
|
|
extern u16 gCurrentMove;
|
|
extern u16 gChosenMove;
|
|
extern u16 gCalledMove;
|
|
extern s32 gBideDmg[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastUsedItem;
|
|
extern enum Ability gLastUsedAbility;
|
|
extern enum BattlerId gBattlerAttacker;
|
|
extern enum BattlerId gBattlerTarget;
|
|
extern enum BattlerId gBattlerFainted;
|
|
extern enum BattlerId gEffectBattler;
|
|
extern enum BattlerId gPotentialItemEffectBattler;
|
|
extern u8 gAbsentBattlerFlags;
|
|
extern u8 gMultiHitCounter;
|
|
extern const u8 *gBattlescriptCurrInstr;
|
|
extern u8 gChosenActionByBattler[MAX_BATTLERS_COUNT];
|
|
extern const u8 *gSelectionBattleScripts[MAX_BATTLERS_COUNT];
|
|
extern const u8 *gPalaceSelectionBattleScripts[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastPrintedMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastLandedMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastHitByType[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastUsedMoveType[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastResultingMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gLockedMoves[MAX_BATTLERS_COUNT];
|
|
extern u16 gLastUsedMove;
|
|
extern u8 gLastHitBy[MAX_BATTLERS_COUNT];
|
|
extern u16 gChosenMoveByBattler[MAX_BATTLERS_COUNT];
|
|
extern u32 gHitMarker;
|
|
extern u8 gBideTarget[MAX_BATTLERS_COUNT];
|
|
extern u32 gSideStatuses[NUM_BATTLE_SIDES];
|
|
extern struct SideTimer gSideTimers[NUM_BATTLE_SIDES];
|
|
extern u16 gPauseCounterBattle;
|
|
extern u16 gPaydayMoney;
|
|
extern u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT];
|
|
extern u8 gBattleOutcome;
|
|
extern struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT];
|
|
extern struct SpecialStatus gSpecialStatuses[MAX_BATTLERS_COUNT];
|
|
extern u16 gBattleWeather;
|
|
extern u16 gIntroSlideFlags;
|
|
extern u8 gSentPokesToOpponent[2];
|
|
extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT];
|
|
extern struct BattleScripting gBattleScripting;
|
|
extern struct BattleStruct *gBattleStruct;
|
|
extern struct StartingStatuses gStartingStatuses;
|
|
extern struct AiBattleData *gAiBattleData;
|
|
extern struct AiThinkingStruct *gAiThinkingStruct;
|
|
extern struct AiLogicData *gAiLogicData;
|
|
extern struct AiPartyData *gAiPartyData;
|
|
extern struct BattleHistory *gBattleHistory;
|
|
extern u8 *gLinkBattleSendBuffer;
|
|
extern u8 *gLinkBattleRecvBuffer;
|
|
extern struct BattleResources *gBattleResources;
|
|
extern u8 gActionSelectionCursor[MAX_BATTLERS_COUNT];
|
|
extern u8 gMoveSelectionCursor[MAX_BATTLERS_COUNT];
|
|
extern u8 gBattlerStatusSummaryTaskId[MAX_BATTLERS_COUNT];
|
|
extern u8 gBattlerInMenuId;
|
|
extern bool8 gDoingBattleAnim;
|
|
extern u32 gTransformedPersonalities[MAX_BATTLERS_COUNT];
|
|
extern bool8 gTransformedShininess[MAX_BATTLERS_COUNT];
|
|
extern u8 gPlayerDpadHoldFrames;
|
|
extern struct BattleSpriteData *gBattleSpritesDataPtr;
|
|
extern struct MonSpritesGfx *gMonSpritesGfxPtr;
|
|
extern u16 gBattleMovePower;
|
|
extern u16 gMoveToLearn;
|
|
extern u32 gFieldStatuses;
|
|
extern struct FieldTimer gFieldTimers;
|
|
extern u16 gBattleTurnCounter;
|
|
extern enum BattlerId gBattlerAbility;
|
|
extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT];
|
|
|
|
extern MainCallback gPreBattleCallback1;
|
|
extern void (*gBattleMainFunc)(void);
|
|
extern struct BattleResults gBattleResults;
|
|
extern u8 gLeveledUpInBattle;
|
|
extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
|
|
extern u8 gMultiUsePlayerCursor;
|
|
extern u8 gNumberOfMovesToChoose;
|
|
extern bool8 gHasFetchedBall;
|
|
extern u16 gLastUsedBall;
|
|
extern u16 gLastThrownBall;
|
|
extern u16 gBallToDisplay;
|
|
extern bool8 gLastUsedBallMenuPresent;
|
|
extern u8 gPartyCriticalHits[PARTY_SIZE];
|
|
extern u8 gCategoryIconSpriteId;
|
|
|
|
static inline bool32 IsBattlerAlive(enum BattlerId battler)
|
|
{
|
|
if (battler >= gBattlersCount)
|
|
return FALSE;
|
|
else if (gBattleMons[battler].hp == 0)
|
|
return FALSE;
|
|
else if (gAbsentBattlerFlags & (1u << battler))
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
enum SubCheck
|
|
{
|
|
EXCLUDING_SUBSTITUTES,
|
|
INCLUDING_SUBSTITUTES
|
|
};
|
|
|
|
static inline bool32 IsBattlerTurnDamaged(enum BattlerId battler, enum SubCheck subCheck)
|
|
{
|
|
return gSpecialStatuses[battler].damagedByAttack || ((subCheck == INCLUDING_SUBSTITUTES) && gBattleStruct->moveDamage[battler] > 0);
|
|
}
|
|
|
|
static inline bool32 IsBattlerAtMaxHp(enum BattlerId battler)
|
|
{
|
|
return gBattleMons[battler].hp == gBattleMons[battler].maxHP;
|
|
}
|
|
|
|
static inline enum BattlerPosition GetBattlerPosition(enum BattlerId battler)
|
|
{
|
|
return gBattlerPositions[battler];
|
|
}
|
|
|
|
static inline enum BattlerId GetBattlerAtPosition(enum BattlerPosition position)
|
|
{
|
|
enum BattlerId battler;
|
|
for (battler = 0; battler < gBattlersCount; battler++)
|
|
{
|
|
if (GetBattlerPosition(battler) == position)
|
|
break;
|
|
}
|
|
return battler;
|
|
}
|
|
|
|
static inline u32 GetPartnerBattler(enum BattlerId battler)
|
|
{
|
|
return GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)));
|
|
}
|
|
|
|
static inline u32 GetOppositeBattler(enum BattlerId battler)
|
|
{
|
|
return GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler)));
|
|
}
|
|
|
|
static inline u32 GetBattlerSide(enum BattlerId battler)
|
|
{
|
|
return GetBattlerPosition(battler) & BIT_SIDE;
|
|
}
|
|
|
|
static inline bool32 IsOnPlayerSide(enum BattlerId battler)
|
|
{
|
|
return GetBattlerSide(battler) == B_SIDE_PLAYER;
|
|
}
|
|
|
|
static inline bool32 IsBattlerAlly(enum BattlerId battlerAtk, enum BattlerId battlerDef)
|
|
{
|
|
return GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef);
|
|
}
|
|
|
|
static inline u32 GetOpposingSideBattler(enum BattlerId battler)
|
|
{
|
|
return GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerSide(battler)));
|
|
}
|
|
|
|
static inline struct Pokemon* GetBattlerMon(enum BattlerId battler)
|
|
{
|
|
u32 index = gBattlerPartyIndexes[battler];
|
|
return !IsOnPlayerSide(battler) ? &gEnemyParty[index] : &gPlayerParty[index];
|
|
}
|
|
|
|
static inline struct Pokemon *GetSideParty(enum BattleSide side)
|
|
{
|
|
return side == B_SIDE_PLAYER ? gPlayerParty : gEnemyParty;
|
|
}
|
|
|
|
static inline struct Pokemon *GetBattlerParty(enum BattlerId battler)
|
|
{
|
|
return GetSideParty(GetBattlerSide(battler));
|
|
}
|
|
|
|
static inline struct PartyState *GetBattlerPartyState(enum BattlerId battler)
|
|
{
|
|
return &gBattleStruct->partyState[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]];
|
|
}
|
|
|
|
static inline bool32 IsDoubleBattle(void)
|
|
{
|
|
return !!(gBattleTypeFlags & BATTLE_TYPE_MORE_THAN_TWO_BATTLERS);
|
|
}
|
|
|
|
static inline bool32 IsSpreadMove(enum MoveTarget moveTarget)
|
|
{
|
|
if (!IsDoubleBattle())
|
|
return FALSE;
|
|
return moveTarget == TARGET_BOTH || moveTarget == TARGET_FOES_AND_ALLY;
|
|
}
|
|
|
|
static inline u32 GetBattlerChosenMove(enum BattlerId battler)
|
|
{
|
|
return gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
|
|
}
|
|
|
|
static inline void SetPassiveDamageAmount(enum BattlerId battler, s32 value)
|
|
{
|
|
if (value == 0)
|
|
value = 1;
|
|
gBattleStruct->passiveHpUpdate[battler] = value;
|
|
}
|
|
|
|
static inline void SetHealAmount(enum BattlerId battler, s32 value)
|
|
{
|
|
if (value == 0)
|
|
value = 1;
|
|
gBattleStruct->passiveHpUpdate[battler] = -1 * value;
|
|
}
|
|
|
|
static inline bool32 IsGhostBattleWithoutScope(void)
|
|
{
|
|
return (gBattleTypeFlags & BATTLE_TYPE_GHOST) && !CheckBagHasItem(ITEM_SILPH_SCOPE, 1);
|
|
}
|
|
|
|
#endif // GUARD_BATTLE_H
|