pokeplatinum/include/battle/battle_lib.h
2024-07-06 14:40:34 -07:00

1489 lines
49 KiB
C

#ifndef POKEPLATINUM_BATTLE_BATTLE_LIB_H
#define POKEPLATINUM_BATTLE_BATTLE_LIB_H
#include "constants/battle.h"
#include "constants/sound.h"
#include "struct_decls/battle_system.h"
#include "battle/battle_context.h"
#include "battle/battle_message.h"
#include "battle/battle_mon.h"
#include "battle/btlcmd.h"
#include "pokemon.h"
enum CountAbilityMode {
COUNT_ALL_BATTLERS_OUR_SIDE = 0, //< Count all the battlers on our side with the ability
COUNT_ALIVE_BATTLERS_OUR_SIDE, //< Count all alive battlers on our side with the ability
COUNT_ALL_BATTLERS_THEIR_SIDE, //< Count all the battlers on their side with the ability
COUNT_ALIVE_BATTLERS_THEIR_SIDE, //< Count all alive battlers on their side with the ability
COUNT_ALIVE_BATTLERS_THEIR_SIDE_FLAG, //< Return a mask of alive battlers on their side with the ability
COUNT_ALL_BATTLERS, //< Count all battlers on the battlefield with the ability
COUNT_ALL_BATTLERS_EXCEPT_ME, //< Count all battlers except for me which have the ability
COUNT_ALL_BATTLERS_EXCEPT_ME_RETURN_BATTLER, //< Return the battler which has the ability
COUNT_ALIVE_BATTLERS, //< Count all alive battlers on the battlefield with the ability
COUNT_ALIVE_BATTLERS_EXCEPT_ME, //< Count all alive battlers except for me which have the ability
};
/**
* @brief Initialize a BattleMon from the Pokemon in the given battler's party,
* from the given party slot.
*
* @param battleSys
* @param battleCtx
* @param battler The battler whose party will be read from
* @param partySlot The slot in the party to retrieve
*/
void BattleSystem_InitBattleMon(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int partySlot);
/**
* @brief Reload a BattleMon from the given battler's party, from the given
* party slot.
*
* Specifically, this will only reload the following fields:
*
* - battle stats (attack, defense, etc.)
* - level
* - friendship
* - move known in each slot
* - total experience
*
* @param battleSys
* @param battleCtx
* @param battler The battler whose party will be read from
* @param partySlot The slot in the party to retrieve
*/
void BattleSystem_ReloadPokemon(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int partySlot);
/**
* @brief Load a script file from the specified NARC.
*
* @param battleCtx
* @param narc Which NARC to open for the script
* @param file Which file in the NARC to load
*/
void BattleSystem_LoadScript(BattleContext *battleCtx, int narc, int file);
/**
* @brief Load a script file from the specified NARC and invoke it as a call,
* returning to the previous script once finished processing.
*
* @param battleCtx
* @param narc Which NARC to open for the script
* @param file Which file in the NARC to load
*/
void BattleSystem_CallScript(BattleContext *battleCtx, int narc, int file);
/**
* @brief Pop a script from the stack, if one is present, and load it for
* execution.
*
* If a script is loaded, then this will also pop a value from the script cursor
* stack and set the internal script cursor to that value.
*
* @param battleCtx
* @return TRUE if there are no contents in the stack to be loaded; FALSE if
* a stack was popped and should be executed.
*/
BOOL BattleSystem_PopScript(BattleContext *battleCtx);
/**
* @brief Enqueue a value onto the given IO queue for the battler.
*
* @param battleCtx
* @param id ID of the queue to enqueue the value onto
* @param battler Battler for which the value should be enqueued
* @param val Value which will be enqueued
*/
void BattleIO_EnqueueVal(BattleContext *battleCtx, int id, int battler, int val);
/**
* @brief Dequeue a specific value from the given IO queue for the battler.
*
* @param battleCtx
* @param id ID of the queue to dequeue the value from
* @param battler Battler for which the value should be dequeued
* @param val Value which will be dequeued
*/
void BattleIO_DequeueVal(BattleContext *battleCtx, int id, int battler, int val);
/**
* @brief Determine if the Battle IO queue is empty (i.e., there are no pending
* actions to be executed for any players hooked into this particular battle).
*
* As a side effect, if the queue is empty, then this routine will also set the
* link-battle timeout counter back to 0.
*
* @param battleCtx
* @return TRUE if the queue has no remaining actions; FALSE otherwise.
*/
BOOL BattleIO_QueueIsEmpty(BattleContext *battleCtx);
/**
* @brief Increments the link-battle timeout counter.
*
* If the counter exceeds the maximum timeout value (1800, ~= 30 seconds),
* then the link will be terminated with an error state.
*
* @param battleCtx
*/
void BattleIO_UpdateTimeout(BattleContext *battleCtx);
/**
* @brief Clear the battle IO queue of all data.
*
* @param battleCtx
* @param battler
*/
void BattleIO_ClearBuffer(BattleContext *battleCtx, int battler);
/**
* @brief Get a data field value from a given battler.
*
* @param battleCtx
* @param battler The requested battler
* @param paramID ID of the field to retrieve from the battler
* @param[out] outBuf Buffer output for non-integral values (i.e., strings)
* @return The value of the data field, or 0 if not recognized or output is
* presented via outBuf
*/
int BattleMon_Get(BattleContext *battleCtx, int battler, enum BattleMonParam paramID, void *buf);
/**
* @brief Set a data field value for a given battler.
*
* @param battleCtx
* @param battler The requested battler
* @param paramID ID of the field to retrieve from the battler
* @param buf Buffer input for the value to be set
*/
void BattleMon_Set(BattleContext *battleCtx, int battler, enum BattleMonParam paramID, const void *buf);
/**
* @brief Add a value to a battler's data field.
*
* This is just a convenience wrapper around BattleMon_AddVal.
*
* @param battleCtx
* @param battler The battler whose data should be modified
* @param paramID ID of the field which should be modified
* @param val Value to be added to the battler's data field
*/
void Battler_AddVal(BattleContext *battleCtx, int battler, enum BattleMonParam paramID, int val);
/**
* @brief Add a value to a Pokemon's data field.
*
* @param mon
* @param paramID ID of the field which should be modified
* @param val Value to be added to the Pokemon's data field
*/
void BattleMon_AddVal(BattleMon *mon, enum BattleMonParam paramID, int val);
/**
* @brief Compare the speed of two battlers and determine which of them should
* move first.
*
* @param battleSys
* @param battleCtx
* @param battler1
* @param battler2
* @param ignoreQuickClaw If set to TRUE, the Quick Claw and Custap Berry
* flags will NOT be set after determining if they
* should activate.
* @return A value representing the speed-ordering of the two battlers,
* relative to the first of the two. See enum CompareSpeedResult.
*/
u8 BattleSystem_CompareBattlerSpeed(BattleSystem *battleSys, BattleContext *battleCtx, int battler1, int battler2, BOOL ignoreQuickClaw);
/**
* @brief Clear the flag denoting that a battler (or its partner) are due to
* gain experience.
*
* @param battleCtx
* @param battler The battler who should not gain experience.
*/
void BattleSystem_ClearSideExpGain(BattleContext *battleCtx, int battler);
/**
* @brief Flag a given battler as due to gain experience.
*
* If the battle involves an AI partner, then this routine will not touch the
* flag for the opposing side of the battle.
*
* @param battleSys
* @param battleCtx
* @param battler The battler who should gain experience.
*/
void BattleSystem_FlagBattlerExpGain(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Trigger a primary effect on the current move.
*
* @param battleSys
* @param battleCtx
* @param[out] effect Output parameter for the effect to be loaded.
* @return TRUE if an effect should be loaded, FALSE if the result should be
* ignored.
*/
BOOL BattleSystem_TriggerPrimaryEffect(BattleSystem *battleSys, BattleContext *battleCtx, int *effect);
/**
* @brief Trigger a secondary effect on the current move.
*
* @param battleSys
* @param battleCtx
* @param[out] effect Output parameter for the effect to be loaded.
* @return TRUE if an effect should be loaded, FALSE if the result should be
* ignored.
*/
BOOL BattleSystem_TriggerSecondaryEffect(BattleSystem *battleSys, BattleContext *battleCtx, int *effect);
/**
* @brief Find the defender for the move.
*
* The defender can be chosen at random in certain scenarios, but only while
* the randomize parameter is TRUE:
*
* 1. The move's range is Me First
* 2. The move's range is Acupressure
* 3. The move is a standard single-target attack, e.g., Thunderbolt
*
* @param battleSys
* @param battleCtx
* @param attacker
* @param move The move being used
* @param randomize If TRUE, permit randomization of target-selection for certain moves
* @param inRange An input range to prefer for the move over whatever range is set on the move data
* @return The chosen defender for the move
*/
int BattleSystem_Defender(BattleSystem *battleSys, BattleContext *battleCtx, int attacker, u16 move, BOOL randomize, int inRange);
/**
* @brief Check for redirection abilities given an attacker using a certain move.
*
* This routine will update the appropriate flags and the current target if the
* used move is Electric- or Water-type, has single-target range, and at least
* one other battler on the field has Lightning Rod or Storm Drain, respectively.
*
* @param battleSys
* @param battleCtx
* @param attacker
* @param move
*/
void BattleSystem_CheckRedirectionAbilities(BattleSystem *battleSys, BattleContext *battleCtx, int attacker, u16 move);
/**
* @brief Trigger a redirection ability's effect and load the appropriate
* subscript for execution.
*
* @param battleSys
* @param battleCtx
* @return TRUE if a subscript was loaded and should be executed for the effect,
* FALSE otherwise.
*/
BOOL BattleSystem_TriggerRedirectionAbilities(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Copy the given battler back to its backing Pokemon structure in the party.
*
* @param battleSys
* @param battleCtx
* @param battler
*/
void BattleMon_CopyToParty(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Locks the battler into their current move.
*
* @param battleSys
* @param battleCtx
* @param battler
*/
void Battler_LockMoveChoice(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Unlocks the battler's future move choices.
*
* This will also, as a convenience, toggle off the flags for Bide and semi-
* invulnerable moves and reset the counters for Rollout and Fury Cutter.
*
* @param battleSys
* @param battleCtx
* @param battler
*/
void Battler_UnlockMoveChoice(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Calculate the status effect value for a battler's non-volatile
* condition, if any.
*
* @param battleCtx
* @param battler
* @return A value representing the battler's status non-volatile status.
*/
enum BattleAnimation Battler_StatusCondition(BattleContext *battleCtx, int battler);
/**
* @brief Check if the given trainer has a trainer message to be shown.
*
* If a trainer message is to be shown, then the respective battler will be
* updated with the appropriate flag, and battleCtx->msgTemp will be loaded
* with the type of message to be shown.
*
* @param battleSys
* @param battleCtx
* @return TRUE if a message should be shown, else FALSE.
*/
BOOL BattleSystem_CheckTrainerMessage(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Initialize the BattleContext structure with start-of-turn state.
*
* @param battleCtx
*/
void BattleContext_Init(BattleContext *battleCtx);
/**
* @brief Initialize standard counters for the BattleContext structure.
*
* @param battleSys
* @param battleCtx
*/
void BattleContext_InitCounters(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Update relevant buffers for a battler after a switch.
*
* This handles all of the logic for what effects are zero'd out due to a
* switch, as well as what effects are transferred across a switch due to
* Baton Pass.
*
* This routine will update the battler's chosen command to be MOVE_END, which
* functionally ends their turn.
*
* @param battleSys
* @param battleCtx
* @param battler The switching battler
*/
void BattleSystem_UpdateAfterSwitch(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Cleanup lingering state according to the given battler.
*
* This routine will clean up any volatile status values dependent on the
* fainted battler (Mean Look, Attract, Bind), all move effects and single-turn
* flags, and extra data associated with the battler that is elsewhere in the
* battle context struct (e.g., buffers for Conversion 2, Sketch, and Mirror
* Move).
*
* @param battleSys
* @param battleCtx
* @param battler
*/
void BattleSystem_CleanupFaintedMon(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Clear single-turn flags and buffered values in setup for the next turn.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_SetupNextTurn(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Compute which moves are invalid for the battler to use, performing
* checks according to the input opcode mask.
*
* The following op-codes are supported in the input mask:
* - CHECK_INVALID_NO_MOVE -> flag empty move-slots
* - CHECK_INVALID_NO_PP -> flag moves with no remaining PP
* - CHECK_INVALID_DISABLED -> flag the battler's Disabled move
* - CHECK_INVALID_TORMENTED -> flag the battler's last-used move
* - CHECK_INVALID_TAUNTED -> flag any of the battler's moves with 0 power
* - CHECK_INVALID_IMPRISONED -> flag any of the battler's Imprisoned moves
* - CHECK_INVALID_GRAVITY -> flag any of the battler's moves which fail in high gravity
* - CHECK_INVALID_HEAL_BLOCK -> flag any of the battler's healing moves
* - CHECK_INVALID_CHOICE_ITEM -> flag any of the battler's moves other than their choice-locked move
*
* @param battleSys
* @param battleCtx
* @param battler The battler choosing their move
* @param invalidMoves An initial mask of moves which should be deemed invalid
* @param opMask An input opcode mask determining which checks should be
* made for move validity
* @return A bitmask denoting which of the battler's move slots are invalid for
* selection
*/
int BattleSystem_CheckInvalidMoves(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int invalidMoves, int opMask);
/**
* @brief Determine if a battler can use the move in the given slot, populating
* the input BattleMessage struct with a message to display if they cannot.
*
* @param battleSys
* @param battleCtx
* @param battler
* @param moveSlot The slot of the move that the battler is trying to use
* @param[out] msgOut An output message for display to the player
* @return TRUE if the move can be used, FALSE if it cannot
*/
BOOL BattleSystem_CanUseMove(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int moveSlot, BattleMessage *msgOut);
/**
* @brief Determine which slot of the Pokemon's moveset contains a given move.
*
* @param mon
* @param move
* @return The slot of the Pokemon's moveset containing the input move
*/
int Battler_SlotForMove(BattleMon *mon, u16 move);
/**
* @brief Apply type-chart effectiveness for a given move against its target.
*
* This encapsulates the following multipliers:
* - Same-Type Attack Bonus (and its modification by the ability Adaptability)
* - Super/Not Very Effective multipliers for each of the defender's types
* - Type-effectiveness overrides for effects like Iron Ball, Roost, and Miracle Eye
* - Wonder Guard's override for moves that are not super-effective
* - Expert Belt's multiplier for super-effective moves
* - Filter and Solid Rock's multipliers for defenders taking super-effective damage
* - Tinted Lens's multiplier for defenders taking not-very-effective damage
*
* The move status mask will also be updated with the correct flags.
*
* @param battleSys
* @param battleCtx
* @param move
* @param inType If this is non-zero, then it will be regarded as the move's type
* @param attacker
* @param defender
* @param damage Pre-calculated starting damage value
* @param[out] moveStatusMask
* @return Damage value after applying the type-chart and related multipliers
*/
int BattleSystem_ApplyTypeChart(BattleSystem *battleSys, BattleContext *battleCtx, int move, int inType, int attacker, int defender, int damage, u32 *moveStatusMask);
/**
* @brief Calculate the effectiveness mask of the given move.
*
* @param battleCtx
* @param move
* @param inType If this is non-zero, then it will be regarded as the move's type
* @param attackerAbility
* @param defenderAbility
* @param defenderItemEffect
* @param defenderType1
* @param defenderType2
* @param[out] moveStatusMask
*/
void BattleSystem_CalcEffectiveness(BattleContext *battleCtx, int move, int inType, int attackerAbility, int defenderAbility, int defenderItemEffect, int defenderType1, int defenderType2, u32 *moveStatusMask);
/**
* @brief Check if a battler's move failed to execute for the turn.
*
* @param battleCtx
* @param battler
* @return TRUE if the battler's move failed to execute for the turn, FALSE
* otherwise.
*/
BOOL BattleContext_MoveFailed(BattleContext *battleCtx, int battler);
/**
* @brief Count the number of targets hit by a move.
*
* @param battleSys
* @param battleCtx
* @param sameSide If TRUE, only the battlers on the same side of the field as
* the defender will be counted. If FALSE, all battlers will
* be counted.
* @param defender
* @return The number of battlers hit by the move.
*/
u8 BattleSystem_CountAliveBattlers(BattleSystem *battleSys, BattleContext *battleCtx, BOOL sameSide, int defender);
/**
* @brief Apply a nickname tag to the given battler for message-formatting.
*
* @param battleSys
* @param battler
* @return The battler + a nickname tag value.
*/
int BattleSystem_NicknameTag(BattleContext *battleSys, int battler);
/**
* @brief Get a battler's selected move for the turn, if any.
*
* @param battleCtx
* @param battler
* @return The battler's selected move for the turn.
*/
u16 Battler_SelectedMove(BattleContext *battleCtx, int battler);
/**
* @brief Count the number of instances of the given ability on the battlefield.
*
* @param battleSys
* @param battleCtx
* @param mode The behavior mode. See enum CountAbilityMode.
* @param battler
* @param ability
* @return The number of battlers with the given ability matching the input
* criteria; if the mode is one of *_FLAG, then the return value will instead
* be a mask of the battlers matching the criteria.
*/
int BattleSystem_CountAbility(BattleSystem *battleSys, BattleContext *battleCtx, enum CountAbilityMode mode, int battler, int ability);
/**
* @brief Determine if a given move is a multi-turn move.
*
* @param battleCtx
* @param move
* @return TRUE if the move is a multi-turn move (one which has a charging
* turn); FALSE if not
*/
BOOL Move_IsMultiTurn(BattleContext *battleCtx, int move);
/**
* @brief Access a particular entry in the type-matchup table.
*
* If the requested entry falls outside the bounds of the table, then a
* random entry's data will instead be accessed.
*
* @param battleSys
* @param idx The index of table entry to access.
* @param[out] atkType Attacking type of the table entry.
* @param[out] defType Defending type of the table entry.
* @param[out] multi Multiplier for the type matchup.
* @return TRUE if the requested entry was accessed; FALSE if the requested
* entry falls outside the bounds of the table.
*/
BOOL BattleSystem_TypeMatchup(BattleSystem *battleSys, int idx, u8 *moveType, u8 *vsType, u8 *multi);
/**
* @brief Determine the total multiplier classification to use for an attacking
* type against a pair of defending types.
*
* This routine centers 1x damage as a return value of 40. From there, the
* multiplier varies by powers of 2:
* - 1/4x -> 10
* - 1/2x -> 20
* - 1x -> 40
* - 2x -> 80
* - 4x -> 160
*
* @param attackingType
* @param defendingType1
* @param defendingType2
* @return The total multiplier of the attacking type against a defender with
* the pair of types.
*/
int BattleSystem_TypeMatchupMultiplier(u8 attackingType, u8 defendingType1, u8 defendingType2);
/**
* @brief Determines if a move is an invoker-class move.
*
* Invoker-class moves are those which call other moves and have no outward
* effect of their own.
*
* @param move
* @return TRUE if the move is invoker-class, FALSE if not.
*/
BOOL Move_IsInvoker(u16 move);
/**
* @brief Check if a given move is Curse being used by a Ghost-type Pokemon.
*
* @param battleCtx
* @param move
* @param battler
* @return TRUE if the move is Curse and the battler has the Ghost typing;
* FALSE otherwise
*/
BOOL Move_IsGhostCurse(BattleContext *battleCtx, u16 move, int battler);
/**
* @brief Determine if a battler's item can be stolen.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return FALSE
*/
BOOL BattleSystem_CanStealItem(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Check if a battler is *not* holding Mail.
*
* @param battleCtx
* @param battler
* @return TRUE if the battler is *not* holding Mail, FALSE if so.
*/
BOOL BattleSystem_NotHoldingMail(BattleContext *battleCtx, int battler);
/**
* @brief Determine if a target can be Whirlwinded away by an attacker.
*
* If the attacker is of a lesser level than the target, then this routine has
* a random chance to return FALSE. Given a random integer R between 0 and 255,
* Whirlwind will fail if the following condition holds:
*
* R * (attackerLevel + defenderLevel) defenderLevel
* ----------------------------------- + 1 ≤ -------------
* 256 4
*
* @param battleSys
* @param battleCtx
* @return TRUE if Whirlwind should succeed, FALSE if it should fail.
*/
BOOL BattleSystem_CanWhirlwind(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Get the battler's ability, accounting for disrupting effects on itself,
* e.g. Gastro Acid, Gravity, and Ingrain.
*
* @param battleCtx
* @param battler
* @return The battler's ability
*/
u8 Battler_Ability(BattleContext *battleCtx, int battler);
/**
* @brief Check if the given defender has the specified ability, treating it as
* ignorable.
*
* The ability will be ignored if the attacker has Mold Breaker.
*
* @param battleCtx
* @param attacker
* @param defender
* @param ability
* @return TRUE if the defender has the given ability and it is not ignored;
* FALSE if the ability is ignored, or if the defender does not have it.
*/
BOOL Battler_IgnorableAbility(BattleContext *battleCtx, int attacker, int defender, int ability);
/**
* @brief Checks if there are any Pokemon which can act as a replacement for a
* fainted one.
*
* Replacement-eligible Pokemon have HP > 0 and belong to the same party as a
* fallen ally.
*
* @param battleSys
* @param battleCtx
* @param battler The battler which wishes to replace a fainted Pokemon.
* @return TRUE if there are any Pokemon which can replace the fainted one;
* otherwise FALSE.
*/
BOOL BattleSystem_AnyReplacementMons(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Check if a battler is trapped and cannot switch and, optionally,
* populate a message for display.
*
* @param battleSys
* @param battleCtx
* @param battler
* @param[out] msgOut If non-null, will be populated with a message for
* display to the player
* @return TRUE if the battler is trapped, FALSE if not.
*/
BOOL Battler_IsTrappedMsg(BattleSystem *battleSys, BattleContext *battleCtx, int battler, BattleMessage *msgOut);
/**
* @brief Try to escape a battle.
*
* @param battleSys
* @param battleCtx
* @param battler The battler trying to escape
* @return TRUE if escape is successful, FALSE otherwise
*/
BOOL Battler_CanEscape(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Check if Truant is active for the turn for a given battler.
*
* @param battleCtx
* @param battler
* @return TRUE if the battler is loafing due to Truant, FALSE if not.
*/
BOOL Battler_CheckTruant(BattleContext *battleCtx, int battler);
/**
* @brief Checks if a given move has been Imprisoned by one of the battler's
* opponents.
*
* @param battleSys
* @param battleCtx
* @param battler The battler trying to execute a move.
* @param move The move to be executed.
* @return TRUE if any of the battler's opponents has used Imprison and also
* knows the requested move; FALSE otherwise.
*/
BOOL Move_Imprisoned(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move);
/**
* @brief Check if any active battlers are flagged as having the given move
* effect.
*
* @param battleSys
* @param battleCtx
* @param effectMask The requested move effect
* @return TRUE if any active battler has the requested move effect; FALSE
* othewise
*/
BOOL BattleSystem_AnyBattlersWithMoveEffect(BattleSystem *battleSys, BattleContext *battleCtx, int effectMask);
/**
* @brief Setup flags for a move loop, e.g. for multi-hit or spread moves.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_SetupLoop(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Sort all active battlers by their speed for the turn, ignoring Quick
* Claw type effects.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_SortMonSpeedOrder(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Check if a given move should fail due to high gravity conditions.
*
* @param battleSys
* @param battleCtx
* @param battler
* @param move The move to be executed
* @return TRUE if the field is under high gravity conditions AND the move
* should fail in such conditions; FALSE otherwise
*/
BOOL Move_FailsInHighGravity(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move);
/**
* @brief Check if a given move should fail due to the battler being afflicted
* by Heal Block.
*
* @param battleSys
* @param battleCtx
* @param battler The battler trying to execute a move
* @param move The move to be executed
* @return TRUE if the battler is afflicted with Heal Block AND the move should
* fail due to such afflicition; FALSE otherwise
*/
BOOL Move_HealBlocked(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move);
/**
* @brief Update buffers for the attacking Pokemon related to Last Resort.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_UpdateLastResort(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Count the number of moves known by a battler.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return The number of moves known.
*/
int Battler_CountMoves(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Trigger an immunity-granting ability of the defender based on the
* attacker's current move.
*
* Despite its name, this routine does NOT check for Levitate, which is
* handled inside the type-chart check routine.
*
* @param battleCtx
* @param attacker
* @param defender
* @return A subscript to be loaded for any triggered effect.
*/
int BattleSystem_TriggerImmunityAbility(BattleContext *battleCtx, int attacker, int defender);
/**
* @brief Trigger an end-of-turn ability for the battler.
*
* If an end-of-turn ability is triggered, then the respective subscript will
* be loaded into the script buffer, and the battle control command will be
* updated to run that script.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return TRUE if a subscript has been loaded for a triggered effect, FALSE
* otherwise.
*/
BOOL BattleSystem_TriggerTurnEndAbility(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Perform a division, setting any zero-result to 1 or -1, matching the
* sign of the dividend.
*
* @param dividend The division's dividend. If positive, quotients of 0 will
* be set to 1; if negative, quotients of 0 will be set to -1.
* @param divisor The dividend's divisor.
* @return The result of the division, not permitted to be lesser in magnitude
* than 1.
*/
int BattleSystem_Divide(int dividend, int divisor);
/**
* @brief Trigger effects which process on-switch-in, e.g. weather abilities,
* Intimidate, status-restoring berries, and Amulet Coin.
*
* @param battleSys
* @param battleCtx
* @return A subscript which should be loaded as a triggered effect, if any.
*/
int BattleSystem_TriggerEffectOnSwitch(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Pick a random opponent for the given attacker.
*
* In a single-battle, this will always return the lone opponent.
*
* In a double-battle, if one of the two opponents has fainted, then the other
* opponent will always be chosen.
*
* @param battleSys
* @param battleCtx
* @param attacker
* @return A random opponent of the attacker's.
*/
int BattleSystem_RandomOpponent(BattleSystem *battleSys, BattleContext *battleCtx, int attacker);
/**
* @brief Trigger the defender's ability after a move deals damage to it.
*
* @param battleSys
* @param battleCtx
* @param[out] subscript Return-param for the subscript to be loaded for any
* triggered effect.
* @return TRUE if the returned subscript param should be loaded for a
* triggered effect.
*/
BOOL BattleSystem_TriggerAbilityOnHit(BattleSystem *battleSys, BattleContext *battleCtx, int *subscript);
/**
* @brief Triggers a battler's ability which prevents an illegal status
* condition on the given battler, e.g. a paralyzed Pokemon with Limber.
*
* This also contains the check responsible for setting the canUnburden flag.
*
* @param battleSys
* @param battleCtx
* @param battler
* @param skipLoad If TRUE, the routine will skip loading the subscript
* responsible for curing an illegal status condition.
* @return TRUE if a subscript for an ability effect was loaded, FALSE
* otherwise.
*/
BOOL BattleSystem_RecoverStatusByAbility(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int skipLoad);
/**
* @brief Check if an ability forbids a value in the given status mask.
*
* @param battleSys
* @param ability The ability to check
* @param status A mask of status values
* @return TRUE if the given ability forbids some status in the given mask;
* FALSE if not
*/
BOOL Ability_ForbidsStatus(BattleContext *battleSys, int ability, int status);
/**
* @brief Synchronize a defender's newly-applied status with the Pokemon who
* applied it.
*
* @param battleSys
* @param battleCtx
* @param controllerCommand The command to return to after sharing the status
* @return TRUE if a subscript has been loaded for the status-sharing effect,
* FALSE if not.
*/
BOOL BattleSystem_SynchronizeStatus(BattleSystem *battleSys, BattleContext *battleCtx, int controllerCommand);
/**
* @brief Check if a held item should trigger due to status, an HP threshold, or
* a stat reduction, then load any such triggered effect's corresponding subscript.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return TRUE if a subscript has been loaded for a triggered effect, FALSE
* otherwise.
*/
BOOL BattleSystem_TriggerHeldItem(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Check if a Leftovers-type item should trigger at the end of the turn.
*
* This also contains the split-effect for Black Sludge.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return TRUE if an effect has been loaded for a subscript to be run, FALSE
* otherwise.
*/
BOOL BattleSystem_TriggerLeftovers(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Check if a held item should trigger due to status, an HP threshold, or
* a stat reduction.
*
* Unlike its counterpart TriggerHeldItem, this routine will return the triggered
* effect subscript to the caller rather than immediately loading it for
* execution.
*
* @param battleSys
* @param battleCtx
* @param battler
* @param[out] subscript Return param for the subscript to load for a
* triggered effect.
* @return TRUE if a subscript has been returned for a triggered effect, FALSE
* otherwise.
*/
BOOL BattleSystem_TriggerHeldItemOnStatus(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int *subscript);
/**
* @brief Check if a detrimental held item should trigger at the end of the turn.
*
* This accounts for the effects of Toxic Orb, Flame Orb, and Sticky Barb.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return TRUE if an effect has been loaded for a subscript to be run, FALSE
* otherwise.
*/
BOOL BattleSystem_TriggerDetrimentalHeldItem(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Get the battler's held item.
*
* @param battleCtx
* @param battler
* @return Integer ID of the battler's held item
*/
u16 Battler_HeldItem(BattleContext *battleCtx, int battler);
/**
* @brief Check if a battler moved this turn.
*
* @param battleCtx
* @param battler
* @return TRUE if the battler's turn is over, FALSE if they have yet to move.
*/
BOOL Battler_MovedThisTurn(BattleContext *battleCtx, int battler);
/**
* @brief Trigger a held item's effect when its holder takes damage.
*
* @param battleSys
* @param battleCtx
* @param[out] subscript Return param for the subscript to load for a
* triggered effect.
* @return TRUE if a subscript should be loaded for a triggered effect,
* FALSE otherwise.
*/
BOOL BattleSystem_TriggerHeldItemOnHit(BattleSystem *battleSys, BattleContext *battleCtx, int *subscript);
/**
* @brief Get the effect of the battler's held item.
*
* @param battleCtx
* @param battler
* @return Integer ID of the effect of the battler's held item
*/
s32 Battler_HeldItemEffect(BattleContext *battleCtx, int battler);
enum HeldItemPowerOp {
ITEM_POWER_CHECK_ALL = 0, //< Check all possible effects which would suppress a battler's held item.
ITEM_POWER_CHECK_NONE, //< Perform no suppression checks; always return the item's power.
ITEM_POWER_CHECK_EMBARGO, //< Check if Embargo is active; if so, return 0 power.
};
/**
* @brief Get the power of the battler's held item.
*
* This routine optionally can perform a series of checks for effects which
* would suppress the held item.
*
* @param battleCtx
* @param battler
* @param opcode Opcode controlling the behavior of this subroutine.
* @return The power of the battler's held item.
*/
s32 Battler_HeldItemPower(BattleContext *battleCtx, int battler, enum HeldItemPowerOp opcode);
/**
* @brief Get the Natural Gift base power for a battler's held item.
*
* @param battleCtx
* @param battler
* @return Base power for Natural Gift.
*/
s32 Battler_NaturalGiftPower(BattleContext *battleCtx, int battler);
/**
* @brief Get the Natural Gift type for a battler's held item.
*
* @param battleCtx
* @param battler
* @return Type for Natural Gift.
*/
s32 Battler_NaturalGiftType(BattleContext *battleCtx, int battler);
/**
* @brief Get the Pluck effect of the battler's held item.
*
* @param battleCtx
* @param battler
* @return Pluck effect of the battler's held item.
*/
s32 Battler_ItemPluckEffect(BattleContext *battleCtx, int battler);
/**
* @brief Get the Fling effect of the battler's held item.
*
* @param battleCtx
* @param battler
* @return Fling effect of the battler's held item.
*/
s32 Battler_ItemFlingEffect(BattleContext *battleCtx, int battler);
/**
* @brief Get the Fling power of the battler's held item.
*
* @param battleCtx
* @param battler
* @return Fling power of the battler's held item.
*/
s32 Battler_ItemFlingPower(BattleContext *battleCtx, int battler);
/**
* @brief Check if a battler is trapped and cannot switch.
*
* @param battleSys
* @param battleCtx
* @param battler
* @return TRUE if the battler is trapped, FALSE if not.
*/
BOOL Battler_IsTrapped(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Try to Pluck the given battler's berry.
*
* This routine will determine what subsequence should be run as the stolen
* effect (if any) and store it in battleCtx->scriptTemp. It will also update
* the attacker's self-turn status flags to denote that the attacker has
* Plucked a berry.
*
* @param battleSys
* @param battleCtx
* @param battler The battler whose berry is to be Plucked.
* @return TRUE if a follow-up subsequence should be run to apply the berry's
* Pluck effect; FALSE if no such follow-up is needed.
*/
BOOL BattleSystem_PluckBerry(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Try to Fling the attacker's item at the given battler.
*
* This routine will determine what subsequence should be run as the flung
* effect (if any) and store it in battleCtx->flingScript. It will also
* determine the base power of Fling, as specified in the item data, and
* store it in battleCtx->movePower.
*
* @param battleSys
* @param battleCtx
* @param battler The target of the flung item.
* @return TRUE if a follow-up subsequence should be run to apply the item's
* Fling effect; FALSE if no such follow-up is needed.
*/
BOOL BattleSystem_FlingItem(BattleSystem *battleSys, BattleContext *battleCtx, int battler);
/**
* @brief Update the count for the Metronome held item.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_UpdateMetronomeCount(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Verify the current count for the Metronome held item.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_VerifyMetronomeCount(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Determine what modulating effect to apply to a battler's cry
* whenever they are sent into battle.
*
* @param battleCtx
* @param battler
* @param battlerType
* @param encounter TRUE if this is a start-of-battle cry.
* @return The type of modulating effect applied to the battler's cry.
*/
enum PokemonCryMod Battler_CryModulation(BattleContext *battleCtx, int battler, int battlerType, BOOL encounter);
/**
* @brief Check if a battler can choose their action for the turn.
*
* @param battleSys
* @param battler
* @return TRUE if the battler can choose their action for the turn, FALSE
* if not.
*/
BOOL Battler_CanPickCommand(BattleContext *battleSys, int battler);
/**
* @brief Set the catch-data for a newly-caught Pokemon.
*
* This will set the met-location and Poke Ball for the newly-caught Pokemon.
*
* @param battleSys
* @param battleCtx
* @param mon
*/
void BattleSystem_SetPokemonCatchData(BattleSystem *battleSys, BattleContext *battleCtx, Pokemon *mon);
/**
* @brief Get the top byte of the IO buffer for the given battler.
*
* @param battleCtx
* @param battler
* @return Top byte of the IO buffer for the given battler.
*/
u8 BattleContext_IOBufferVal(BattleContext *battleCtx, int battler);
/**
* @brief Check if a battler's substitute was hit.
*
* @param battleCtx
* @param battler
* @return TRUE if the battler's substitute was hit, FALSE if not.
*/
BOOL Battler_SubstituteWasHit(BattleContext *battleCtx, int battler);
/**
* @brief Check if the player is the attacking Pokemon's OT.
*
* @param battleSys
* @param battleCtx
* @return TRUE if the player is the attacking Pokemon's OT, FALSE
* otherwise.
*/
BOOL BattleSystem_TrainerIsOT(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Check if the player is a given Pokemon's OT.
*
* @param battleSys
* @param mon
* @return TRUE if the player is the given Pokemon's OT, FALSE otherwise.
*/
BOOL BattleSystem_PokemonIsOT(BattleSystem *battleSys, Pokemon *mon);
/**
* @brief Trigger a form change for the battler stored in battleCtx->msgBattlerTemp,
* if applicable.
*
* @param battleSys
* @param battleCtx
* @param[out] subscript Return-param for the subscript to be loaded for any
* triggered effect.
* @return TRUE if a form change has triggered and the returned subscript should
* be loaded for execution, FALSE otherwise.
*/
BOOL BattleSystem_TriggerFormChange(BattleSystem *battleSys, BattleContext *battleCtx, int *subscript);
/**
* @brief Initialize the party order buffer.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_InitPartyOrder(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Switch the party order by swapping the battler in the given party slot
* with an active slot.
*
* @param battleSys
* @param battleCtx
* @param battler The battler who is switching
* @param partySlot The party slot which should be moved to an active slot
*/
void BattleSystem_SwitchSlots(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int partySlot);
/**
* @brief Calculate the base damage for a move using the general damage formula.
*
* This computes the following value:
*
* ( ( 2 x Level ) ( Attack ) )
* ( ( --------- + 2 ) * Power * ( ------- ) )
* ( ( 5 ) ( Defense ) )
* ( --------------------------------------- ) * Burn * Screens * Targets * Weather * FlashFire + 2
* ( 50 )
*
* @param battleSys
* @param battleCtx
* @param move The move being calculated
* @param sideConditions State of the side conditions mask at the time of calculation
* @param fieldConditions State of the field conditions mask at the time of calculation
* @param inPower Input power for variable base-power moves
* @param inType Input type for variable type moves (e.g. Hidden Power)
* @param attacker
* @param defender
* @param criticalMul Critical multiplier; must always be >= 1, 1 == no crit,
* 2+ signifies a crit
* @return The computed base damage for the move
*/
int BattleSystem_CalcMoveDamage(BattleSystem *battleSys,
BattleContext *battleCtx,
int move,
u32 sideConditions,
u32 fieldConditions,
u16 inPower,
u8 inType,
u8 attacker,
u8 defender,
u8 criticalMul);
/**
* @brief Incorporate random variance in the given damage value.
*
* A random factor in the range of [0.85, 1] will be used to vary the output
* damage value, i.e., we compute the following:
*
* Damage = Damage * Random([0.85, 1])
*
* @param battleSys
* @param battleCtx
* @param damage
* @return The varied damage value.
*/
int BattleSystem_CalcDamageVariance(BattleSystem *battleSys, BattleContext *battleCtx, int damage);
/**
* @brief Calculate the critical multiplier to be applied to a move's damage.
*
* This also performs all of the calculations for if a critical hit should/can
* occur.
*
* @param battleSys
* @param battleCtx
* @param attacker
* @param defender
* @param criticalStage The existing critical hit stage for the attacker
* @param sideConditions State of the side conditions mask at the time of calculation
* @return 1 if no critical occurs, 2 if a critical occurs, 3 if a critical
* occurs and the attacker also has the ability Sniper
*/
int BattleSystem_CalcCriticalMulti(BattleSystem *battleSys, BattleContext *battleCtx, int attacker, int defender, int criticalStage, u32 sideConditions);
/**
* @brief Check if a move can be copied by Mimic.
*
* @param move
* @return TRUE if the move can be copied by Mimic, FALSE if not.
*/
BOOL Move_CanBeMimicked(u16 move);
/**
* @brief Check if a move can be invoked by Metronome.
*
* @param battleSys
* @param battleCtx
* @param battler The battler using Metronome.
* @param move
* @return TRUE if the move can be invoked by Metronome, FALSE if not.
*/
BOOL Move_CanBeMetronomed(BattleSystem *battleSys, BattleContext *battleCtx, int battler, u16 move);
/**
* @brief Check if a move can be Encored.
*
* @param battleCtx
* @param move
* @return TRUE if the move can be Encored, FALSE if not.
*/
BOOL Move_CanBeEncored(BattleContext *battleCtx, u16 move);
/**
* @brief Check if a move can be copied by Me First.
*
* @param battleCtx
* @param move
* @return TRUE if the move can be copied by Me First, FALSE if not.
*/
BOOL Move_MeFirstCanCopy(BattleContext *battleCtx, u16 move);
/**
* @brief Get a data element out of the given item's data structure.
*
* This consults the item table loaded at battle start-time.
*
* @param battleCtx
* @param item ID of the item to be loaded
* @param paramID ID of the item param to be retrieved
* @return s32-representation of the data pulled from the item table
*/
s32 BattleSystem_GetItemData(BattleContext *battleCtx, u16 item, enum ItemDataParam paramID);
/**
* @brief Determine the first battler which matches the input side value.
*
* @param battleSys
* @param battleCtx
* @param side
* @return The first battler which matches the input side value.
*/
int BattleSystem_SideToBattler(BattleSystem *battleSys, BattleContext *battleCtx, int side);
/**
* @brief Sort the action order for battlers based on their speed and actions.
*
* @param battleSys
* @param battleCtx
*/
void BattleSystem_SortMonActionOrder(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Determine if a status effect should be shown for the given battler.
*
* This handles the determination of if a given status effect animation should
* be played if the battler is behind a substitute or is in an invulnerable
* state.
*
* @param battleCtx
* @param battler The battler for whom the status effect should be shown.
* @param status The status effect attempting to be shown.
* @return TRUE if the status effect should be shown, FALSE otherwise.
*/
BOOL BattleSystem_ShouldShowStatusEffect(BattleContext *battleCtx, int battler, int status);
/**
* @brief Trigger a held item's effect after a pivoting move has been used.
*
* This is meant to support triggering effects such as Shell Bell, Life Orb,
* and Sticky Barb transferral before the user of a pivoting move switches out.
*
* @param battleSys
* @param battleCtx
* @param[out] subscript Return param for the subscript to load for a
* triggered effect.
* @return TRUE if a subscript should be loaded for a triggered effect,
* FALSE otherwise.
*/
BOOL BattleSystem_TriggerHeldItemOnPivotMove(BattleSystem *battleSys, BattleContext *battleCtx, int *subscript);
/**
* @brief Decrement additional PP from the attacker's selected move if its
* target has the Pressure ability.
*
* @param battleCtx
* @param attacker
* @param defender
*/
void BattleSystem_DecPPForPressure(BattleContext *battleCtx, int attacker, int defender);
/**
* @brief Check if the recording for a battle has finished playing.
*
* If the recording has finished, then the controller will be set to a
* SCREEN_WIPE command.
*
* @param battleSys
* @param battleCtx
* @return TRUE if the recording has stopped, FALSE otherwise.
*/
BOOL Battle_RecordingStopped(BattleSystem *battleSys, BattleContext *battleCtx);
/**
* @brief Get an accessible field from the BattleContext struct.
*
* See: enum BattleContextParam
*
* @param battleSys
* @param battleCtx
* @param paramID ID of the field to retrieve
* @param battler Battler for retrieving the correct field, if applicable
* @return Value of the field, or 0 if unrecognized.
*/
int BattleContext_Get(BattleSystem *battleSys, BattleContext *battleCtx, enum BattleContextParam paramID, int battler);
/**
* @brief Set the value of an accessible field in the BattleContext struct.
*
* See: enum BattleContextParam
*
* The following values may be modified:
* - The full side conditions mask for a particular side
* - The number of turns of Mist for a particular side
* - The selected party slot for a battler
* - The total number of turns that have elapsed
* - The AI's chosen target for the turn
* - The AI's chosen target from a particular battler for the turn
*
* @param battleSys
* @param battleCtx
* @param paramID ID of the field to retrieve
* @param battler Battler for accessing the correct field, if applicable
* @param val Value to which the field should be set
*/
void BattleContext_Set(BattleSystem *battleSys, BattleContext *battleCtx, enum BattleContextParam paramID, int battler, int val);
/**
* @brief Determine what Pokemon the AI will switch-in from their party after
* one of their active battlers has been KO'd.
*
* @param battleSys
* @param battler
* @return The party slot of the Pokemon to be switched in.
*/
int BattleAI_PostKOSwitchIn(BattleSystem *battleSys, int battler);
/**
* @brief Get the switched-to slot determined by the AI for a given battler.
*
* @param battleSys
* @param battler
* @return The AI's switched-to slot for the battler.
*/
int BattleAI_SwitchedSlot(BattleSystem *battleSys, int battler);
/**
* @brief Compute the variable-type of a move, given its use by a given Pokemon.
*
* This is used by moves such as Natural Gift, Hidden Power, and Weather Ball.
*
* @param battleSys
* @param battleCtx
* @param mon The Pokemon using the move.
* @param move The move being used.
* @return The variable-type of a move, considering parameters of its user and
* the battlefield.
*/
int Move_CalcVariableType(BattleSystem *battleSys, BattleContext *battleCtx, Pokemon *mon, int move);
#endif // POKEPLATINUM_BATTLE_BATTLE_LIB_H