compilable

This commit is contained in:
cawtds 2025-10-03 02:02:20 +02:00
parent 844dc72add
commit 770ab29653
113 changed files with 21184 additions and 17084 deletions

View File

@ -365,6 +365,7 @@ include tileset_rules.mk
include spritesheet_rules.mk
include json_data_rules.mk
include audio_rules.mk
include trainer_rules.mk
# NOTE: Tools must have been built prior (FIXME)
# so you can't really call this rule directly
@ -394,11 +395,6 @@ clean-generated:
@rm -f $(ALL_LEARNABLES_JSON)
@echo "rm -f <ALL_LEARNABLES_JSON>"
COMPETITIVE_PARTY_SYNTAX := $(shell PATH="$(PATH)"; echo 'COMPETITIVE_PARTY_SYNTAX' | $(CPP) $(CPPFLAGS) -imacros include/gba/defines.h -imacros include/config/general.h | tail -n1)
ifeq ($(COMPETITIVE_PARTY_SYNTAX),1)
%.h: %.party ; $(CPP) $(CPPFLAGS) -traditional-cpp - < $< | $(TRAINERPROC) -o $@ -i $< -
endif
$(C_BUILDDIR)/librfu_intr.o: CFLAGS := -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast
$(C_BUILDDIR)/berry_crush.o: override CFLAGS += -Wno-address-of-packed-member
$(C_BUILDDIR)/agb_flash.o: override CFLAGS += -fno-toplevel-reorder

File diff suppressed because it is too large Load Diff

View File

@ -385,7 +385,7 @@ B_LAST_ITEM = FD 16
B_LAST_ABILITY = FD 17
B_ATK_ABILITY = FD 18
B_DEF_ABILITY = FD 19
B_SCR_ACTIVE_ABILITY = FD 1A
B_SCR_ABILITY = FD 1A
B_EFF_ABILITY = FD 1B
B_TRAINER1_CLASS = FD 1C
B_TRAINER1_NAME = FD 1D
@ -431,8 +431,8 @@ B_TRAINER1_NAME_WITH_CLASS = FD 42
B_TRAINER2_NAME_WITH_CLASS = FD 43
B_PARTNER_NAME_WITH_CLASS = FD 44
B_ATK_TRAINER_NAME_WITH_CLASS = FD 45
B_SCR_TEAM1 = FD 46
B_SCR_TEAM2 = FD 47
B_EFF_TEAM1 = FD 46
B_EFF_TEAM2 = FD 47
@ indicates the end of a town/city name (before " TOWN" or " CITY")
NAME_END = FC 00

File diff suppressed because it is too large Load Diff

View File

@ -174,7 +174,7 @@ BattleScript_PokeFluteEnd::
BattleScript_ItemSetMist::
call BattleScript_UseItemMessage
setmist
playmoveanimation BS_ATTACKER, MOVE_MIST
playmoveanimation MOVE_MIST
waitanimation
printfromtable gMistUsedStringIds
waitmessage B_WAIT_TIME_LONG
@ -185,7 +185,7 @@ BattleScript_ItemSetFocusEnergy::
jumpifvolatile BS_ATTACKER, VOLATILE_DRAGON_CHEER, BattleScript_ButItFailed
jumpifvolatile BS_ATTACKER, VOLATILE_FOCUS_ENERGY, BattleScript_ButItFailed
setfocusenergy BS_ATTACKER
playmoveanimation BS_ATTACKER, MOVE_FOCUS_ENERGY
playmoveanimation MOVE_FOCUS_ENERGY
waitanimation
copybyte sBATTLER, gBattlerAttacker
printstring STRINGID_PKMNUSEDXTOGETPUMPED

View File

@ -83,6 +83,15 @@ Debug_FlagsNotSetBattleConfigMessage_Text:
.string "Please define a usable flag in:\l"
.string "'include/config/battle.h'!$"
Debug_VarsNotSetBattleConfigMessage::
message Debug_VarsNotSetBattleConfigMessage_Text
goto Debug_MessageEnd
Debug_VarsNotSetBattleConfigMessage_Text:
.string "Feature unavailable!\n"
.string "Please define a usable var in:\l"
.string "'include/config/battle.h'!$"
Debug_BoxFilledMessage::
message Debug_BoxFilledMessage_Text
goto Debug_MessageEnd
@ -331,6 +340,44 @@ Debug_EventScript_InflictStatus1_Single:
releaseall
end
Debug_EventScript_SetHiddenNature::
special ChoosePartyMon
waitstate
goto_if_ge VAR_0x8004, PARTY_SIZE, Debug_EventScript_InflictStatus1_Close
specialvar VAR_RESULT, ScriptGetPartyMonSpecies
goto_if_eq VAR_RESULT, SPECIES_EGG, Debug_EventScript_InflictStatus1_Close
dynmultipush Debug_EventScript_ChangeNature_Text_Hardy, 0
dynmultipush Debug_EventScript_ChangeNature_Text_Lonely, 1
dynmultipush Debug_EventScript_ChangeNature_Text_Brave, 2
dynmultipush Debug_EventScript_ChangeNature_Text_Adamant, 3
dynmultipush Debug_EventScript_ChangeNature_Text_Naughty, 4
dynmultipush Debug_EventScript_ChangeNature_Text_Bold, 5
dynmultipush Debug_EventScript_ChangeNature_Text_Docile, 6
dynmultipush Debug_EventScript_ChangeNature_Text_Relaxed, 7
dynmultipush Debug_EventScript_ChangeNature_Text_Impish, 8
dynmultipush Debug_EventScript_ChangeNature_Text_Lax, 9
dynmultipush Debug_EventScript_ChangeNature_Text_Timid, 10
dynmultipush Debug_EventScript_ChangeNature_Text_Hasty, 11
dynmultipush Debug_EventScript_ChangeNature_Text_Serious, 12
dynmultipush Debug_EventScript_ChangeNature_Text_Jolly, 13
dynmultipush Debug_EventScript_ChangeNature_Text_Naive, 14
dynmultipush Debug_EventScript_ChangeNature_Text_Modest, 15
dynmultipush Debug_EventScript_ChangeNature_Text_Mild, 16
dynmultipush Debug_EventScript_ChangeNature_Text_Quiet, 17
dynmultipush Debug_EventScript_ChangeNature_Text_Bashful, 18
dynmultipush Debug_EventScript_ChangeNature_Text_Rash, 19
dynmultipush Debug_EventScript_ChangeNature_Text_Calm, 20
dynmultipush Debug_EventScript_ChangeNature_Text_Gentle, 21
dynmultipush Debug_EventScript_ChangeNature_Text_Sassy, 22
dynmultipush Debug_EventScript_ChangeNature_Text_Careful, 23
dynmultipush Debug_EventScript_ChangeNature_Text_Quirky, 24
dynmultistack 0, 0, TRUE, 7, FALSE, 0, NULL
switch VAR_RESULT
case MULTI_B_PRESSED, Debug_EventScript_InflictStatus1_Close
special SetHiddenNature
releaseall
end
Debug_EventScript_InflictStatus1_Single_Poison:
setstatus1 STATUS1_POISON, VAR_0x8004
releaseall
@ -439,6 +486,57 @@ Debug_EventScript_InflictStatus1_Text_Freeze:
Debug_EventScript_InflictStatus1_Text_Frostbite:
.string "Frostbite$"
Debug_EventScript_ChangeNature_Text_Hardy:
.string "Hardy$"
Debug_EventScript_ChangeNature_Text_Lonely:
.string "Lonely$"
Debug_EventScript_ChangeNature_Text_Brave:
.string "Brave$"
Debug_EventScript_ChangeNature_Text_Adamant:
.string "Adamant$"
Debug_EventScript_ChangeNature_Text_Naughty:
.string "Naughty$"
Debug_EventScript_ChangeNature_Text_Bold:
.string "Bold$"
Debug_EventScript_ChangeNature_Text_Docile:
.string "Docile$"
Debug_EventScript_ChangeNature_Text_Relaxed:
.string "Relaxed$"
Debug_EventScript_ChangeNature_Text_Impish:
.string "Impish$"
Debug_EventScript_ChangeNature_Text_Lax:
.string "Lax$"
Debug_EventScript_ChangeNature_Text_Timid:
.string "Timid$"
Debug_EventScript_ChangeNature_Text_Hasty:
.string "Hasty$"
Debug_EventScript_ChangeNature_Text_Serious:
.string "Serious$"
Debug_EventScript_ChangeNature_Text_Jolly:
.string "Jolly$"
Debug_EventScript_ChangeNature_Text_Naive:
.string "Naive$"
Debug_EventScript_ChangeNature_Text_Modest:
.string "Modest$"
Debug_EventScript_ChangeNature_Text_Mild:
.string "Mild$"
Debug_EventScript_ChangeNature_Text_Quiet:
.string "Quiet$"
Debug_EventScript_ChangeNature_Text_Bashful:
.string "Bashful$"
Debug_EventScript_ChangeNature_Text_Rash:
.string "Rash$"
Debug_EventScript_ChangeNature_Text_Calm:
.string "Calm$"
Debug_EventScript_ChangeNature_Text_Gentle:
.string "Gentle$"
Debug_EventScript_ChangeNature_Text_Sassy:
.string "Sassy$"
Debug_EventScript_ChangeNature_Text_Careful:
.string "Careful$"
Debug_EventScript_ChangeNature_Text_Quirky:
.string "Quirky$"
Debug_EventScript_EWRAMCounters::
callnative CheckEWRAMCounters
msgbox Debug_EventScript_EWRAMCounters_Text, MSGBOX_DEFAULT

View File

@ -464,4 +464,5 @@ gSpecials::
def_special GetLastUsedSprayType
def_special TrySkyBattle
def_special TryPrepareSecondApproachingTrainer
def_special SetHiddenNature
gSpecialsEnd::

View File

@ -2,6 +2,7 @@
#define GUARD_BATTLE_H
// should they be included here or included individually by every file?
#include "constants/abilities.h"
#include "constants/battle.h"
#include "constants/form_change_types.h"
#include "battle_main.h"
@ -18,6 +19,7 @@
#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"
@ -44,7 +46,7 @@
// Used to exclude moves learned temporarily by Transform or Mimic
#define MOVE_IS_PERMANENT(battler, moveSlot) \
(!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) \
(!(gBattleMons[battler].volatiles.transformed) \
&& !(gDisableStructs[battler].mimickedMoves & (1u << moveSlot)))
// Battle Actions
@ -113,37 +115,34 @@ struct DisableStruct
u8 usedMoves:4;
u8 truantCounter:1;
u8 truantSwitchInHack:1;
u8 noRetreat:1;
u8 tarShot:1;
u8 octolock:1;
u8 cudChew:1;
u8 spikesDone:1;
u8 toxicSpikesDone:1;
u8 stickyWebDone:1;
u8 stealthRockDone:1;
u8 weatherAbilityDone:1;
u8 terrainAbilityDone:1;
u8 syrupBombIsShiny:1;
u8 steelSurgeDone:1;
u8 usedProteanLibero:1;
u8 flashFireBoosted:1;
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
u8 boosterEnergyActivated:1;
u8 padding1:1;
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
u8 roostActive:1;
u8 unburdenActive:1;
u8 neutralizingGas:1;
u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case
u8 unnerveActivated:1; // Unnerve and As One (Unnerve part) activate only once per switch in
u8 padding:3;
u8 hazardsDone:1;
u8 endured:1;
u8 tryEjectPack:1;
u8 octolockedBy:3;
u8 padding:5;
};
// 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 endured:1;
u32 noValidMoves:1;
u32 helpingHand:1;
u32 bounceMove:1;
u32 stealMove:1;
u32 nonVolatileStatusImmobility:1;
@ -151,31 +150,31 @@ struct ProtectStruct
u32 chargingTurn:1;
u32 fleeType:2; // 0: Normal, 1: FLEE_ITEM, 2: FLEE_ABILITY
u32 unableToUseMove:1; // Not to be confused with HITMARKER_UNABLE_TO_USE_MOVE (It is questionable though if there is a difference. Needs further research)
u32 notFirstStrike:1;
u32 laggingTail:1;
u32 palaceUnableToUseMove:1;
u32 powderSelfDmg:1;
u32 statRaised:1;
u32 usedCustapBerry:1; // also quick claw
u32 touchedProtectLike:1;
u32 unused:8;
// End of 32-bit bitfield
u16 disableEjectPack:1;
u16 tryEjectPack:1;
u16 pranksterElevated:1;
u16 quickDraw:1;
u16 beakBlastCharge:1;
u16 quash:1;
u16 shellTrap:1;
u16 eatMirrorHerb:1;
u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
u32 disableEjectPack:1;
u32 pranksterElevated:1;
u32 quickDraw:1;
u32 beakBlastCharge: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
u16 usedAllySwitch:1;
// End of 32-bit bitfield
u16 helpingHand:3;
u16 lashOutAffected:1;
u16 padding:4;
u16 assuranceDoubled:1;
u16 myceliumMight:1;
u16 padding:10;
// End of 16-bit bitfield
u16 physicalDmg;
u16 specialDmg;
u8 physicalBattlerId;
u8 specialBattlerId;
u8 physicalBattlerId:4;
u8 specialBattlerId:4;
};
// Cleared at the start of HandleAction_ActionFinished
@ -185,13 +184,13 @@ struct SpecialStatus
s32 specialDmg;
u8 changedStatsBattlerId; // Battler that was responsible for the latest stat change. Can be self.
u8 statLowered:1;
u8 lightningRodRedirected:1;
u8 abilityRedirected:1;
u8 restoredBattlerSprite: 1;
u8 faintedHasReplacement:1;
u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects.
u8 afterYou:1;
u8 enduredDamage:1;
u8 stormDrainRedirected:1;
u8 dancerUsedMove:1;
u8 padding:1;
// End of byte
u8 switchInAbilityDone:1;
u8 switchInItemDone:1;
@ -210,9 +209,8 @@ struct SpecialStatus
u8 teraShellAbilityDone:1;
u8 criticalHit:1;
// End of byte
u8 dancerUsedMove:1;
u8 dancerOriginalTarget:3;
u8 unused:4;
u8 unused:5;
// End of byte
};
@ -222,21 +220,18 @@ struct SideTimer
u16 lightscreenTimer;
u16 mistTimer;
u16 safeguardTimer;
u16 spikesAmount; // debug menu complains. might be better to solve there instead if possible
u16 toxicSpikesAmount;
u16 stealthRockAmount;
u16 stickyWebAmount;
u8 spikesAmount:4;
u8 toxicSpikesAmount:4;
u8 stickyWebBattlerId;
u8 stickyWebBattlerSide; // Used for Court Change
u16 auroraVeilTimer;
u16 tailwindTimer;
u16 luckyChantTimer;
u16 steelsurgeAmount;
// Timers below this point are not swapped by Court Change
u16 followmeTimer;
u8 followmeTimer:4;
u8 followmeTarget:3;
u8 followmePowder:1; // Rage powder, does not affect grass type pokemon.
u16 retaliateTimer;
u8 retaliateTimer;
u16 damageNonTypesTimer;
u8 damageNonTypesType;
u16 rainbowTimer;
@ -270,7 +265,7 @@ struct WishFutureKnock
struct AI_SavedBattleMon
{
u16 ability;
enum Ability ability;
u16 moves[MAX_MON_MOVES];
u16 heldItem;
u16 species:15;
@ -283,7 +278,7 @@ struct AiPartyMon
u16 species;
u16 item;
u16 heldEffect;
u16 ability;
enum Ability ability;
u16 level;
u16 moves[MAX_MON_MOVES];
u32 status;
@ -316,7 +311,7 @@ struct SimulatedDamage
// Ai Data used when deciding which move to use, computed only once before each turn's start.
struct AiLogicData
{
u16 abilities[MAX_BATTLERS_COUNT];
enum Ability abilities[MAX_BATTLERS_COUNT];
u16 items[MAX_BATTLERS_COUNT];
u16 holdEffects[MAX_BATTLERS_COUNT];
u8 holdEffectParams[MAX_BATTLERS_COUNT];
@ -335,12 +330,12 @@ struct AiLogicData
u8 ejectButtonSwitch:1; // Tracks whether current switch out was from Eject Button
u8 ejectPackSwitch:1; // Tracks whether current switch out was from Eject Pack
u8 predictingSwitch:1; // Determines whether AI will use switch predictions this turn or not
u8 predictingMove:1; // Determines whether AI will use move predictions this turn or not
u8 aiPredictionInProgress:1; // Tracks whether the AI is in the middle of running prediction calculations
u8 padding:2;
u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
u8 aiCalcInProgress:1;
u8 battlerDoingPrediction; // Stores which battler is currently running its prediction calcs
u8 predictingMove:1; // Determines whether AI will use move predictions this turn or not
u8 padding1:1;
u8 shouldSwitch:4; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
u8 padding2:4;
u16 predictedMove[MAX_BATTLERS_COUNT];
};
@ -350,7 +345,6 @@ struct AiThinkingStruct
u8 movesetIndex;
u16 moveConsidered;
s32 score[MAX_MON_MOVES];
u32 funcResult;
u64 aiFlags[MAX_BATTLERS_COUNT];
u8 aiAction;
u8 aiLogicId;
@ -361,7 +355,7 @@ struct AiThinkingStruct
struct BattleHistory
{
u16 abilities[MAX_BATTLERS_COUNT];
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
@ -588,7 +582,10 @@ struct BattlerState
u32 pursuitTarget:1;
u32 stompingTantrumTimer:2;
u32 canPickupItem:1;
u32 padding:17;
u32 itemCanBeKnockedOff:1;
u32 ateBoost:1;
u32 commanderSpecies:11;
u32 padding:4;
// End of Word
};
@ -600,7 +597,9 @@ struct PartyState
u32 battleBondBoost:1;
u32 transformZeroToHero:1;
u32 supersweetSyrup:1;
u32 padding:26;
u32 timesGotHit:5;
u32 changedSpecies:11; // For forms when multiple mons can change into the same pokemon.
u32 padding:10;
};
// Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise.
@ -609,8 +608,9 @@ struct BattleStruct
struct BattlerState battlerState[MAX_BATTLERS_COUNT];
struct PartyState partyState[NUM_BATTLE_SIDES][PARTY_SIZE];
u8 eventBlockCounter;
u8 turnEffectsBattlerId;
u8 endTurnEventsCounter;
u8 turnEffectsBattlerId:4;
u8 moveEndBattlerId:4;
u16 wrappedMove[MAX_BATTLERS_COUNT];
u16 moveTarget[MAX_BATTLERS_COUNT];
u32 expShareExpValue;
@ -662,7 +662,8 @@ struct BattleStruct
u8 anyMonHasTransformed:1; // Only used in battle_tv.c
u8 multipleSwitchInState:2;
u8 multipleSwitchInCursor:3;
u8 padding1:2;
u8 sleepClauseNotBlocked:1;
u8 isSkyBattle:1;
u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT];
void (*savedCallback)(void);
u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle
@ -681,11 +682,11 @@ struct BattleStruct
u8 startingStatusDone:1;
u8 terrainDone:1;
u8 overworldWeatherDone:1;
u8 unused:3;
u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice.
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
u16 startingStatusTimer;
u8 atkCancellerTracker;
// struct BattleTvMovePoints tvMovePoints;
@ -699,12 +700,10 @@ struct BattleStruct
u8 debugBattler;
u8 magnitudeBasePower;
u8 presentBasePower;
u8 roostTypes[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES];
u8 savedBattlerTarget[5];
u8 savedBattlerAttacker[5];
u8 savedTargetCount:4;
u8 savedAttackerCount:4;
bool8 ateBoost[MAX_BATTLERS_COUNT];
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; // two per battler
struct ZMoveData zmove;
struct DynamaxData dynamax;
@ -713,13 +712,12 @@ struct BattleStruct
enum BattleIntroStates introState:8;
u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages
u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct
u16 tracedAbility[MAX_BATTLERS_COUNT];
enum Ability tracedAbility[MAX_BATTLERS_COUNT];
u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell.
struct Illusion illusion[MAX_BATTLERS_COUNT];
u8 soulheartBattlerId;
u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles.
u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used.
u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon.
u8 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
@ -735,6 +733,7 @@ struct BattleStruct
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
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];
u8 attackerBeforeBounce:2;
u8 beatUpSlot:3;
u8 pledgeMove:1;
@ -743,17 +742,14 @@ struct BattleStruct
u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies.
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
u8 isSkyBattle:1;
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 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE];
u8 stickySyrupdBy[MAX_BATTLERS_COUNT];
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
u16 commanderActive[MAX_BATTLERS_COUNT];
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;
@ -766,7 +762,7 @@ struct BattleStruct
s16 critChance[MAX_BATTLERS_COUNT];
u16 moveResultFlags[MAX_BATTLERS_COUNT];
u8 missStringId[MAX_BATTLERS_COUNT];
u8 noResultString[MAX_BATTLERS_COUNT];
enum CalcDamageState noResultString[MAX_BATTLERS_COUNT];
u8 doneDoublesSpreadHit:1;
u8 calculatedDamageDone:1;
u8 calculatedSpreadMoveAccuracy:1;
@ -777,7 +773,11 @@ struct BattleStruct
s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg
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 padding2:2;
// pokefirered
u8 field_DA; // battle tower related
u8 lastAttackerToFaintOpponent;
@ -867,8 +867,6 @@ static inline bool32 IsBattleMoveStatus(u32 move)
#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))
#define DO_ACCURACY_CHECK 2 // Don't skip the accuracy check before the move might be absorbed
// NOTE: The members of this struct have hard-coded offsets
// in include/constants/battle_script_commands.h
struct BattleScripting
@ -904,7 +902,7 @@ struct BattleScripting
s32 savedDmg;
u16 savedMoveEffect; // For moves hitting multiple targets.
u16 moveEffect;
u16 multihitMoveEffect;
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;
@ -1060,7 +1058,7 @@ extern u16 gChosenMove;
extern u16 gCalledMove;
extern s32 gBideDmg[MAX_BATTLERS_COUNT];
extern u16 gLastUsedItem;
extern u16 gLastUsedAbility;
extern enum Ability gLastUsedAbility;
extern u8 gBattlerAttacker;
extern u8 gBattlerTarget;
extern u8 gBattlerFainted;
@ -1086,8 +1084,6 @@ extern u32 gHitMarker;
extern u8 gBideTarget[MAX_BATTLERS_COUNT];
extern u32 gSideStatuses[NUM_BATTLE_SIDES];
extern struct SideTimer gSideTimers[NUM_BATTLE_SIDES];
extern u32 gStatuses3[MAX_BATTLERS_COUNT];
extern u32 gStatuses4[MAX_BATTLERS_COUNT];
extern struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT];
extern u16 gPauseCounterBattle;
extern u16 gPaydayMoney;
@ -1136,7 +1132,7 @@ extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
extern u8 gMultiUsePlayerCursor;
extern u8 gNumberOfMovesToChoose;
extern bool8 gHasFetchedBall;
extern u8 gLastUsedBall;
extern u16 gLastUsedBall;
extern u16 gLastThrownBall;
extern u16 gBallToDisplay;
extern bool8 gLastUsedBallMenuPresent;
@ -1230,6 +1226,11 @@ static inline struct Pokemon *GetBattlerParty(u32 battler)
return GetSideParty(GetBattlerSide(battler));
}
static inline struct PartyState *GetBattlerPartyState(u32 battler)
{
return &gBattleStruct->partyState[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]];
}
static inline bool32 IsDoubleBattle(void)
{
return gBattleTypeFlags & BATTLE_TYPE_DOUBLE;
@ -1243,7 +1244,7 @@ static inline bool32 IsSpreadMove(u32 moveTarget)
static inline bool32 IsDoubleSpreadMove(void)
{
return gBattleStruct->numSpreadTargets > 1
&& !(gHitMarker & (HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_UNABLE_TO_USE_MOVE))
&& !(gHitMarker & (HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_UNABLE_TO_USE_MOVE))
&& IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove));
}
@ -1254,4 +1255,14 @@ static inline bool32 IsBattlerInvalidForSpreadMove(u32 battlerAtk, u32 battlerDe
|| (battlerDef == BATTLE_PARTNER(battlerAtk) && (moveTarget == MOVE_TARGET_BOTH));
}
static inline u32 GetChosenMoveFromPosition(u32 battler)
{
return gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
}
static inline bool32 IsGhostBattleWithoutScope()
{
return (gBattleTypeFlags & BATTLE_TYPE_GHOST) && !CheckBagHasItem(ITEM_SILPH_SCOPE, 1);
}
#endif // GUARD_BATTLE_H

View File

@ -0,0 +1,18 @@
#ifndef GUARD_BATTLE_AI_FIELD_STATUSES_H
#define GUARD_BATTLE_AI_FIELD_STATUSES_H
#include "battle_ai_main.h"
#include "battle_ai_util.h"
enum FieldEffectOutcome
{
FIELD_EFFECT_POSITIVE,
FIELD_EFFECT_NEUTRAL,
FIELD_EFFECT_NEGATIVE,
FIELD_EFFECT_BLOCKED,
};
bool32 WeatherChecker(u32 battler, u32 weather, enum FieldEffectOutcome desiredResult);
bool32 FieldStatusChecker(u32 battler, u32 fieldStatus, enum FieldEffectOutcome desiredResult);
#endif //GUARD_BATTLE_AI_FIELD_STATUSES_H

View File

@ -23,6 +23,11 @@ enum StatChange
STAT_CHANGE_SPEED_2,
STAT_CHANGE_SPATK_2,
STAT_CHANGE_SPDEF_2,
STAT_CHANGE_ATK_3,
STAT_CHANGE_DEF_3,
STAT_CHANGE_SPEED_3,
STAT_CHANGE_SPATK_3,
STAT_CHANGE_SPDEF_3,
STAT_CHANGE_ACC,
STAT_CHANGE_EVASION
};
@ -38,7 +43,18 @@ enum AIScore
WEAK_EFFECT = 1,
DECENT_EFFECT = 2,
GOOD_EFFECT = 3,
BEST_EFFECT = 4
BEST_EFFECT = 4,
PERFECT_EFFECT = 10,
BAD_EFFECT = -1,
AWFUL_EFFECT = -3,
WORST_EFFECT = -10
};
enum MoveComparisonResult
{
MOVE_NEUTRAL_COMPARISON,
MOVE_WON_COMPARISON,
MOVE_LOST_COMPARISON,
};
// AI_TryToFaint

View File

@ -45,7 +45,7 @@ void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId);
void AI_TrySwitchOrUseItem(u32 battler);
u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType);
bool32 ShouldSwitch(u32 battler);
bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2);
bool32 IsMonGrounded(u16 heldItemEffect, enum Ability ability, u8 type1, u8 type2);
void ModifySwitchAfterMoveScoring(u32 battler);
#endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H

View File

@ -2,8 +2,12 @@
#define GUARD_BATTLE_AI_UTIL_H
#include "battle_ai_main.h"
#include "battle_ai_field_statuses.h"
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
// Left and right are determined by how they're referred to in tests and everywhere else.
// Left is battlers 0 and 1, right 2 and 3; if you assume the battler referencing them is south, left is to the northeast and right to the northwest.
#define LEFT_FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
#define RIGHT_FOE(battler) (((BATTLE_OPPOSITE(battler)) & BIT_SIDE) | BIT_FLANK)
// Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt.
#define MAX_ROLL_PERCENTAGE DMG_ROLL_PERCENT_HI
@ -23,6 +27,17 @@ enum DamageCalcContext
AI_ATTACKING,
};
// Higher priority at the bottom; note that these are used in the formula MAX_MON_MOVES ^ AiCompareMovesPriority, which must fit within a u32.
// In expansion where MAX_MON_MOVES is 4, this means that AiCompareMovesPriority can range from 0 - 15 inclusive.
enum AiCompareMovesPriority
{
PRIORITY_EFFECT,
PRIORITY_GUARANTEE,
PRIORITY_ACCURACY,
PRIORITY_NOT_CHARGING,
PRIORITY_SPEED,
};
enum AIPivot
{
DONT_PIVOT,
@ -44,6 +59,12 @@ enum AIConsiderGimmick
USE_GIMMICK,
};
enum ConsiderPriority
{
DONT_CONSIDER_PRIORITY,
CONSIDER_PRIORITY,
};
static inline bool32 IsMoveUnusable(u32 moveIndex, u32 move, u32 moveLimitations)
{
return move == MOVE_NONE
@ -53,18 +74,25 @@ static inline bool32 IsMoveUnusable(u32 moveIndex, u32 move, u32 moveLimitations
typedef bool32 (*MoveFlag)(u32 move);
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move);
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move);
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 aiMove, u32 playerMove, enum ConsiderPriority considerPriority);
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 aiMove, u32 playerMove, enum ConsiderPriority considerPriority);
bool32 AI_IsPartyMonFaster(u32 battlerAi, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 aiMove, u32 playerMove, enum ConsiderPriority considerPriority);
bool32 AI_IsPartyMonSlower(u32 battlerAi, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 aiMove, u32 playerMove, enum ConsiderPriority considerPriority);
bool32 AI_RandLessThan(u32 val);
bool32 AI_IsBattlerGrounded(u32 battler);
u32 AI_GetDamage(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext, struct AiLogicData *aiData);
bool32 IsAiVsAiBattle(void);
bool32 BattlerHasAi(u32 battlerId);
bool32 IsAiBattlerAware(u32 battlerId);
bool32 CanAiPredictMove(void);
bool32 IsAiBattlerAssumingStab(void);
bool32 IsAiBattlerAssumingStatusMoves(void);
bool32 ShouldRecordStatusMove(u32 move);
void ClearBattlerMoveHistory(u32 battlerId);
void RecordLastUsedMoveBy(u32 battlerId, u32 move);
void RecordAllMoves(u32 battler);
void RecordKnownMove(u32 battlerId, u32 move);
void RecordAbilityBattle(u32 battlerId, u32 abilityId);
void RecordAbilityBattle(u32 battlerId, enum Ability abilityId);
void ClearBattlerAbilityHistory(u32 battlerId);
void RecordItemEffectBattle(u32 battlerId, u32 itemEffect);
void ClearBattlerItemEffectHistory(u32 battlerId);
@ -79,146 +107,164 @@ bool32 AI_BattlerAtMaxHp(u32 battler);
u32 GetHealthPercentage(u32 battler);
bool32 AI_CanBattlerEscape(u32 battler);
bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef);
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 aiMoveConsidered, u32 playerMoveConsidered, enum ConsiderPriority considerPriority);
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk);
u32 NoOfHitsForTargetToFaintBattler(u32 battlerDef, u32 battlerAtk);
u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext);
u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget, enum DamageCalcContext calcContext);
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits);
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
s32 AI_DecideKnownAbilityForTurn(u32 battlerId);
enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId);
enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId);
bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move);
bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, enum Ability atkAbility, u32 move);
u32 AI_GetWeather(void);
u32 AI_GetSwitchinWeather(struct BattlePokemon battleMon);
enum WeatherState IsWeatherActive(u32 flags);
bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits);
bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, enum DamageCalcContext calcContext);
bool32 CanIndexMoveGuaranteeFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index);
bool32 HasDamagingMove(u32 battlerId);
bool32 HasDamagingMoveOfType(u32 battlerId, u32 type);
bool32 HasDamagingMove(u32 battler);
bool32 HasDamagingMoveOfType(u32 battler, u32 type);
u32 GetBattlerSecondaryDamage(u32 battlerId);
bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability);
bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability);
bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move);
bool32 BattlerWillFaintFromWeather(u32 battler, enum Ability ability);
bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, enum Ability ability);
bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move);
bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex);
u32 GetBattlerSideSpeedAverage(u32 battler);
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage);
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent, enum DamageCalcContext calcContext);
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent);
bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect);
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex);
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 moveIndex);
bool32 IsRecycleEncouragedItem(u32 item);
bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item);
bool32 IsStatBoostingBerry(u32 item);
bool32 CanKnockOffItem(u32 battler, u32 item);
bool32 IsAbilityOfRating(u32 ability, s8 rating);
bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability);
bool32 AI_MoveMakesContact(u32 ability, enum ItemHoldEffect holdEffect, u32 move);
bool32 IsAbilityOfRating(enum Ability ability, s8 rating);
bool32 AI_IsAbilityOnSide(u32 battlerId, enum Ability ability);
bool32 AI_MoveMakesContact(enum Ability ability, enum ItemHoldEffect holdEffect, u32 move);
bool32 IsConsideringZMove(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove);
void SetAIUsingGimmick(u32 battler, enum AIConsiderGimmick use);
bool32 IsAIUsingGimmick(u32 battler);
void DecideTerastal(u32 battler);
bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move);
// stat stage checks
bool32 AnyStatIsRaised(u32 battlerId);
bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat);
bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat);
bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat);
bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, u32 stat);
bool32 AreBattlersStatsMaxed(u32 battler);
u32 CountPositiveStatStages(u32 battlerId);
u32 CountNegativeStatStages(u32 battlerId);
// move checks
bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData);
bool32 IsAffectedByPowder(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect);
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category);
s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);
enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);
struct SimulatedDamage AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef);
struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef, u32 weather);
bool32 AI_IsDamagedByRecoil(u32 battler);
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);
u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef);
u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext);
u32 GetBestNoOfHitsToKO(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext);
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext);
uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef);
u16 *GetMovesArray(u32 battler);
bool32 IsConfusionMoveEffect(enum BattleMoveEffects moveEffect);
bool32 HasMove(u32 battlerId, u32 move);
u32 GetIndexInMoveArray(u32 battler, u32 move);
bool32 HasOnlyMovesWithCategory(u32 battlerId, enum DamageCategory category, bool32 onlyOffensive);
bool32 HasMoveWithCategory(u32 battler, enum DamageCategory category);
bool32 HasMoveWithType(u32 battler, u32 type);
bool32 HasMoveWithEffect(u32 battlerId, enum BattleMoveEffects moveEffect);
bool32 HasMoveWithEffect(u32 battler, enum BattleMoveEffects moveEffect);
bool32 HasMoveWithAIEffect(u32 battler, u32 aiEffect);
bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect);
bool32 HasBattlerSideMoveWithAIEffect(u32 battler, u32 effect);
bool32 HasBattlerSideUsedMoveWithEffect(u32 battler, u32 effect);
bool32 HasNonVolatileMoveEffect(u32 battlerId, u32 effect);
bool32 IsPowerBasedOnStatus(u32 battlerId, enum BattleMoveEffects effect, u32 argument);
bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect);
bool32 HasBattlerSideMoveWithAdditionalEffect(u32 battler, u32 moveEffect);
bool32 HasMoveWithCriticalHitChance(u32 battlerId);
bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, enum BattleMoveEffects exception);
bool32 HasMoveThatLowersOwnStats(u32 battlerId);
bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus);
bool32 HasAnyKnownMove(u32 battlerId);
bool32 IsAromaVeilProtectedEffect(enum BattleMoveEffects moveEffect);
bool32 IsNonVolatileStatusMove(u32 moveEffect);
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, enum Ability atkAbility);
bool32 IsHazardMove(u32 move);
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move);
bool32 IsBattlerDamagedByStatus(u32 battler);
s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove);
bool32 ShouldSetSandstorm(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
bool32 ShouldSetHail(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
bool32 ShouldSetSnow(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
bool32 ShouldSetRain(u32 battlerAtk, u32 ability, enum ItemHoldEffect holdEffect);
bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, enum ItemHoldEffect holdEffect);
bool32 ShouldRaiseAnyStat(u32 battlerAtk, u32 battlerDef);
bool32 ShouldSetWeather(u32 battler, u32 weather);
bool32 ShouldClearWeather(u32 battler, u32 weather);
bool32 ShouldSetFieldStatus(u32 battler, u32 fieldStatus);
bool32 ShouldClearFieldStatus(u32 battler, u32 fieldStatus);
bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef);
bool32 IsHealingMove(u32 move);
bool32 HasHealingEffect(u32 battler);
bool32 IsTrappingMove(u32 move);
bool32 HasTrappingMoveEffect(u32 battler);
bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsFlinchGuaranteed(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 HasChoiceEffect(u32 battler);
bool32 HasThawingMove(u32 battler);
bool32 IsStatRaisingEffect(enum BattleMoveEffects effect);
bool32 IsStatLoweringEffect(enum BattleMoveEffects effect);
bool32 IsSelfStatLoweringEffect(enum BattleMoveEffects effect);
bool32 IsSelfStatLoweringEffect(enum MoveEffect effect);
bool32 IsSelfStatRaisingEffect(enum MoveEffect effect);
bool32 IsSwitchOutEffect(enum BattleMoveEffects effect);
bool32 IsChaseEffect(enum BattleMoveEffects effect);
bool32 IsAttackBoostMoveEffect(enum BattleMoveEffects effect);
bool32 IsUngroundingEffect(enum BattleMoveEffects effect);
bool32 IsSemiInvulnerable(u32 battlerDef, u32 move);
bool32 HasMoveWithFlag(u32 battler, MoveFlag getFlag);
bool32 IsHazardClearingMove(u32 move);
bool32 IsSubstituteEffect(enum BattleMoveEffects effect);
// status checks
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability);
bool32 IsBattlerIncapacitated(u32 battler, u32 ability);
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability ability);
bool32 IsBattlerIncapacitated(u32 battler, enum Ability ability);
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove);
bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef);
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove);
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove);
bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, enum Ability defAbility);
bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof);
u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move);
u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move);
bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsWakeupTurn(u32 battler);
bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId);
// ability logic
bool32 IsMoxieTypeAbility(u32 ability);
bool32 ShouldTriggerAbility(u32 battler, u32 ability);
bool32 IsMoxieTypeAbility(enum Ability ability);
bool32 DoesAbilityRaiseStatsWhenLowered(enum Ability ability);
bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability);
bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct AiLogicData *aiData);
void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, struct AiLogicData *aiData);
s32 BattlerBenefitsFromAbilityScore(u32 battler, enum Ability ability, struct AiLogicData *aiData);
// partner logic
#define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK))
bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef);
// IsTargetingPartner includes a check to make sure the adjacent pokemon is truly a partner.
u32 GetAllyChosenMove(u32 battlerId);
bool32 IsValidDoubleBattle(u32 battlerAtk);
bool32 IsBattle1v1();
// IsBattle1v1 is distinct from !IsDoubleBattle. If the player is fighting Maxie and Tabitha, with Steven as their partner, and both Tabitha and Steven have run out of Pokemon, the battle is 1v1, even though mechanically it is a Double Battle for how battlers and flags are set.
// Most AI checks should be using IsBattle1v1; most engine checks should be using !IsDoubleBattle
bool32 HasTwoOpponents(u32 battler);
// HasTwoOpponents checks if the opposing side has two pokemon. Partner state is irrelevant. e.g., Dragon Darts hits one time with two opponents and twice with one opponent.
bool32 HasPartner(u32 battler);
bool32 HasPartnerIgnoreFlags(u32 battler);
// HasPartner respects the Attacks Partner AI flag; HasPartnerIgnoreFlags checks only if a live pokemon is adjacent.
bool32 AreMovesEquivalent(u32 battlerAtk, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove);
bool32 IsMoveEffectWeather(u32 move);
bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove);
bool32 PartnerMoveEffectIs(u32 battlerAtkPartner, u32 partnerMove, enum BattleMoveEffects effectCheck);
bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck);
bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
@ -247,19 +293,37 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, enum DamageCalcContext calcContext);
u32 AI_WhoStrikesFirstPartyMon(u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 moveConsidered);
s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, uq4_12_t *effectiveness, enum DamageCalcContext calcContext);
u32 AI_WhoStrikesFirstPartyMon(u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 aiMoveConsidered, u32 playerMoveConsidered, enum ConsiderPriority ConsiderPriority);
s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle);
bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef);
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData);
void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData);
u32 IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsBattlerItemEnabled(u32 battler);
bool32 IsBattlerPredictedToSwitch(u32 battler);
u32 GetIncomingMove(u32 battler, u32 opposingBattler, struct AiLogicData *aiData);
bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef);
bool32 HasBattlerSideAbility(u32 battlerDef, u32 ability, struct AiLogicData *aiData);
u32 GetThinkingBattler(u32 battler);
u32 GetIncomingMoveSpeedCheck(u32 battler, u32 opposingBattler, struct AiLogicData *aiData);
bool32 HasBattlerSideAbility(u32 battlerDef, enum Ability ability, struct AiLogicData *aiData);
bool32 IsNaturalEnemy(u32 speciesAttacker, u32 speciesTarget);
// These are for the purpose of not doubling up on moves during double battles.
// Used in GetAIEffectGroup for move effects and GetAIEffectGroupFromMove for additional effects
#define AI_EFFECT_NONE 0
#define AI_EFFECT_WEATHER (1 << 0)
#define AI_EFFECT_TERRAIN (1 << 1)
#define AI_EFFECT_CLEAR_HAZARDS (1 << 2)
#define AI_EFFECT_BREAK_SCREENS (1 << 3)
#define AI_EFFECT_RESET_STATS (1 << 4)
#define AI_EFFECT_FORCE_SWITCH (1 << 5)
#define AI_EFFECT_TORMENT (1 << 6)
#define AI_EFFECT_LIGHT_SCREEN (1 << 7)
#define AI_EFFECT_REFLECT (1 << 8)
#define AI_EFFECT_GRAVITY (1 << 9)
#define AI_EFFECT_CHANGE_ABILITY (1 << 10)
// As Aurora Veil should almost never be used alongside the other screens, we save the bit.
#define AI_EFFECT_AURORA_VEIL (AI_EFFECT_LIGHT_SCREEN | AI_EFFECT_REFLECT)
#endif //GUARD_BATTLE_AI_UTIL_H

View File

@ -121,6 +121,8 @@ void AnimMudSportDirt(struct Sprite *sprite);
void AnimDirtScatter(struct Sprite *sprite);
void AnimMudSportDirtRising(struct Sprite *sprite);
void AnimDirtPlumeParticle(struct Sprite *);
void AnimBoneHitProjectile(struct Sprite *sprite);
extern const union AnimCmd *const sAnims_MudSlapMud[];
extern const union AffineAnimCmd *const gAffineAnims_SpinningBone[];
// battle_anim_throw.c
@ -153,6 +155,7 @@ void AnimTranslateLinearSingleSineWave(struct Sprite *sprite);
void AnimTeraStarstormStars(struct Sprite *sprite);
void AnimGrantingStars(struct Sprite *sprite);
void AnimFollowMeFinger(struct Sprite *sprite);
void AnimPoisonJabProjectile(struct Sprite *sprite);
extern const union AnimCmd *const gRazorLeafParticleAnimTable[];
extern const union AnimCmd *const gPowerAbsorptionOrbAnimTable[];
extern const union AffineAnimCmd *const gPowerAbsorptionOrbAffineAnimTable[];
@ -380,6 +383,7 @@ void AnimElectricity(struct Sprite *);
void AnimTask_VoltSwitch(struct Sprite* sprite);
extern const union AffineAnimCmd *const gAffineAnims_GrowingElectricOrb[];
extern const union AffineAnimCmd *const gAffineAnims_FlashingSpark[];
extern const union AnimCmd *const sAnims_CirclingElectricShock[];
extern const union AnimCmd *const gAnims_ThunderboltOrb[];
extern const union AnimCmd *const gAnims_ElectricPuff[];
extern const union AnimCmd *const gAnims_ElectricChargingParticles[];
@ -403,6 +407,9 @@ extern const union AnimCmd *const gAnims_RevengeBigScratch[];
extern const union AnimCmd *const gAnims_FlyingRock[];
extern const union AffineAnimCmd *const gAffineAnims_Whirlpool[];
extern const union AffineAnimCmd *const gAffineAnims_BasicRock[];
extern const union AnimCmd *const gAnims_FlyingRock[];
extern const union AnimCmd *const sAnims_BasicRock[];
void AnimRockTomb(struct Sprite *sprite);
void AnimParticleInVortex(struct Sprite *sprite);
void AnimFallingRock(struct Sprite *sprite);
void AnimRaiseSprite(struct Sprite *sprite);
@ -598,6 +605,9 @@ void ClearBattleAnimBg(u32 bgId);
void AnimLoadCompressedBgTilemapHandleContest(struct BattleAnimBgData *, const void *, bool32);
bool32 InitSpritePosToAnimBattler(u32 animBattlerId, struct Sprite *sprite, bool8 respectMonPicOffsets);
// battle_anim_ice.c
void AnimIceBeamParticle(struct Sprite *sprite);
// battle_anim_bug.c
void AnimTranslateStinger(struct Sprite *sprite);

View File

@ -280,6 +280,7 @@ void InitBattleControllers(void);
bool32 IsValidForBattle(struct Pokemon *mon);
void TryReceiveLinkBattleData(void);
void PrepareBufferDataTransferLink(u32 battler, u32 bufferId, u16 size, u8 *data);
void UpdateFriendshipFromXItem(u32 battler);
// emitters
void BtlController_EmitGetMonData(u32 battler, u32 bufferId, u8 requestId, u8 monToCheck);
@ -302,8 +303,8 @@ void BtlController_EmitChooseItem(u32 battler, u32 bufferId, u8 *battlePartyOrde
void BtlController_EmitChoosePokemon(u32 battler, u32 bufferId, u8 caseId, u8 slotId, u16 abilityId, u8 battlerPreventingSwitchout, u8 *data);
void BtlController_EmitHealthBarUpdate(u32 battler, u32 bufferId, u16 hpValue);
void BtlController_EmitExpUpdate(u32 battler, u32 bufferId, u8 partyId, s32 expPoints);
void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status1, u32 status2);
void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 status2, u32 status);
void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status);
void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 isVolatile, u32 status);
void BtlController_EmitDataTransfer(u32 battler, u32 bufferId, u16 size, void *data);
void BtlController_EmitTwoReturnValues(u32 battler, u32 bufferId, u8 ret8, u32 ret32);
void BtlController_EmitChosenMonReturnValue(u32 battler, u32 bufferId, u8 partyId, u8 *battlePartyOrder);
@ -421,11 +422,50 @@ void LinkOpponentBufferExecCompleted(u32 battler);
void SetControllerToLinkPartner(u32 battler);
void LinkPartnerBufferExecCompleted(u32 battler);
void TrySetBattlerShadowSpriteCallback(u32 battler);
void AnimateMonAfterPokeBallFail(u32 battler);
void TryShinyAnimAfterMonAnim(u32 battler);
void WaitForMonAnimAfterLoad(u32 battler);
void BtlController_HandleSwitchInWaitAndEnd(u32 battler);
void BtlController_Intro_DelayAndEnd(u32 battler);
void BtlController_HandleSwitchInShowHealthbox(u32 battler);
void BtlController_HandleSwitchInTryShinyAnim(u32 battler);
void BtlController_HandleSwitchInSoundAndEnd(u32 battler);
void BtlController_HandleSwitchInShowSubstitute(u32 battler);
// oak and old man controller
void SetControllerToOakOrOldMan(u32 battler);
void OakOldManBufferExecCompleted(u32 battler);
// pokedude controller
void SetControllerToPokedude(u32 battler);
void InitPokedudePartyAndOpponent(void);
void PokedudeBufferExecCompleted(u32 battler);
// These flags are set to signal that the indicated message
// was already emitted
// Inflicting damage is key
#define FIRST_BATTLE_MSG_FLAG_INFLICT_DMG 0x1
// Lowering stats is advantageous
#define FIRST_BATTLE_MSG_FLAG_STAT_CHG 0x2
// Keep an eye on your HP
#define FIRST_BATTLE_MSG_FLAG_HP_RESTORE 0x4
//
#define FIRST_BATTLE_MSG_FLAG_PARTY_MENU 0x8
bool8 BtlCtrl_OakOldMan_TestState2Flag(u8 mask);
void BtlCtrl_OakOldMan_SetState2Flag(u8 mask);
void PrintOakText_InflictingDamageIsKey(u32 battler);
void PrintOakText_HowDisappointing(u32 battler);
void PrintOakText_OakNoRunningFromATrainer(u32 battler);
void OakOldManHandleInputChooseMove(u32 battler);
void BtlCtrl_DrawVoiceoverMessageFrame(void);
void BtlCtrl_RemoveVoiceoverMessageFrame(void);
bool32 ShouldBattleRestrictionsApply(u32 battler);
// oak and old man controller
void SetControllerToOakOrOldMan(u32 battler);
void OakOldManBufferExecCompleted(u32 battler);
@ -451,15 +491,4 @@ void OakOldManHandleInputChooseMove(u32 battler);
void BtlCtrl_DrawVoiceoverMessageFrame(void);
void BtlCtrl_RemoveVoiceoverMessageFrame(void);
void TrySetBattlerShadowSpriteCallback(u32 battler);
void TryShinyAnimAfterMonAnim(u32 battler);
void WaitForMonAnimAfterLoad(u32 battler);
void BtlController_HandleSwitchInWaitAndEnd(u32 battler);
void BtlController_Intro_DelayAndEnd(u32 battler);
void BtlController_HandleSwitchInShowHealthbox(u32 battler);
void BtlController_HandleSwitchInTryShinyAnim(u32 battler);
void BtlController_HandleSwitchInSoundAndEnd(u32 battler);
void BtlController_HandleSwitchInShowSubstitute(u32 battler);
#endif // GUARD_BATTLE_CONTROLLERS_H

View File

@ -11,7 +11,6 @@ u16 GetNonDynamaxHP(u32 battler);
u16 GetNonDynamaxMaxHP(u32 battler);
void UndoDynamax(u32 battler);
bool32 IsMoveBlockedByMaxGuard(u32 move);
bool32 IsMoveBlockedByDynamax(u32 move);
u16 GetMaxMove(u32 battler, u32 baseMove);
u32 GetMaxMovePower(u32 move);
@ -20,8 +19,6 @@ void ChooseDamageNonTypesString(u8 type);
void BS_UpdateDynamax(void);
void BS_SetSteelsurge(void);
void BS_TrySetStatus1(void);
void BS_TrySetStatus2(void);
void BS_HealOneSixth(void);
void BS_TryRecycleBerry(void);
void BS_JumpIfDynamaxed(void);

View File

@ -11,10 +11,9 @@ bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattler, u8 atkBattler, u8 de
void InitAndLaunchSpecialAnimation(u8 activeBattler, u8 atkBattler, u8 defBattler, u8 tableId);
bool8 IsBattleSEPlaying(u8 battlerId);
void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId);
void DecompressGhostFrontPic(struct Pokemon *unused, u8 battlerId);
void DecompressGhostFrontPic(u32 battlerId);
void DecompressTrainerFrontPic(u16 frontPicId, u8 battlerId);
void DecompressTrainerBackPic(u16 backPicId, u8 battler);
void DecompressTrainerBackPalette(u16 a1, u8 a2);
void BattleGfxSfxDummy2(u16 species);
void FreeTrainerFrontPicPalette(u16 frontPicId);
bool8 BattleLoadAllHealthBoxesGfx(u8 state);

View File

@ -125,7 +125,7 @@ void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elem
s32 MoveBattleBar(u8 battler, u8 healthboxSpriteId, u8 whichBar, u8 unused);
u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale);
u8 GetHPBarLevel(s16 hp, s16 maxhp);
void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle);
void CreateAbilityPopUp(u8 battlerId, enum Ability ability, bool32 isDoubleBattle);
void DestroyAbilityPopUp(u8 battlerId);
bool32 CanThrowLastUsedBall(void);
void TryHideLastUsedBall(void);

View File

@ -57,9 +57,10 @@ enum FirstTurnEventsStates
FIRST_TURN_EVENTS_TOTEM_BOOST,
FIRST_TURN_EVENTS_NEUTRALIZING_GAS,
FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES,
FIRST_TURN_EVENTS_OPPORTUNIST_1,
FIRST_TURN_EVENTS_ITEM_EFFECTS,
FIRST_TURN_EVENTS_OPPORTUNIST_2,
FIRST_TURN_EVENTS_WHITE_HERB,
FIRST_TURN_EVENTS_OPPORTUNIST,
FIRST_TURN_EVENTS_MIRROR_HERB,
FIRST_TURN_EVENTS_EJECT_PACK,
FIRST_TURN_EVENTS_END,
};
@ -90,18 +91,18 @@ void SpriteCB_TrainerThrowObject(struct Sprite *sprite);
void AnimSetCenterToCornerVecX(struct Sprite *sprite);
void BeginBattleIntroDummy(void);
void BeginBattleIntro(void);
void SwitchInClearSetData(u32 battler);
void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy);
const u8* FaintClearSetData(u32 battler);
void BattleTurnPassed(void);
u8 IsRunningFromBattleImpossible(u32 battler);
void SwitchTwoBattlersInParty(u32 battler, u32 battler2);
void SwitchPartyOrder(u32 battler);
void SwapTurnOrder(u8 id1, u8 id2);
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect holdEffect);
u32 GetBattlerTotalSpeedStatArgs(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect);
u32 GetBattlerTotalSpeedStat(u32 battler);
s32 GetChosenMovePriority(u32 battler, u32 ability);
s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move);
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
s32 GetChosenMovePriority(u32 battler, enum Ability ability);
s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move);
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, enum Ability ability1, enum Ability ability2,
enum ItemHoldEffect holdEffectBattler1, enum ItemHoldEffect holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2);
s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);
s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);
@ -117,6 +118,7 @@ u32 GeneratePersonalityForGender(u32 gender, u32 species);
void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMon *partyEntry);
bool32 CanPlayerForfeitNormalTrainerBattle(void);
bool32 DidPlayerForfeitNormalTrainerBattle(void);
void BattleDebug_WonBattle(void);
extern struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE];

View File

@ -2,6 +2,7 @@
#define GUARD_BATTLE_MESSAGE_H
#include "constants/battle.h"
#include "constants/battle_string_ids.h"
// This buffer can hold many different things. Some of the things it can hold
// that have explicit sizes are listed below to ensure it can contain them.
@ -83,8 +84,8 @@
#define B_TXT_TRAINER2_NAME_WITH_CLASS 0x43
#define B_TXT_PARTNER_NAME_WITH_CLASS 0x44
#define B_TXT_ATK_TRAINER_NAME_WITH_CLASS 0x45
#define B_TXT_SCR_TEAM1 0x46
#define B_TXT_SCR_TEAM2 0x47
#define B_TXT_EFF_TEAM1 0x46
#define B_TXT_EFF_TEAM2 0x47
// for B_TXT_BUFF1, B_TXT_BUFF2 and B_TXT_BUFF3
@ -249,7 +250,7 @@ struct BattleMsgData
u8 textBuffs[3][TEXT_BUFF_ARRAY_COUNT];
};
void BufferStringBattle(u16 stringID, u32 battler);
void BufferStringBattle(enum StringID stringID, u32 battler);
u32 BattleStringExpandPlaceholdersToDisplayedString(const u8 *src);
u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst, u32 dstSize);
void BattleHandleAddTextPrinter(const u8 *text, u8 arg1);
@ -299,4 +300,7 @@ extern const u8 gText_Win[];
extern const u8 gText_Loss[];
extern const u8 gText_Draw[];
extern const u16 gStatUpStringIds[];
extern const u16 gStatDownStringIds[];
#endif // GUARD_BATTLE_MESSAGE_H

View File

@ -40,11 +40,12 @@ union TRANSPARENT StatChangeFlags
};
};
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk);
s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk);
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum ItemHoldEffect holdEffectAtk);
s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum ItemHoldEffect holdEffectAtk);
s32 GetCritHitOdds(s32 critChanceIndex);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
u8 GetBattlerTurnOrderNum(u8 battler);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, u32 atkHoldEffect, u32 defHoldEffect);
bool32 HasBattlerActedThisTurn(u32 battler);
u32 GetBattlerTurnOrderNum(u32 battler);
bool32 NoAliveMonsForBattlerSide(u32 battler);
bool32 NoAliveMonsForPlayer(void);
bool32 NoAliveMonsForEitherParty(void);
@ -59,24 +60,23 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 DoesDisguiseBlockMove(u32 battler, u32 move);
bool32 CanUseLastResort(u8 battlerId);
u32 IsFlowerVeilProtected(u32 battler);
u32 IsLeafGuardProtected(u32 battler, u32 ability);
bool32 IsShieldsDownProtected(u32 battler, u32 ability);
u32 IsAbilityStatusProtected(u32 battler, u32 ability);
u32 IsLeafGuardProtected(u32 battler, enum Ability ability);
bool32 IsShieldsDownProtected(u32 battler, enum Ability ability);
u32 IsAbilityStatusProtected(u32 battler, enum Ability ability);
bool32 TryResetBattlerStatChanges(u8 battler);
bool32 CanCamouflage(u8 battlerId);
u32 GetNaturePowerMove(u32 battler);
void StealTargetItem(u8 battlerStealer, u8 battlerItem);
u8 GetCatchingBattler(void);
u32 GetHighestStatId(u32 battlerId);
bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType);
bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, u32 moveType);
bool32 IsMoveNotAllowedInSkyBattles(u32 move);
bool32 DoSwitchInAbilities(u32 battlerId);
u8 GetFirstFaintedPartyIndex(u8 battlerId);
bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler);
void SaveBattlerTarget(u32 battler);
void SaveBattlerAttacker(u32 battler);
bool32 IsMonGettingExpSentOut(void);
bool32 CanBurnHitThaw(u16 move);
bool32 IsMonGettingExpSentOut(void);
extern void (*const gBattleScriptingCommandsTable[])(void);
extern const struct StatFractions gAccuracyStageRatios[];

View File

@ -3,17 +3,17 @@
extern const u8 BattleScript_SupersweetSyrupActivates[];
extern const u8 BattleScript_OpportunistCopyStatChange[];
extern const u8 BattleScript_OpportunistCopyStatChangeEnd3[];
extern const u8 BattleScript_MirrorHerbCopyStatChange[];
extern const u8 BattleScript_MirrorHerbCopyStatChangeEnd2[];
extern const u8 BattleScript_NotAffected[];
extern const u8 BattleScript_HitFromCritCalc[];
extern const u8 BattleScript_MoveEnd[];
extern const u8 BattleScript_MakeMoveMissed[];
extern const u8 BattleScript_PrintMoveMissed[];
extern const u8 BattleScript_MoveMissedPause[];
extern const u8 BattleScript_MoveMissedPause[];
extern const u8 BattleScript_MoveMissed[];
extern const u8 BattleScript_FlingFailConsumeItem[];
extern const u8 BattleScript_FailedFromAtkString[];
extern const u8 BattleScript_FailedFromAtkCanceler[];
extern const u8 BattleScript_ButItFailed[];
extern const u8 BattleScript_StatUp[];
@ -92,7 +92,7 @@ extern const u8 BattleScript_AllStatsUp[];
extern const u8 BattleScript_RapidSpinAway[];
extern const u8 BattleScript_WrapFree[];
extern const u8 BattleScript_LeechSeedFree[];
extern const u8 BattleScript_SpikesFree[];
extern const u8 BattleScript_SpinHazardsAway[];
extern const u8 BattleScript_MonTookFutureAttack[];
extern const u8 BattleScript_NoMovesLeft[];
extern const u8 BattleScript_SelectingMoveWithNoPP[];
@ -150,7 +150,7 @@ extern const u8 BattleScript_TargetWokeUp[];
extern const u8 BattleScript_TargetBurnHeal[];
extern const u8 BattleScript_TargetPoisonHealed[];
extern const u8 BattleScript_MoveEffectSleep[];
extern const u8 BattleScript_YawnMakesAsleep[];
extern const u8 BattleScript_YawnMakesAsleepEnd2[];
extern const u8 BattleScript_MoveEffectPoison[];
extern const u8 BattleScript_MoveEffectBurn[];
extern const u8 BattleScript_MoveEffectFrostbite[];
@ -168,7 +168,6 @@ extern const u8 BattleScript_DoRecoil33[];
extern const u8 BattleScript_Recoil33End[];
extern const u8 BattleScript_ItemSteal[];
extern const u8 BattleScript_DrizzleActivates[];
extern const u8 BattleScript_SpeedBoostActivates[];
extern const u8 BattleScript_TraceActivates[];
extern const u8 BattleScript_RainDishActivates[];
extern const u8 BattleScript_SandstreamActivates[];
@ -180,11 +179,8 @@ extern const u8 BattleScript_DroughtActivates[];
extern const u8 BattleScript_TookAttack[];
extern const u8 BattleScript_SturdyPreventsOHKO[];
extern const u8 BattleScript_DampStopsExplosion[];
extern const u8 BattleScript_MoveHPDrain_PPLoss[];
extern const u8 BattleScript_MoveHPDrain[];
extern const u8 BattleScript_MonMadeMoveUseless_PPLoss[];
extern const u8 BattleScript_MonMadeMoveUseless[];
extern const u8 BattleScript_FlashFireBoost_PPLoss[];
extern const u8 BattleScript_FlashFireBoost[];
extern const u8 BattleScript_AbilityNoStatLoss[];
extern const u8 BattleScript_ItemNoStatLoss[];
@ -279,10 +275,10 @@ extern const u8 BattleScript_WaterSportEnds[];
extern const u8 BattleScript_SturdiedMsg[];
extern const u8 BattleScript_GravityEnds[];
extern const u8 BattleScript_MoveStatDrain[];
extern const u8 BattleScript_MoveStatDrain_PPLoss[];
extern const u8 BattleScript_TargetsStatWasMaxedOut[];
extern const u8 BattleScript_AttackerAbilityStatRaise[];
extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[];
extern const u8 BattleScript_AttackerAbilityStatRaiseEnd2[];
extern const u8 BattleScript_PoisonHealActivates[];
extern const u8 BattleScript_BadDreamsActivates[];
extern const u8 BattleScript_SwitchInAbilityMsg[];
@ -296,6 +292,7 @@ extern const u8 BattleScript_CursedBodyActivates[];
extern const u8 BattleScript_MummyActivates[];
extern const u8 BattleScript_WeakArmorActivates[];
extern const u8 BattleScript_FellStingerRaisesStat[];
extern const u8 BattleScript_RemoveTerrain[];
extern const u8 BattleScript_SnowWarningActivatesHail[];
extern const u8 BattleScript_SnowWarningActivatesSnow[];
extern const u8 BattleScript_PickupActivates[];
@ -311,13 +308,7 @@ extern const u8 BattleScript_SelectingNotAllowedMoveGravityInPalace[];
extern const u8 BattleScript_SelectingNotAllowedMoveHealBlock[];
extern const u8 BattleScript_MoveUsedHealBlockPrevents[];
extern const u8 BattleScript_SelectingNotAllowedMoveHealBlockInPalace[];
extern const u8 BattleScript_ToxicSpikesFree[];
extern const u8 BattleScript_StickyWebFree[];
extern const u8 BattleScript_StealthRockFree[];
extern const u8 BattleScript_SpikesDefog[];
extern const u8 BattleScript_ToxicSpikesDefog[];
extern const u8 BattleScript_StickyWebDefog[];
extern const u8 BattleScript_StealthRockDefog[];
extern const u8 BattleScript_DefogClearHazards[];
extern const u8 BattleScript_MegaEvolution[];
extern const u8 BattleScript_WishMegaEvolution[];
extern const u8 BattleScript_MoveEffectClearSmog[];
@ -333,7 +324,6 @@ extern const u8 BattleScript_ProteanActivates[];
extern const u8 BattleScript_DazzlingProtected[];
extern const u8 BattleScript_MoveUsedPsychicTerrainPrevents[];
extern const u8 BattleScript_MoveUsedPowder[];
extern const u8 BattleScript_ZMoveActivatePowder[];
extern const u8 BattleScript_SelectingNotAllowedStuffCheeks[];
extern const u8 BattleScript_SelectingNotAllowedStuffCheeksInPalace[];
extern const u8 BattleScript_SelectingNotAllowedBelch[];
@ -343,6 +333,7 @@ extern const u8 BattleScript_GrassySurgeActivates[];
extern const u8 BattleScript_MistySurgeActivates[];
extern const u8 BattleScript_ElectricSurgeActivates[];
extern const u8 BattleScript_EffectSpectralThief[];
extern const u8 BattleScript_EffectLifeDew[];
extern const u8 BattleScript_AbilityRaisesDefenderStat[];
extern const u8 BattleScript_PowderMoveNoEffect[];
extern const u8 BattleScript_GrassyTerrainHeals[];
@ -375,10 +366,11 @@ extern const u8 BattleScript_IllusionOffEnd3[];
extern const u8 BattleScript_IllusionOffAndTerastallization[];
extern const u8 BattleScript_DancerActivates[];
extern const u8 BattleScript_AftermathDmg[];
extern const u8 BattleScript_AttackerFormChange[];
extern const u8 BattleScript_AttackerFormChangeEnd3[];
extern const u8 BattleScript_BattlerFormChange[];
extern const u8 BattleScript_BattlerFormChangeEnd2[];
extern const u8 BattleScript_BattlerFormChangeEnd3[];
extern const u8 BattleScript_AttackerFormChangeWithString[];
extern const u8 BattleScript_AttackerFormChangeWithStringEnd3[];
extern const u8 BattleScript_BattlerFormChangeWithStringEnd3[];
extern const u8 BattleScript_TargetFormChange[];
extern const u8 BattleScript_AnticipationActivates[];
extern const u8 BattleScript_SlowStartEnds[];
@ -427,9 +419,10 @@ extern const u8 BattleScript_EjectPackActivates[];
extern const u8 BattleScript_MentalHerbCureRet[];
extern const u8 BattleScript_MentalHerbCureEnd2[];
extern const u8 BattleScript_TerrainPreventsEnd2[];
extern const u8 BattleScript_ImmunityProtectedEnd2[];
extern const u8 BattleScript_MistyTerrainPrevents[];
extern const u8 BattleScript_ElectricTerrainPrevents[];
extern const u8 BattleScript_DarkTypePreventsPrankster[];
extern const u8 BattleScript_DoesntAffectTargetAtkString[];
extern const u8 BattleScript_GulpMissileGorging[];
extern const u8 BattleScript_GulpMissileGulping[];
extern const u8 BattleScript_GulpMissileFormChange[];
@ -451,8 +444,7 @@ extern const u8 BattleScript_WanderingSpiritActivates[];
extern const u8 BattleScript_MirrorArmorReflect[];
extern const u8 BattleScript_GooeyActivates[];
extern const u8 BattleScript_PastelVeilActivates[];
extern const u8 BattleScript_AttackerFormChangeEnd3NoPopup[];
extern const u8 BattleScript_AttackerFormChangeWithStringEnd3NoPopup[];
extern const u8 BattleScript_BattlerFormChangeEnd3NoPopup[];
extern const u8 BattleScript_AttackerFormChangeMoveEffect[];
extern const u8 BattleScript_BothCanNoLongerEscape[];
extern const u8 BattleScript_OctolockEndTurn[];
@ -470,6 +462,7 @@ extern const u8 BattleScript_RemoveFireType[];
extern const u8 BattleScript_TargetAbilityStatRaiseRet[];
extern const u8 BattleScript_RemoveElectricType[];
extern const u8 BattleScript_SeedSowerActivates[];
extern const u8 BattleScript_BerserkActivates[];
extern const u8 BattleScript_AngerShellActivates[];
extern const u8 BattleScript_WellBakedBodyActivates[];
extern const u8 BattleScript_WindRiderActivatesMoveEnd[];
@ -522,9 +515,8 @@ extern const u8 BattleScript_BoosterEnergyEnd2[];
extern const u8 BattleScript_BoosterEnergyRet[];
extern const u8 BattleScript_TeraShellDistortingTypeMatchups[];
extern const u8 BattleScript_TeraFormChange[];
extern const u8 BattleScript_SleepClausePreventsEnd[];
extern const u8 BattleScript_SleepClausePreventsEnd2[];
extern const u8 BattleScript_PowerConstruct[];
extern const u8 BattleScript_AbilityProtectsDoesntAffect[];
extern const u8 BattleScript_ImmunityProtected[];
extern const u8 BattleScript_SafeguardProtected[];
@ -536,6 +528,7 @@ extern const u8 BattleScript_AlreadyPoisoned[];
extern const u8 BattleScript_AlreadyParalyzed[];
extern const u8 BattleScript_AlreadyBurned[];
extern const u8 BattleScript_PrintAbilityMadeIneffective[];
extern const u8 BattleScript_ItDoesntAffectFoe[];
// zmoves
extern const u8 BattleScript_ZMoveActivateDamaging[];
@ -553,14 +546,12 @@ extern const u8 BattleScript_EffectSetWeather[];
extern const u8 BattleScript_EffectSetTerrain[];
extern const u8 BattleScript_EffectStonesurge[];
extern const u8 BattleScript_EffectSteelsurge[];
extern const u8 BattleScript_SteelsurgeFree[];
extern const u8 BattleScript_SteelsurgeDefog[];
extern const u8 BattleScript_DamageNonTypesStarts[];
extern const u8 BattleScript_DamageNonTypesContinues[];
extern const u8 BattleScript_DefogTryHazards[];
extern const u8 BattleScript_EffectAuroraVeilSuccess[];
extern const u8 BattleScript_MoveEffectDefog[];
extern const u8 BattleScript_MoveEffectAuroraVeil[];
extern const u8 BattleScript_EffectGravitySuccess[];
extern const u8 BattleScript_EffectYawnSuccess[];
extern const u8 BattleScript_MoveEffectYawnSide[];
extern const u8 BattleScript_EffectTryReducePP[];
extern const u8 BattleScript_EffectParalyzeSide[];
extern const u8 BattleScript_EffectPoisonSide[];
@ -587,7 +578,6 @@ extern const u8 BattleScript_EffectAbsorb[];
extern const u8 BattleScript_EffectAbsorbLiquidOoze[];
extern const u8 BattleScript_EffectExplosion[];
extern const u8 BattleScript_EffectDreamEater[];
extern const u8 BattleScript_EffectMirrorMove[];
extern const u8 BattleScript_EffectAttackUp[];
extern const u8 BattleScript_EffectDefenseUp[];
extern const u8 BattleScript_EffectSpeedUp[];
@ -611,6 +601,8 @@ extern const u8 BattleScript_EffectConversion[];
extern const u8 BattleScript_EffectRestoreHp[];
extern const u8 BattleScript_EffectLightScreen[];
extern const u8 BattleScript_EffectRest[];
extern const u8 BattleScript_RestIsAlreadyAsleep[];
extern const u8 BattleScript_InsomniaProtects[];
extern const u8 BattleScript_EffectOHKO[];
extern const u8 BattleScript_EffectHealBlock[];
extern const u8 BattleScript_RecoilIfMiss[];
@ -637,7 +629,6 @@ extern const u8 BattleScript_EffectTwoTurnsAttack[];
extern const u8 BattleScript_EffectSubstitute[];
extern const u8 BattleScript_EffectRage[];
extern const u8 BattleScript_EffectMimic[];
extern const u8 BattleScript_EffectMetronome[];
extern const u8 BattleScript_EffectLeechSeed[];
extern const u8 BattleScript_EffectDoNothing[];
extern const u8 BattleScript_EffectHoldHands[];
@ -651,11 +642,10 @@ extern const u8 BattleScript_EffectSnore[];
extern const u8 BattleScript_EffectConversion2[];
extern const u8 BattleScript_EffectLockOn[];
extern const u8 BattleScript_EffectSketch[];
extern const u8 BattleScript_EffectSleepTalk[];
extern const u8 BattleScript_EffectDestinyBond[];
extern const u8 BattleScript_EffectSpite[];
extern const u8 BattleScript_EffectHealBell[];
extern const u8 BattleScript_EffectHealBell_FromHeal[];
extern const u8 BattleScript_MoveEffectAromatherapy[];
extern const u8 BattleScript_EffectMeanLook[];
extern const u8 BattleScript_EffectNightmare[];
extern const u8 BattleScript_EffectMinimize[];
@ -693,8 +683,6 @@ extern const u8 BattleScript_EffectBeatUp[];
extern const u8 BattleScript_EffectSemiInvulnerable[];
extern const u8 BattleScript_EffectDefenseCurl[];
extern const u8 BattleScript_EffectSoftboiled[];
extern const u8 BattleScript_EffectFirstTurnOnly[];
extern const u8 BattleScript_EffectUproar[];
extern const u8 BattleScript_EffectStockpile[];
extern const u8 BattleScript_EffectSpitUp[];
extern const u8 BattleScript_EffectSwallow[];
@ -706,14 +694,12 @@ extern const u8 BattleScript_EffectNonVolatileStatus[];
extern const u8 BattleScript_EffectMemento[];
extern const u8 BattleScript_EffectFocusPunch[];
extern const u8 BattleScript_EffectFollowMe[];
extern const u8 BattleScript_EffectNaturePower[];
extern const u8 BattleScript_EffectCharge[];
extern const u8 BattleScript_EffectTaunt[];
extern const u8 BattleScript_EffectHelpingHand[];
extern const u8 BattleScript_EffectTrick[];
extern const u8 BattleScript_EffectRolePlay[];
extern const u8 BattleScript_EffectWish[];
extern const u8 BattleScript_EffectAssist[];
extern const u8 BattleScript_EffectIngrain[];
extern const u8 BattleScript_EffectMagicCoat[];
extern const u8 BattleScript_EffectRecycle[];
@ -761,7 +747,6 @@ extern const u8 BattleScript_EffectGuardSplit[];
extern const u8 BattleScript_EffectStickyWeb[];
extern const u8 BattleScript_EffectMetalBurst[];
extern const u8 BattleScript_EffectLuckyChant[];
extern const u8 BattleScript_EffectSuckerPunch[];
extern const u8 BattleScript_EffectSimpleBeam[];
extern const u8 BattleScript_EffectEntrainment[];
extern const u8 BattleScript_EffectHealPulse[];
@ -774,14 +759,12 @@ extern const u8 BattleScript_EffectElectricTerrain[];
extern const u8 BattleScript_EffectPsychicTerrain[];
extern const u8 BattleScript_EffectAttackAccUp[];
extern const u8 BattleScript_EffectAttackSpAttackUp[];
extern const u8 BattleScript_EffectMeFirst[];
extern const u8 BattleScript_EffectQuiverDance[];
extern const u8 BattleScript_EffectCoil[];
extern const u8 BattleScript_EffectElectrify[];
extern const u8 BattleScript_EffectReflectType[];
extern const u8 BattleScript_EffectSoak[];
extern const u8 BattleScript_EffectGrowth[];
extern const u8 BattleScript_EffectLastResort[];
extern const u8 BattleScript_EffectShellSmash[];
extern const u8 BattleScript_EffectShiftGear[];
extern const u8 BattleScript_EffectDefenseUp3[];
@ -794,7 +777,6 @@ extern const u8 BattleScript_AbilityPreventsPhasingOutRet[];
extern const u8 BattleScript_PrintMonIsRootedRet[];
extern const u8 BattleScript_FinalGambit[];
extern const u8 BattleScript_EffectAutotomize[];
extern const u8 BattleScript_EffectCopycat[];
extern const u8 BattleScript_EffectDefog[];
extern const u8 BattleScript_EffectHitEnemyHealAlly[];
extern const u8 BattleScript_EffectSynchronoise[];
@ -811,14 +793,12 @@ extern const u8 BattleScript_EffectAcupressure[];
extern const u8 BattleScript_EffectAromaticMist[];
extern const u8 BattleScript_EffectPowder[];
extern const u8 BattleScript_EffectPartingShot[];
extern const u8 BattleScript_EffectMatBlock[];
extern const u8 BattleScript_EffectInstruct[];
extern const u8 BattleScript_EffectLaserFocus[];
extern const u8 BattleScript_EffectMagneticFlux[];
extern const u8 BattleScript_EffectGearUp[];
extern const u8 BattleScript_EffectStrengthSap[];
extern const u8 BattleScript_EffectPurify[];
extern const u8 BattleScript_FailIfNotArgType[];
extern const u8 BattleScript_EffectShoreUp[];
extern const u8 BattleScript_EffectGeomancy[];
extern const u8 BattleScript_EffectFairyLock[];
@ -835,7 +815,6 @@ extern const u8 BattleScript_MoveEffectLeechSeed[];
extern const u8 BattleScript_MoveEffectHaze[];
extern const u8 BattleScript_MoveEffectIonDeluge[];
extern const u8 BattleScript_EffectHyperspaceFury[];
extern const u8 BattleScript_EffectAuraWheel[];
extern const u8 BattleScript_EffectNoRetreat[];
extern const u8 BattleScript_EffectTarShot[];
extern const u8 BattleScript_EffectPoltergeist[];
@ -845,7 +824,7 @@ extern const u8 BattleScript_EffectSkyDrop[];
extern const u8 BattleScript_EffectMeteorBeam[];
extern const u8 BattleScript_EffectCourtChange[];
extern const u8 BattleScript_EffectExtremeEvoboost[];
extern const u8 BattleScript_EffectHitSetRemoveTerrain[];
extern const u8 BattleScript_EffectHitSetTerrain[];
extern const u8 BattleScript_EffectDarkVoid[];
extern const u8 BattleScript_EffectVictoryDance[];
extern const u8 BattleScript_EffectTeatime[];
@ -871,6 +850,18 @@ extern const u8 BattleScript_FickleBeamDoubled[];
extern const u8 BattleScript_QuestionForfeitBattle[];
extern const u8 BattleScript_ForfeitBattleGaveMoney[];
extern const u8 BattleScript_AbilityPopUp[];
extern const u8 BattleScript_Attackstring[];
extern const u8 BattleScript_SubmoveAttackstring[];
extern const u8 BattleScript_MetronomeAttackstring[];
extern const u8 BattleScript_SleepTalkAttackstring[];
extern const u8 BattleScript_NaturePowerAttackstring[];
extern const u8 BattleScript_PokemonCantUseTheMove[];
extern const u8 BattleScript_GhostBallDodge[];
extern const u8 BattleScript_GhostGetOutGetOut[];
extern const u8 BattleScript_TooScaredToMove[];
extern const u8 BattleScript_SilphScopeUnveiled[];
// pokefirered
extern const u8 BattleScript_BattleTowerTrainerBattleWon[];
@ -881,4 +872,4 @@ extern const u8 BattleScript_GhostBallDodge[];
extern const u8 BattleScript_OldMan_Pokedude_CaughtMessage[];
extern const u8 BattleScript_SilphScopeUnveiled[];
#endif // GUARD_BATTLE_SCRIPTS_H
#endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -7,7 +7,7 @@ bool32 CanTerastallize(u32 battler);
u32 GetBattlerTeraType(u32 battler);
void ExpendTypeStellarBoost(u32 battler, u32 type);
bool32 IsTypeStellarBoosted(u32 battler, u32 type);
uq4_12_t GetTeraMultiplier(u32 battler, u32 type);
uq4_12_t GetTeraMultiplier(struct DamageContext *ctx);
u16 GetTeraTypeRGB(u32 type);

View File

@ -23,17 +23,12 @@
#define MOVE_LIMITATION_PLACEHOLDER (1 << 15)
#define MOVE_LIMITATIONS_ALL 0xFFFF
enum NonVolatileStatus
// Switches between simulated battle calc and actual battle combat
enum FunctionCallOption
{
STATUS_CHECK_TRIGGER,
STATUS_RUN_SCRIPT,
};
enum AbilityEffectOptions
{
ABILITY_CHECK_TRIGGER,
ABILITY_CHECK_TRIGGER_AI,
ABILITY_RUN_SCRIPT,
CHECK_TRIGGER, // Check the function without running scripts / setting any flags.
AI_CHECK, // Check the function without running scripts / setting any flags. Same as CHECK_TRIGGER but only used when additional data has to be fetched during ai calcs
RUN_SCRIPT, // Used during actual combat where a script has to be run / flags need to be set
};
enum MoveAbsorbed
@ -48,31 +43,30 @@ enum {
ABILITYEFFECT_ON_SWITCHIN,
ABILITYEFFECT_ENDTURN,
ABILITYEFFECT_MOVE_END_ATTACKER,
ABILITYEFFECT_COLOR_CHANGE, // Color Change, Berserk, Anger Shell
ABILITYEFFECT_MOVE_END,
ABILITYEFFECT_IMMUNITY,
ABILITYEFFECT_SYNCHRONIZE,
ABILITYEFFECT_ATK_SYNCHRONIZE,
ABILITYEFFECT_MOVE_END_OTHER,
ABILITYEFFECT_NEUTRALIZINGGAS,
ABILITYEFFECT_FIELD_SPORT, // Only used if B_SPORT_TURNS >= GEN_6
ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN,
ABILITYEFFECT_ON_WEATHER,
ABILITYEFFECT_ON_TERRAIN,
ABILITYEFFECT_SWITCH_IN_TERRAIN,
ABILITYEFFECT_SWITCH_IN_WEATHER,
ABILITYEFFECT_OPPORTUNIST,
ABILITYEFFECT_OPPORTUNIST_FIRST_TURN,
ABILITYEFFECT_SWITCH_IN_STATUSES,
};
// Special cases
#define ABILITYEFFECT_MUD_SPORT 252 // Only used if B_SPORT_TURNS >= GEN_6
#define ABILITYEFFECT_WATER_SPORT 253 // Only used if B_SPORT_TURNS >= GEN_6
// For the first argument of ItemBattleEffects, to deteremine which block of item effects to try
enum ItemCaseId
{
ITEMEFFECT_NONE,
ITEMEFFECT_ON_SWITCH_IN,
ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN,
ITEMEFFECT_LEFTOVERS, // Leftovers, Black Sludge
ITEMEFFECT_NORMAL,
ITEMEFFECT_TRY_HEALING,
ITEMEFFECT_MOVE_END,
@ -81,7 +75,11 @@ enum ItemCaseId
ITEMEFFECT_ORBS,
ITEMEFFECT_LIFEORB_SHELLBELL,
ITEMEFFECT_USE_LAST_ITEM, // move end effects for just the battler, not whole field
ITEMEFFECT_STATS_CHANGED, // For White Herb and Eject Pack
ITEMEFFECT_WHITE_HERB,
ITEMEFFECT_WHITE_HERB_ENDTURN,
ITEMEFFECT_WHITE_HERB_FIRST_TURN,
ITEMEFFECT_MIRROR_HERB,
ITEMEFFECT_MIRROR_HERB_FIRST_TURN,
};
enum ItemEffect
@ -115,33 +113,38 @@ struct TypePower
enum MoveSuccessOrder
{
CANCELLER_FLAGS,
CANCELLER_CLEAR_FLAGS,
CANCELLER_STANCE_CHANGE_1,
CANCELLER_SKY_DROP,
CANCELLER_RECHARGE,
CANCELLER_ASLEEP_OR_FROZEN,
CANCELLER_POWER_POINTS,
CANCELLER_OBEDIENCE,
CANCELLER_TRUANT,
CANCELLER_FLINCH,
CANCELLER_DISABLED,
CANCELLER_VOLATILE_BLOCKED,
CANCELLER_VOLATILE_BLOCKED, // Gravity / Heal Block / Throat Chop
CANCELLER_TAUNTED,
CANCELLER_IMPRISONED,
CANCELLER_CONFUSED,
CANCELLER_GHOST, // pokefirered
CANCELLER_PARALYSED,
CANCELLER_INFATUATION,
CANCELLER_GHOST, // pokefirered
CANCELLER_BIDE,
CANCELLER_Z_MOVES,
CANCELLER_CHOICE_LOCK,
CANCELLER_CALLSUBMOVE,
CANCELLER_THAW,
CANCELLER_STANCE_CHANGE_2,
CANCELLER_ATTACKSTRING,
CANCELLER_PPDEDUCTION,
CANCELLER_WEATHER_PRIMAL,
CANCELLER_DYNAMAX_BLOCKED,
CANCELLER_MOVE_FAILURE,
CANCELLER_POWDER_STATUS,
CANCELLER_PRIORITY_BLOCK,
CANCELLER_PROTEAN,
CANCELLER_PSYCHIC_TERRAIN,
CANCELLER_EXPLODING_DAMP,
CANCELLER_MULTIHIT_MOVES,
CANCELLER_Z_MOVES,
CANCELLER_MULTI_TARGET_MOVES,
CANCELLER_END,
};
@ -159,7 +162,8 @@ enum Obedience
enum MoveCanceller
{
MOVE_STEP_SUCCESS,
MOVE_STEP_BREAK,
MOVE_STEP_BREAK, // Breaks out of the function to run a script
MOVE_STEP_FAILURE, // Same as break but breaks out of it due to move failure and jumps to script that handles the failure
MOVE_STEP_REMOVES_STATUS,
};
@ -179,12 +183,21 @@ struct DamageContext
u32 fixedBasePower:8;
u32 padding2:8;
uq4_12_t typeEffectivenessModifier;
u32 abilityAtk:16;
u32 abilityDef:16;
enum Ability abilityAtk;
enum Ability abilityDef;
enum ItemHoldEffect holdEffectAtk:16;
enum ItemHoldEffect holdEffectDef:16;
};
struct BattleContext
{
u32 battlerAtk:3;
u32 battlerDef:3;
u32 currentMove:16;
enum BattleMoveEffects moveEffect:10;
enum Ability ability[MAX_BATTLERS_COUNT];
};
enum SleepClauseBlock
{
NOT_BLOCKED_BY_SLEEP_CLAUSE,
@ -229,7 +242,7 @@ void MarkBattlerForControllerExec(u32 battler);
void MarkBattlerReceivedLinkData(u32 battler);
const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState);
bool32 WasUnableToUseMove(u32 battler);
bool32 ShouldDefiantCompetitiveActivate(u32 battler, u32 ability);
bool32 ShouldDefiantCompetitiveActivate(u32 battler, enum Ability ability);
void PrepareStringBattle(enum StringID stringId, u32 battler);
void ResetSentPokesToOpponentValue(void);
void OpponentSwitchInResetSentPokesToOpponentValue(u32 battler);
@ -243,28 +256,27 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check);
bool32 AreAllMovesUnusable(u32 battler);
u8 GetImprisonedMovesCount(u32 battler, u16 move);
s32 GetDrainedBigRootHp(u32 battler, s32 hp);
bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck);
bool32 IsAbilityAndRecord(u32 battler, enum Ability battlerAbility, enum Ability abilityToCheck);
u32 DoEndTurnEffects(void);
bool32 HandleFaintedMonActions(void);
void TryClearRageAndFuryCutter(void);
enum MoveCanceller AtkCanceller_MoveSuccessOrder(void);
void SetAtkCancellerForCalledMove(void);
enum MoveCanceller AtkCanceller_MoveSuccessOrder(struct BattleContext *ctx);
bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2);
bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility);
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum AbilityEffectOptions option);
bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum AbilityEffectOptions option);
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg);
bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option);
bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, u32 moveType, enum FunctionCallOption option);
u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg);
bool32 TryPrimalReversion(u32 battler);
bool32 IsNeutralizingGasOnField(void);
bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability);
bool32 IsMoldBreakerTypeAbility(u32 battler, enum Ability ability);
u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler);
u32 GetBattlerAbilityNoAbilityShield(u32 battler);
u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityShield);
u32 GetBattlerAbility(u32 battler);
u32 IsAbilityOnSide(u32 battler, u32 ability);
u32 IsAbilityOnOpposingSide(u32 battler, u32 ability);
u32 IsAbilityOnField(u32 ability);
u32 IsAbilityOnFieldExcept(u32 battler, u32 ability);
enum Ability GetBattlerAbility(u32 battler);
u32 IsAbilityOnSide(u32 battler, enum Ability ability);
u32 IsAbilityOnOpposingSide(u32 battler, enum Ability ability);
u32 IsAbilityOnField(enum Ability ability);
u32 IsAbilityOnFieldExcept(u32 battler, enum Ability ability);
u32 IsAbilityPreventingEscape(u32 battler);
bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move);
u32 GetProtectType(enum ProtectMethod method);
@ -277,21 +289,24 @@ void HandleAction_RunBattleScript(void);
u32 SetRandomTarget(u32 battler);
u32 GetBattleMoveTarget(u16 move, u8 setTarget);
u8 GetAttackerObedienceForAction();
enum ItemHoldEffect GetBattlerHoldEffect(u32 battler, bool32 checkNegating);
enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating);
enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility);
enum ItemHoldEffect GetBattlerHoldEffect(u32 battler);
enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler);
enum ItemHoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler);
enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability);
u32 GetBattlerHoldEffectParam(u32 battler);
bool32 IsMoveMakingContact(u32 move, u32 battlerAtk);
bool32 IsBattlerGrounded(u32 battler);
bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move);
bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move);
bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect);
u32 GetMoveSlot(u16 *moves, u32 move);
u32 GetBattlerWeight(u32 battler);
u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer);
u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter);
s32 CalculateMoveDamage(struct DamageContext *ctx);
s32 CalculateMoveDamageVars(struct DamageContext *ctx);
s32 DoFixedDamageMoveCalc(struct DamageContext *ctx);
s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg);
uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx);
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, enum Ability abilityDef);
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType);
void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags);
@ -313,7 +328,7 @@ bool32 TryClearIllusion(u32 battler, u32 caseID);
u32 GetIllusionMonSpecies(u32 battler);
struct Pokemon *GetIllusionMonPtr(u32 battler);
void ClearIllusionMon(u32 battler);
u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pokemon *partnerMon);
u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pokemon *partnerMon, u32 battler);
bool32 SetIllusionMon(struct Pokemon *mon, u32 battler);
bool32 ShouldGetStatBadgeBoost(u16 flagId, u32 battler);
enum DamageCategory GetBattleMoveCategory(u32 move);
@ -337,7 +352,6 @@ bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes);
void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast);
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind);
bool32 TryRoomService(u32 battler);
void BufferStatChange(u32 battler, u8 statId, enum StringID stringId);
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget);
u16 GetUsedHeldItem(u32 battler);
bool32 PickupHasValidTarget(u32 battler);
@ -359,15 +373,15 @@ bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef);
bool32 MoodyCantRaiseStat(u32 stat);
bool32 MoodyCantLowerStat(u32 stat);
bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, u32 abilityDef, enum SleepClauseBlock isBlockedBySleepClause);
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef);
bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, u32 ability);
bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef);
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffects secondaryMoveEffect, enum NonVolatileStatus option);
bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, enum SleepClauseBlock isBlockedBySleepClause);
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef);
bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, enum Ability ability);
bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect secondaryMoveEffect, enum FunctionCallOption option);
bool32 CanBeConfused(u32 battler);
bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag);
bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect, u32 terrainFlag);
u32 GetBattlerAffectionHearts(u32 battler);
void TryToRevertMimicryAndFlags(void);
bool32 BattleArenaTurnEnd(void);
@ -377,8 +391,8 @@ void RemoveConfusionStatus(u32 battler);
u8 GetBattlerGender(u32 battler);
bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2);
bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2);
u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect);
bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect);
u32 CalcSecondaryEffectChance(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect);
bool32 MoveEffectIsGuaranteed(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect);
void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]);
u32 GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera);
bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon);
@ -391,19 +405,34 @@ bool32 IsSleepClauseActiveForSide(u32 battlerSide);
bool32 IsSleepClauseEnabled();
void ClearDamageCalcResults(void);
u32 DoesDestinyBondFail(u32 battler);
bool32 IsMoveEffectBlockedByTarget(u32 ability);
bool32 IsMoveEffectBlockedByTarget(enum Ability ability);
bool32 IsPursuitTargetSet(void);
void ClearPursuitValuesIfSet(u32 battler);
void ClearPursuitValues(void);
bool32 HasWeatherEffect(void);
u32 RestoreWhiteHerbStats(u32 battler);
bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 HadMoreThanHalfHpNowDoesnt(u32 battler);
void UpdateStallMons(void);
bool32 TryRestoreHPBerries(u32 battler, enum ItemCaseId caseId);
bool32 TrySwitchInEjectPack(enum ItemCaseId caseID);
u32 GetMonVolatile(u32 battler, enum Volatile volatile);
void SetMonVolatile(u32 battler, enum Volatile volatile, u32 newValue);
u32 TryBoosterEnergy(u32 battler, u32 ability, enum ItemCaseId caseID);
u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile);
void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue);
u32 TryBoosterEnergy(u32 battler, enum Ability ability, enum ItemCaseId caseID);
bool32 ItemHealMonVolatile(u32 battler, u16 itemId);
void PushHazardTypeToQueue(u32 side, enum Hazards hazardType);
bool32 IsHazardOnSide(u32 side, enum Hazards hazardType);
bool32 AreAnyHazardsOnSide(u32 side);
void RemoveAllHazardsFromField(u32 side);
bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType);
void RemoveHazardFromField(u32 side, enum Hazards hazardType);
bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, u32 atkHoldEffect, u32 defHoldEffect);
bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander);
bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move);
u32 GetNaturePowerMove(u32 battler);
u32 GetNaturePowerMove(u32 battler);
void RemoveAbilityFlags(u32 battler);
bool32 IsDazzlingAbility(enum Ability ability);
bool32 IsAllowedToUseBag(void);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -13,8 +13,9 @@
// AI smart switching chances; if you want more complex behaviour, modify GetSwitchChance
#define SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE 100
#define SHOULD_SWITCH_ABSORBS_HIDDEN_POWER_PERCENTAGE 50
#define SHOULD_SWITCH_TRAPPER_PERCENTAGE 100
#define SHOULD_SWITCH_FREE_TURN_PERCENTAGE 100
#define SHOULD_SWITCH_FREE_TURN_PERCENTAGE 50
#define STAY_IN_ABSORBING_PERCENTAGE 66 // Chance to stay in if outgoing mon has super effective move against player, will prevent switching out for an absorber with this likelihood
#define SHOULD_SWITCH_HASBADODDS_PERCENTAGE 50
#define SHOULD_SWITCH_ENCORE_STATUS_PERCENTAGE 100
@ -51,11 +52,16 @@
#define AI_GOOD_SCORE_THRESHOLD 100 // Move scores above this threshold are considered "good" when deciding switching
// AI held item-based move scoring
#define LOW_ACCURACY_THRESHOLD 75 // Moves with accuracy equal OR below this value are considered low accuracy
#define LOW_ACCURACY_THRESHOLD 75 // Moves with accuracy equal OR below this value are considered low accuracy
// AI move scoring
#define STATUS_MOVE_FOCUS_PUNCH_CHANCE 50 // Chance the AI will use a status move if the player's best move is Focus Punch
#define BOOST_INTO_HAZE_CHANCE 0 // Chance the AI will use a stat boosting move if the player has used Haze
#define SHOULD_RECOVER_CHANCE 50 // Chance the AI will give recovery moves score increase if less than ENABLE_RECOVERY_THRESHOLD and in no immediate danger
#define ENABLE_RECOVERY_THRESHOLD 60 // HP percentage beneath which SHOULD_RECOVER_CHANCE is active
#define SUCKER_PUNCH_CHANCE 50 // Chance for the AI to not use Sucker Punch if the player has a status move
#define SUCKER_PUNCH_PREDICTION_CHANCE 50 // Additional chance for the AI to not use Sucker Punch if actively predicting a status move if SUCKER_PUNCH_CHANCE fails
#define PRIORITIZE_LAST_CHANCE_CHANCE 50 // Chance the AI will prioritize Last Chance (priority move in the face of being outsped and KO'd) over Slow KO
// AI damage calc considerations
#define RISKY_AI_CRIT_STAGE_THRESHOLD 2 // Stat stages at which Risky will assume it gets a crit
@ -67,16 +73,46 @@
// AI Terastalization chances
#define AI_CONSERVE_TERA_CHANCE_PER_MON 10 // Chance for AI with smart tera flag to decide not to tera before considering defensive benefit is this*(X-1), where X is the number of alive pokemon that could tera
#define AI_TERA_PREDICT_CHANCE 40 // Chance for AI with smart tera flag to tera in the situation where tera would save it from a KO, but could be punished by a KO from a different move.
#define AI_TERA_PREDICT_CHANCE 40 // Chance for AI with smart tera flag to tera in the situation where tera would save it from a KO, but could be punished by a KO from a different move.
// AI PP Stall detection chance per roll
#define PP_STALL_DISREGARD_MOVE_PERCENTAGE 50
// Score reduction if any roll for PP stall detection passes
#define PP_STALL_SCORE_REDUCTION 20
// AI_FLAG_PP_STALL_PREVENTION settings
#define PP_STALL_DISREGARD_MOVE_PERCENTAGE 50 // Detection chance per roll
#define PP_STALL_SCORE_REDUCTION 20 // Score reduction if any roll for PP stall detection passes
// AI's acceptable number of hits to KO the partner via friendly fire in a double battle.
#define FRIENDLY_FIRE_RISKY_THRESHOLD 2
#define FRIENDLY_FIRE_NORMAL_THRESHOLD 3
#define FRIENDLY_FIRE_CONSERVATIVE_THRESHOLD 4
// AI_FLAG_ASSUME_STAB settings
#define ASSUME_STAB_SEES_ABILITY FALSE // Flag also gives omniscience for player's ability. Can use AI_FLAG_WEIGH_ABILITY_PREDICTION instead for smarter prediction without omniscience.
// AI_FLAG_ASSUME_STATUS_MOVES settings
#define ASSUME_STATUS_MOVES_HAS_TUNING TRUE // Flag has varying rates for different kinds of status move.
// Setting to false also means it will not alert on Fake Out or Super Fang.
#define ASSUME_STATUS_HIGH_ODDS 90 // Chance for AI to see extremely likely moves for a pokemon to have, like Spore
#define ASSUME_STATUS_MEDIUM_ODDS 70 // Chance for AI to see moderately likely moves for a pokemon to have, like Protect
#define ASSUME_STATUS_LOW_ODDS 40 // Chance for AI to see niche moves a pokemon may have but probably won't, like Entrainment
#define ASSUME_ALL_STATUS_ODDS 25 // Chance for the AI to see any kind of status move.
// AI_FLAG_SMART_SWITCHING settings
#define SMART_SWITCHING_OMNISCIENT FALSE // AI will use omniscience for switching calcs, regardless of omniscience setting otherwise
// Configurations specifically for AI_FLAG_DOUBLE_BATTLE.
#define FRIENDLY_FIRE_RISKY_THRESHOLD 2 // AI_FLAG_RISKY acceptable number of hits to KO the partner via friendly fire
#define FRIENDLY_FIRE_NORMAL_THRESHOLD 3 // typical acceptable number of hits to KO the partner via friendly fire
#define FRIENDLY_FIRE_CONSERVATIVE_THRESHOLD 4 // AI_FLAG_CONSERVATIVE acceptable number of hits to KO the partner via friendly fire
// Counterplay on the assumption of opponents Protecting.
#define DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE 35 // both pokemon use Trick Room on turn Trick Room expires in the hopes both opponents used Protect to stall, getting a free refresh on the timer
#define TAILWIND_IN_TRICK_ROOM_CHANCE 35 // use Tailwind on turn Trick Room expires in the hopes both opponents used Protect to stall
#define AI_FLAG_ATTACKS_PARTNER_FOCUSES_PARTNER FALSE // if TRUE, AI_FLAG_ATTACKS_PARTNER prefers attacking the partner over the ally.
// This is treated as true regardless during wild battles with AI.
// AI's desired stat changes for Guard Split and Power Split, treated as %
#define GUARD_SPLIT_ALLY_PERCENTAGE 200
#define GUARD_SPLIT_ENEMY_PERCENTAGE 50
#define POWER_SPLIT_ALLY_PERCENTAGE 150
#define POWER_SPLIT_ENEMY_PERCENTAGE 50
// HP thresholds to use a status z-move.
#define Z_EFFECT_FOLLOW_ME_THRESHOLD 30
#define Z_EFFECT_RESTORE_HP_LOWER_THRESHOLD ENABLE_RECOVERY_THRESHOLD // threshold used for moves you could conceivably use more than once
#define Z_EFFECT_RESTORE_HP_HIGHER_THRESHOLD 90 // these moves are one-time use or drop your HP
#endif // GUARD_CONFIG_AI_H

View File

@ -28,7 +28,7 @@
#define B_BURN_DAMAGE GEN_LATEST // In Gen7+, burn damage is 1/16th of max HP instead of 1/8th. Also applies to Frostbite.
#define B_BURN_FACADE_DMG GEN_LATEST // In Gen6+, burn's effect of lowering the Attack stat no longer applies to Facade.
#define B_BINDING_DAMAGE GEN_LATEST // In Gen6+, binding damage is 1/8 of max HP instead of 1/16. (With Binding Band, 1/6 and 1/8 respectively.)
#define B_PSYWAVE_DMG GEN_LATEST // Psywave's damage formula. See Cmd_psywavedamageeffect.
#define B_PSYWAVE_DMG GEN_LATEST // Psywave's damage formula. See DoFixedDamageMoveCalc for details.
#define B_PAYBACK_SWITCH_BOOST GEN_LATEST // In Gen5+, if the opponent switches out, Payback's damage will no longer be doubled.
#define B_HIDDEN_POWER_DMG GEN_LATEST // In Gen6+, Hidden Power's base power was set to always be 60. Before, it was determined by the mon's IVs.
#define B_ROUGH_SKIN_DMG GEN_LATEST // In Gen4+, Rough Skin contact damage is 1/8th of max HP instead of 1/16th. This will also affect Iron Barbs.
@ -131,7 +131,8 @@
#define B_SKIP_RECHARGE GEN_LATEST // In Gen1, recharging moves such as Hyper Beam skip the recharge if the target gets KO'd
#define B_ENCORE_TARGET GEN_LATEST // In Gen5+, encored moves are allowed to choose a target
#define B_TIME_OF_DAY_HEALING_MOVES GEN_LATEST // In Gen2, Morning Sun, Moonlight, and Synthesis heal twice as much HP based off the time of day. Also changes how much they heal. Evening affects Moonlight.
// If OW_TIMES_OF_DAY is set to Gen 3, then Morning Sun is boosted during the day.
// If OW_TIMES_OF_DAY is set to Gen 3, then Morning Sun is boosted during the day.
#define B_DREAM_EATER_LIQUID_OOZE GEN_LATEST // In Gen5+, Dream Eater is affected by Liquid Ooze.
// Ability settings
#define B_GALE_WINGS GEN_LATEST // In Gen7+ requires full HP to trigger.
@ -207,7 +208,6 @@
#define B_FLAG_INVERSE_BATTLE 0 // If this flag is set, the battle's type effectiveness are inversed. For example, fire is super effective against water.
#define B_FLAG_FORCE_DOUBLE_WILD 0 // If this flag is set, all land and surfing wild battles will be double battles.
#define B_SMART_WILD_AI_FLAG 0 // If this flag is set, wild Pokémon will become smart, with all AI flags enabled.
#define B_FLAG_NO_BAG_USE 0 // If this flag is set, the ability to use the bag in battle is disabled.
#define B_FLAG_NO_CATCHING 0 // If this flag is set, the ability to catch wild Pokémon is disabled.
#define B_FLAG_NO_RUNNING 0 // If this flag is set, the ability to escape from wild battles is disabled. Also makes Roar/Whirlwind and Teleport (under Gen8) fail.
#define B_FLAG_AI_VS_AI_BATTLE 0 // If this flag is set, the player's mons will be controlled by the ai next battles.
@ -229,6 +229,13 @@
#define B_VAR_DIFFICULTY 0 // If not 0, you can use this var to control which difficulty version of a Trainer is loaded. This should be manually set by the developer using Script_SetDifficulty AFTER NewGameInitData has run.
// No bag settings
#define NO_BAG_RESTRICTION 0
#define NO_BAG_AGAINST_TRAINER 1
#define NO_BAG_IN_BATTLE 2
#define B_VAR_NO_BAG_USE 0 // If 1, the ability to use the bag in battle is disabled in trainer battles. If 2, it is also disabled in wild battles.
// Sky Battles
#define B_FLAG_SKY_BATTLE 0 // If this flag has a value, the player will be able to engage in scripted Sky Battles.
#define B_VAR_SKY_BATTLE 0 // If this var has a value, the game will remember the positions of Pokémon used in Sky Battles.
@ -262,32 +269,33 @@
#define B_TERRAIN_TYPE_BOOST GEN_LATEST // In Gen8, damage is boosted by 30% instead of 50%.
#define B_SECRET_POWER_EFFECT GEN_LATEST // Secret Power's effects change depending on terrain and generation. See MOVE_EFFECT_SECRET_POWER's case in `SetMoveEffect`.
#define B_SECRET_POWER_ANIMATION GEN_LATEST // Secret Power's animations change depending on terrain and generation.
#define B_NATURE_POWER_MOVES GEN_LATEST // Nature Power calls different moves depending on terrain and generation. See sNaturePowerMoves.
#define B_NATURE_POWER_MOVES GEN_LATEST // Nature Power calls different moves depending on terrain and generation. See gBattleEnvironmentInfo.
#define B_CAMOUFLAGE_TYPES GEN_LATEST // Camouflage changes the user to different types depending on terrain and generation. See sTerrainToType.
#define B_NEW_TERRAIN_BACKGROUNDS FALSE // If set to TRUE, uses new terrain backgrounds for Electric, Misty, Grassy and Psychic Terrain.
// Interface settings
#define B_ABILITY_POP_UP TRUE // In Gen5+, the Pokémon abilities are displayed in a pop-up, when they activate in battle.
#define B_FAST_INTRO_PKMN_TEXT TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end.
#define B_FAST_INTRO_NO_SLIDE FALSE // If set to TRUE, the slide animation that happens at the beginning of the battle is skipped.
#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 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_WAIT_TIME_MULTIPLIER 16 // This determines how long text pauses in battle last. Vanilla is 16. Lower values result in faster battles.
#define B_QUICK_MOVE_CURSOR_TO_RUN FALSE // If set to TRUE, pushing B in the battle options against a wild encounter will move the cursor to the run option
#define B_RUN_TRAINER_BATTLE TRUE // If set to TRUE, players can run from Trainer battles. This is treated as a whiteout.
#define B_MOVE_DESCRIPTION_BUTTON L_BUTTON // If set to a button other than B_LAST_USED_BALL_BUTTON, pressing this button will open the move description menu
#define B_SHOW_USELESS_Z_MOVE_INFO FALSE // If set to TRUE, Z-moves without additional effects like newer gen status moves will say "no additional effect"
#define B_ANIMATE_MON_AFTER_KO TRUE // If set to TRUE, if a Pokémon on the opposite site faints, the non-fainted Pokemon will display a victory animation.
#define B_SHOW_DYNAMAX_MESSAGE FALSE // If set to TRUE, an additional battle message is shown after completing Dynamaxing/Gigantamaxing.
#define B_FAST_INTRO_PKMN_TEXT TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end.
#define B_FAST_INTRO_NO_SLIDE FALSE // If set to TRUE, the slide animation that happens at the beginning of the battle is skipped.
#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 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_WAIT_TIME_MULTIPLIER 16 // This determines how long text pauses in battle last. Vanilla is 16. Lower values result in faster battles.
#define B_QUICK_MOVE_CURSOR_TO_RUN FALSE // If set to TRUE, pushing B in the battle options against a wild encounter will move the cursor to the run option
#define B_RUN_TRAINER_BATTLE TRUE // If set to TRUE, players can run from Trainer battles. This is treated as a whiteout.
#define B_MOVE_DESCRIPTION_BUTTON L_BUTTON // If set to a button other than B_LAST_USED_BALL_BUTTON, pressing this button will open the move description menu
#define B_SHOW_USELESS_Z_MOVE_INFO FALSE // If set to TRUE, Z-moves without additional effects like newer gen status moves will say "no additional effect"
#define B_ANIMATE_MON_AFTER_KO TRUE // If set to TRUE, if a Pokémon on the opposite site faints, the non-fainted Pokemon will display a victory animation.
#define B_ANIMATE_MON_AFTER_FAILED_POKEBALL TRUE // If set to TRUE, if a Pokémon on the opposite side breaks out of a thrown Poké Ball, the wild Pokémon will display its animation.
#define B_SHOW_DYNAMAX_MESSAGE FALSE // If set to TRUE, an additional battle message is shown after completing Dynamaxing/Gigantamaxing.
// Catching settings
#define B_SEMI_INVULNERABLE_CATCH GEN_LATEST // In Gen4+, you cannot throw a ball against a Pokemon that is in a semi-invulnerable state (dig/fly/etc)
#define B_CATCHING_CHARM_BOOST 20 // % boost in Critical Capture odds if player has the Catching Charm.
#define B_CATCHING_CHARM_BOOST 100 // % boost in Critical Capture odds if player has the Catching Charm.
#define B_CRITICAL_CAPTURE TRUE // If set to TRUE, Critical Capture will be enabled.
#define B_CRITICAL_CAPTURE_LOCAL_DEX TRUE // If set to FALSE, Critical Capture % is based off of the National Pokedex estimated by enabled generations.
#define B_CRITICAL_CAPTURE_IF_OWNED GEN_LATEST // In Gen9, a capture appear critical if the pokemon you are trying to catch already has a dex entry (has already been caught)
#define B_LAST_USED_BALL TRUE // If TRUE, the "last used ball" feature from Gen 7 will be implemented
#define B_LAST_USED_BALL_BUTTON R_BUTTON // If last used ball is implemented, this button (or button combo) will trigger throwing the last used ball.
@ -363,5 +371,7 @@
#define B_POOL_RULE_EXCLUDE_FORMS FALSE // Exclude different forms from the Species Clause
#define B_POOL_RULE_ITEM_CLAUSE FALSE // Only allow each item to be picked once
#define B_POOL_RULES_USE_ITEM_EXCLUSIONS FALSE // Exclude items listed in poolItemClauseExclusions
#define B_POOL_RULE_MEGA_STONE_CLAUSE FALSE // Pick only 1 mon with mega stone
#define B_POOL_RULE_Z_CRYSTAL_CLAUSE FALSE // Pick only 1 mon with Z-crystal
#endif // GUARD_CONFIG_BATTLE_H

View File

@ -75,7 +75,6 @@
#define EXPANSION_INTRO TRUE // If TRUE, a custom RHH intro will play after the vanilla copyright screen.
#define SUMMARY_SCREEN_NATURE_COLORS TRUE // If TRUE, nature-based stat boosts and reductions will be red and blue in the summary screen.
#define HQ_RANDOM TRUE // If TRUE, replaces the default RNG with an implementation of SFC32 RNG. May break code that relies on RNG.
#define COMPETITIVE_PARTY_SYNTAX TRUE // If TRUE, parties are defined in "competitive syntax".
#define AUTO_SCROLL_TEXT FALSE // If TRUE, text will automatically scroll to the next line after NUM_FRAMES_AUTO_SCROLL_DELAY. Players can still press A_BUTTON or B_BUTTON to scroll on their own.
#define NUM_FRAMES_AUTO_SCROLL_DELAY 49

View File

@ -1,344 +1,339 @@
#ifndef GUARD_CONSTANTS_ABILITIES_H
#define GUARD_CONSTANTS_ABILITIES_H
#define ABILITY_NONE 0
#define ABILITY_STENCH 1
#define ABILITY_DRIZZLE 2
#define ABILITY_SPEED_BOOST 3
#define ABILITY_BATTLE_ARMOR 4
#define ABILITY_STURDY 5
#define ABILITY_DAMP 6
#define ABILITY_LIMBER 7
#define ABILITY_SAND_VEIL 8
#define ABILITY_STATIC 9
#define ABILITY_VOLT_ABSORB 10
#define ABILITY_WATER_ABSORB 11
#define ABILITY_OBLIVIOUS 12
#define ABILITY_CLOUD_NINE 13
#define ABILITY_COMPOUND_EYES 14
#define ABILITY_INSOMNIA 15
#define ABILITY_COLOR_CHANGE 16
#define ABILITY_IMMUNITY 17
#define ABILITY_FLASH_FIRE 18
#define ABILITY_SHIELD_DUST 19
#define ABILITY_OWN_TEMPO 20
#define ABILITY_SUCTION_CUPS 21
#define ABILITY_INTIMIDATE 22
#define ABILITY_SHADOW_TAG 23
#define ABILITY_ROUGH_SKIN 24
#define ABILITY_WONDER_GUARD 25
#define ABILITY_LEVITATE 26
#define ABILITY_EFFECT_SPORE 27
#define ABILITY_SYNCHRONIZE 28
#define ABILITY_CLEAR_BODY 29
#define ABILITY_NATURAL_CURE 30
#define ABILITY_LIGHTNING_ROD 31
#define ABILITY_SERENE_GRACE 32
#define ABILITY_SWIFT_SWIM 33
#define ABILITY_CHLOROPHYLL 34
#define ABILITY_ILLUMINATE 35
#define ABILITY_TRACE 36
#define ABILITY_HUGE_POWER 37
#define ABILITY_POISON_POINT 38
#define ABILITY_INNER_FOCUS 39
#define ABILITY_MAGMA_ARMOR 40
#define ABILITY_WATER_VEIL 41
#define ABILITY_MAGNET_PULL 42
#define ABILITY_SOUNDPROOF 43
#define ABILITY_RAIN_DISH 44
#define ABILITY_SAND_STREAM 45
#define ABILITY_PRESSURE 46
#define ABILITY_THICK_FAT 47
#define ABILITY_EARLY_BIRD 48
#define ABILITY_FLAME_BODY 49
#define ABILITY_RUN_AWAY 50
#define ABILITY_KEEN_EYE 51
#define ABILITY_HYPER_CUTTER 52
#define ABILITY_PICKUP 53
#define ABILITY_TRUANT 54
#define ABILITY_HUSTLE 55
#define ABILITY_CUTE_CHARM 56
#define ABILITY_PLUS 57
#define ABILITY_MINUS 58
#define ABILITY_FORECAST 59
#define ABILITY_STICKY_HOLD 60
#define ABILITY_SHED_SKIN 61
#define ABILITY_GUTS 62
#define ABILITY_MARVEL_SCALE 63
#define ABILITY_LIQUID_OOZE 64
#define ABILITY_OVERGROW 65
#define ABILITY_BLAZE 66
#define ABILITY_TORRENT 67
#define ABILITY_SWARM 68
#define ABILITY_ROCK_HEAD 69
#define ABILITY_DROUGHT 70
#define ABILITY_ARENA_TRAP 71
#define ABILITY_VITAL_SPIRIT 72
#define ABILITY_WHITE_SMOKE 73
#define ABILITY_PURE_POWER 74
#define ABILITY_SHELL_ARMOR 75
#define ABILITY_AIR_LOCK 76
enum __attribute__((packed)) Ability
{
ABILITY_NONE = 0,
ABILITY_STENCH = 1,
ABILITY_DRIZZLE = 2,
ABILITY_SPEED_BOOST = 3,
ABILITY_BATTLE_ARMOR = 4,
ABILITY_STURDY = 5,
ABILITY_DAMP = 6,
ABILITY_LIMBER = 7,
ABILITY_SAND_VEIL = 8,
ABILITY_STATIC = 9,
ABILITY_VOLT_ABSORB = 10,
ABILITY_WATER_ABSORB = 11,
ABILITY_OBLIVIOUS = 12,
ABILITY_CLOUD_NINE = 13,
ABILITY_COMPOUND_EYES = 14,
ABILITY_INSOMNIA = 15,
ABILITY_COLOR_CHANGE = 16,
ABILITY_IMMUNITY = 17,
ABILITY_FLASH_FIRE = 18,
ABILITY_SHIELD_DUST = 19,
ABILITY_OWN_TEMPO = 20,
ABILITY_SUCTION_CUPS = 21,
ABILITY_INTIMIDATE = 22,
ABILITY_SHADOW_TAG = 23,
ABILITY_ROUGH_SKIN = 24,
ABILITY_WONDER_GUARD = 25,
ABILITY_LEVITATE = 26,
ABILITY_EFFECT_SPORE = 27,
ABILITY_SYNCHRONIZE = 28,
ABILITY_CLEAR_BODY = 29,
ABILITY_NATURAL_CURE = 30,
ABILITY_LIGHTNING_ROD = 31,
ABILITY_SERENE_GRACE = 32,
ABILITY_SWIFT_SWIM = 33,
ABILITY_CHLOROPHYLL = 34,
ABILITY_ILLUMINATE = 35,
ABILITY_TRACE = 36,
ABILITY_HUGE_POWER = 37,
ABILITY_POISON_POINT = 38,
ABILITY_INNER_FOCUS = 39,
ABILITY_MAGMA_ARMOR = 40,
ABILITY_WATER_VEIL = 41,
ABILITY_MAGNET_PULL = 42,
ABILITY_SOUNDPROOF = 43,
ABILITY_RAIN_DISH = 44,
ABILITY_SAND_STREAM = 45,
ABILITY_PRESSURE = 46,
ABILITY_THICK_FAT = 47,
ABILITY_EARLY_BIRD = 48,
ABILITY_FLAME_BODY = 49,
ABILITY_RUN_AWAY = 50,
ABILITY_KEEN_EYE = 51,
ABILITY_HYPER_CUTTER = 52,
ABILITY_PICKUP = 53,
ABILITY_TRUANT = 54,
ABILITY_HUSTLE = 55,
ABILITY_CUTE_CHARM = 56,
ABILITY_PLUS = 57,
ABILITY_MINUS = 58,
ABILITY_FORECAST = 59,
ABILITY_STICKY_HOLD = 60,
ABILITY_SHED_SKIN = 61,
ABILITY_GUTS = 62,
ABILITY_MARVEL_SCALE = 63,
ABILITY_LIQUID_OOZE = 64,
ABILITY_OVERGROW = 65,
ABILITY_BLAZE = 66,
ABILITY_TORRENT = 67,
ABILITY_SWARM = 68,
ABILITY_ROCK_HEAD = 69,
ABILITY_DROUGHT = 70,
ABILITY_ARENA_TRAP = 71,
ABILITY_VITAL_SPIRIT = 72,
ABILITY_WHITE_SMOKE = 73,
ABILITY_PURE_POWER = 74,
ABILITY_SHELL_ARMOR = 75,
ABILITY_AIR_LOCK = 76,
ABILITIES_COUNT_GEN3,
#define ABILITIES_COUNT_GEN3 77
// Gen 4
ABILITY_TANGLED_FEET = ABILITIES_COUNT_GEN3,
ABILITY_MOTOR_DRIVE = 78,
ABILITY_RIVALRY = 79,
ABILITY_STEADFAST = 80,
ABILITY_SNOW_CLOAK = 81,
ABILITY_GLUTTONY = 82,
ABILITY_ANGER_POINT = 83,
ABILITY_UNBURDEN = 84,
ABILITY_HEATPROOF = 85,
ABILITY_SIMPLE = 86,
ABILITY_DRY_SKIN = 87,
ABILITY_DOWNLOAD = 88,
ABILITY_IRON_FIST = 89,
ABILITY_POISON_HEAL = 90,
ABILITY_ADAPTABILITY = 91,
ABILITY_SKILL_LINK = 92,
ABILITY_HYDRATION = 93,
ABILITY_SOLAR_POWER = 94,
ABILITY_QUICK_FEET = 95,
ABILITY_NORMALIZE = 96,
ABILITY_SNIPER = 97,
ABILITY_MAGIC_GUARD = 98,
ABILITY_NO_GUARD = 99,
ABILITY_STALL = 100,
ABILITY_TECHNICIAN = 101,
ABILITY_LEAF_GUARD = 102,
ABILITY_KLUTZ = 103,
ABILITY_MOLD_BREAKER = 104,
ABILITY_SUPER_LUCK = 105,
ABILITY_AFTERMATH = 106,
ABILITY_ANTICIPATION = 107,
ABILITY_FOREWARN = 108,
ABILITY_UNAWARE = 109,
ABILITY_TINTED_LENS = 110,
ABILITY_FILTER = 111,
ABILITY_SLOW_START = 112,
ABILITY_SCRAPPY = 113,
ABILITY_STORM_DRAIN = 114,
ABILITY_ICE_BODY = 115,
ABILITY_SOLID_ROCK = 116,
ABILITY_SNOW_WARNING = 117,
ABILITY_HONEY_GATHER = 118,
ABILITY_FRISK = 119,
ABILITY_RECKLESS = 120,
ABILITY_MULTITYPE = 121,
ABILITY_FLOWER_GIFT = 122,
ABILITY_BAD_DREAMS = 123,
ABILITIES_COUNT_GEN4,
// Gen 4
#define ABILITY_TANGLED_FEET 77
#define ABILITY_MOTOR_DRIVE 78
#define ABILITY_RIVALRY 79
#define ABILITY_STEADFAST 80
#define ABILITY_SNOW_CLOAK 81
#define ABILITY_GLUTTONY 82
#define ABILITY_ANGER_POINT 83
#define ABILITY_UNBURDEN 84
#define ABILITY_HEATPROOF 85
#define ABILITY_SIMPLE 86
#define ABILITY_DRY_SKIN 87
#define ABILITY_DOWNLOAD 88
#define ABILITY_IRON_FIST 89
#define ABILITY_POISON_HEAL 90
#define ABILITY_ADAPTABILITY 91
#define ABILITY_SKILL_LINK 92
#define ABILITY_HYDRATION 93
#define ABILITY_SOLAR_POWER 94
#define ABILITY_QUICK_FEET 95
#define ABILITY_NORMALIZE 96
#define ABILITY_SNIPER 97
#define ABILITY_MAGIC_GUARD 98
#define ABILITY_NO_GUARD 99
#define ABILITY_STALL 100
#define ABILITY_TECHNICIAN 101
#define ABILITY_LEAF_GUARD 102
#define ABILITY_KLUTZ 103
#define ABILITY_MOLD_BREAKER 104
#define ABILITY_SUPER_LUCK 105
#define ABILITY_AFTERMATH 106
#define ABILITY_ANTICIPATION 107
#define ABILITY_FOREWARN 108
#define ABILITY_UNAWARE 109
#define ABILITY_TINTED_LENS 110
#define ABILITY_FILTER 111
#define ABILITY_SLOW_START 112
#define ABILITY_SCRAPPY 113
#define ABILITY_STORM_DRAIN 114
#define ABILITY_ICE_BODY 115
#define ABILITY_SOLID_ROCK 116
#define ABILITY_SNOW_WARNING 117
#define ABILITY_HONEY_GATHER 118
#define ABILITY_FRISK 119
#define ABILITY_RECKLESS 120
#define ABILITY_MULTITYPE 121
#define ABILITY_FLOWER_GIFT 122
#define ABILITY_BAD_DREAMS 123
// Gen 5
ABILITY_PICKPOCKET = ABILITIES_COUNT_GEN4,
ABILITY_SHEER_FORCE = 125,
ABILITY_CONTRARY = 126,
ABILITY_UNNERVE = 127,
ABILITY_DEFIANT = 128,
ABILITY_DEFEATIST = 129,
ABILITY_CURSED_BODY = 130,
ABILITY_HEALER = 131,
ABILITY_FRIEND_GUARD = 132,
ABILITY_WEAK_ARMOR = 133,
ABILITY_HEAVY_METAL = 134,
ABILITY_LIGHT_METAL = 135,
ABILITY_MULTISCALE = 136,
ABILITY_TOXIC_BOOST = 137,
ABILITY_FLARE_BOOST = 138,
ABILITY_HARVEST = 139,
ABILITY_TELEPATHY = 140,
ABILITY_MOODY = 141,
ABILITY_OVERCOAT = 142,
ABILITY_POISON_TOUCH = 143,
ABILITY_REGENERATOR = 144,
ABILITY_BIG_PECKS = 145,
ABILITY_SAND_RUSH = 146,
ABILITY_WONDER_SKIN = 147,
ABILITY_ANALYTIC = 148,
ABILITY_ILLUSION = 149,
ABILITY_IMPOSTER = 150,
ABILITY_INFILTRATOR = 151,
ABILITY_MUMMY = 152,
ABILITY_MOXIE = 153,
ABILITY_JUSTIFIED = 154,
ABILITY_RATTLED = 155,
ABILITY_MAGIC_BOUNCE = 156,
ABILITY_SAP_SIPPER = 157,
ABILITY_PRANKSTER = 158,
ABILITY_SAND_FORCE = 159,
ABILITY_IRON_BARBS = 160,
ABILITY_ZEN_MODE = 161,
ABILITY_VICTORY_STAR = 162,
ABILITY_TURBOBLAZE = 163,
ABILITY_TERAVOLT = 164,
ABILITIES_COUNT_GEN5,
#define ABILITIES_COUNT_GEN4 124
// Gen 6
ABILITY_AROMA_VEIL = ABILITIES_COUNT_GEN5,
ABILITY_FLOWER_VEIL = 166,
ABILITY_CHEEK_POUCH = 167,
ABILITY_PROTEAN = 168,
ABILITY_FUR_COAT = 169,
ABILITY_MAGICIAN = 170,
ABILITY_BULLETPROOF = 171,
ABILITY_COMPETITIVE = 172,
ABILITY_STRONG_JAW = 173,
ABILITY_REFRIGERATE = 174,
ABILITY_SWEET_VEIL = 175,
ABILITY_STANCE_CHANGE = 176,
ABILITY_GALE_WINGS = 177,
ABILITY_MEGA_LAUNCHER = 178,
ABILITY_GRASS_PELT = 179,
ABILITY_SYMBIOSIS = 180,
ABILITY_TOUGH_CLAWS = 181,
ABILITY_PIXILATE = 182,
ABILITY_GOOEY = 183,
ABILITY_AERILATE = 184,
ABILITY_PARENTAL_BOND = 185,
ABILITY_DARK_AURA = 186,
ABILITY_FAIRY_AURA = 187,
ABILITY_AURA_BREAK = 188,
ABILITY_PRIMORDIAL_SEA = 189,
ABILITY_DESOLATE_LAND = 190,
ABILITY_DELTA_STREAM = 191,
ABILITIES_COUNT_GEN6,
// Gen 5
#define ABILITY_PICKPOCKET 124
#define ABILITY_SHEER_FORCE 125
#define ABILITY_CONTRARY 126
#define ABILITY_UNNERVE 127
#define ABILITY_DEFIANT 128
#define ABILITY_DEFEATIST 129
#define ABILITY_CURSED_BODY 130
#define ABILITY_HEALER 131
#define ABILITY_FRIEND_GUARD 132
#define ABILITY_WEAK_ARMOR 133
#define ABILITY_HEAVY_METAL 134
#define ABILITY_LIGHT_METAL 135
#define ABILITY_MULTISCALE 136
#define ABILITY_TOXIC_BOOST 137
#define ABILITY_FLARE_BOOST 138
#define ABILITY_HARVEST 139
#define ABILITY_TELEPATHY 140
#define ABILITY_MOODY 141
#define ABILITY_OVERCOAT 142
#define ABILITY_POISON_TOUCH 143
#define ABILITY_REGENERATOR 144
#define ABILITY_BIG_PECKS 145
#define ABILITY_SAND_RUSH 146
#define ABILITY_WONDER_SKIN 147
#define ABILITY_ANALYTIC 148
#define ABILITY_ILLUSION 149
#define ABILITY_IMPOSTER 150
#define ABILITY_INFILTRATOR 151
#define ABILITY_MUMMY 152
#define ABILITY_MOXIE 153
#define ABILITY_JUSTIFIED 154
#define ABILITY_RATTLED 155
#define ABILITY_MAGIC_BOUNCE 156
#define ABILITY_SAP_SIPPER 157
#define ABILITY_PRANKSTER 158
#define ABILITY_SAND_FORCE 159
#define ABILITY_IRON_BARBS 160
#define ABILITY_ZEN_MODE 161
#define ABILITY_VICTORY_STAR 162
#define ABILITY_TURBOBLAZE 163
#define ABILITY_TERAVOLT 164
// Gen 7
ABILITY_STAMINA = ABILITIES_COUNT_GEN6,
ABILITY_WIMP_OUT = 193,
ABILITY_EMERGENCY_EXIT = 194,
ABILITY_WATER_COMPACTION = 195,
ABILITY_MERCILESS = 196,
ABILITY_SHIELDS_DOWN = 197,
ABILITY_STAKEOUT = 198,
ABILITY_WATER_BUBBLE = 199,
ABILITY_STEELWORKER = 200,
ABILITY_BERSERK = 201,
ABILITY_SLUSH_RUSH = 202,
ABILITY_LONG_REACH = 203,
ABILITY_LIQUID_VOICE = 204,
ABILITY_TRIAGE = 205,
ABILITY_GALVANIZE = 206,
ABILITY_SURGE_SURFER = 207,
ABILITY_SCHOOLING = 208,
ABILITY_DISGUISE = 209,
ABILITY_BATTLE_BOND = 210,
ABILITY_POWER_CONSTRUCT = 211,
ABILITY_CORROSION = 212,
ABILITY_COMATOSE = 213,
ABILITY_QUEENLY_MAJESTY = 214,
ABILITY_INNARDS_OUT = 215,
ABILITY_DANCER = 216,
ABILITY_BATTERY = 217,
ABILITY_FLUFFY = 218,
ABILITY_DAZZLING = 219,
ABILITY_SOUL_HEART = 220,
ABILITY_TANGLING_HAIR = 221,
ABILITY_RECEIVER = 222,
ABILITY_POWER_OF_ALCHEMY = 223,
ABILITY_BEAST_BOOST = 224,
ABILITY_RKS_SYSTEM = 225,
ABILITY_ELECTRIC_SURGE = 226,
ABILITY_PSYCHIC_SURGE = 227,
ABILITY_MISTY_SURGE = 228,
ABILITY_GRASSY_SURGE = 229,
ABILITY_FULL_METAL_BODY = 230,
ABILITY_SHADOW_SHIELD = 231,
ABILITY_PRISM_ARMOR = 232,
ABILITY_NEUROFORCE = 233,
ABILITIES_COUNT_GEN7,
#define ABILITIES_COUNT_GEN5 165
// Gen 8
ABILITY_INTREPID_SWORD = ABILITIES_COUNT_GEN7,
ABILITY_DAUNTLESS_SHIELD = 235,
ABILITY_LIBERO = 236,
ABILITY_BALL_FETCH = 237,
ABILITY_COTTON_DOWN = 238,
ABILITY_PROPELLER_TAIL = 239,
ABILITY_MIRROR_ARMOR = 240,
ABILITY_GULP_MISSILE = 241,
ABILITY_STALWART = 242,
ABILITY_STEAM_ENGINE = 243,
ABILITY_PUNK_ROCK = 244,
ABILITY_SAND_SPIT = 245,
ABILITY_ICE_SCALES = 246,
ABILITY_RIPEN = 247,
ABILITY_ICE_FACE = 248,
ABILITY_POWER_SPOT = 249,
ABILITY_MIMICRY = 250,
ABILITY_SCREEN_CLEANER = 251,
ABILITY_STEELY_SPIRIT = 252,
ABILITY_PERISH_BODY = 253,
ABILITY_WANDERING_SPIRIT = 254,
ABILITY_GORILLA_TACTICS = 255,
ABILITY_NEUTRALIZING_GAS = 256,
ABILITY_PASTEL_VEIL = 257,
ABILITY_HUNGER_SWITCH = 258,
ABILITY_QUICK_DRAW = 259,
ABILITY_UNSEEN_FIST = 260,
ABILITY_CURIOUS_MEDICINE = 261,
ABILITY_TRANSISTOR = 262,
ABILITY_DRAGONS_MAW = 263,
ABILITY_CHILLING_NEIGH = 264,
ABILITY_GRIM_NEIGH = 265,
ABILITY_AS_ONE_ICE_RIDER = 266,
ABILITY_AS_ONE_SHADOW_RIDER = 267,
ABILITIES_COUNT_GEN8,
// Gen 6
#define ABILITY_AROMA_VEIL 165
#define ABILITY_FLOWER_VEIL 166
#define ABILITY_CHEEK_POUCH 167
#define ABILITY_PROTEAN 168
#define ABILITY_FUR_COAT 169
#define ABILITY_MAGICIAN 170
#define ABILITY_BULLETPROOF 171
#define ABILITY_COMPETITIVE 172
#define ABILITY_STRONG_JAW 173
#define ABILITY_REFRIGERATE 174
#define ABILITY_SWEET_VEIL 175
#define ABILITY_STANCE_CHANGE 176
#define ABILITY_GALE_WINGS 177
#define ABILITY_MEGA_LAUNCHER 178
#define ABILITY_GRASS_PELT 179
#define ABILITY_SYMBIOSIS 180
#define ABILITY_TOUGH_CLAWS 181
#define ABILITY_PIXILATE 182
#define ABILITY_GOOEY 183
#define ABILITY_AERILATE 184
#define ABILITY_PARENTAL_BOND 185
#define ABILITY_DARK_AURA 186
#define ABILITY_FAIRY_AURA 187
#define ABILITY_AURA_BREAK 188
#define ABILITY_PRIMORDIAL_SEA 189
#define ABILITY_DESOLATE_LAND 190
#define ABILITY_DELTA_STREAM 191
#define ABILITIES_COUNT_GEN6 192
// Gen 7
#define ABILITY_STAMINA 192
#define ABILITY_WIMP_OUT 193
#define ABILITY_EMERGENCY_EXIT 194
#define ABILITY_WATER_COMPACTION 195
#define ABILITY_MERCILESS 196
#define ABILITY_SHIELDS_DOWN 197
#define ABILITY_STAKEOUT 198
#define ABILITY_WATER_BUBBLE 199
#define ABILITY_STEELWORKER 200
#define ABILITY_BERSERK 201
#define ABILITY_SLUSH_RUSH 202
#define ABILITY_LONG_REACH 203
#define ABILITY_LIQUID_VOICE 204
#define ABILITY_TRIAGE 205
#define ABILITY_GALVANIZE 206
#define ABILITY_SURGE_SURFER 207
#define ABILITY_SCHOOLING 208
#define ABILITY_DISGUISE 209
#define ABILITY_BATTLE_BOND 210
#define ABILITY_POWER_CONSTRUCT 211
#define ABILITY_CORROSION 212
#define ABILITY_COMATOSE 213
#define ABILITY_QUEENLY_MAJESTY 214
#define ABILITY_INNARDS_OUT 215
#define ABILITY_DANCER 216
#define ABILITY_BATTERY 217
#define ABILITY_FLUFFY 218
#define ABILITY_DAZZLING 219
#define ABILITY_SOUL_HEART 220
#define ABILITY_TANGLING_HAIR 221
#define ABILITY_RECEIVER 222
#define ABILITY_POWER_OF_ALCHEMY 223
#define ABILITY_BEAST_BOOST 224
#define ABILITY_RKS_SYSTEM 225
#define ABILITY_ELECTRIC_SURGE 226
#define ABILITY_PSYCHIC_SURGE 227
#define ABILITY_MISTY_SURGE 228
#define ABILITY_GRASSY_SURGE 229
#define ABILITY_FULL_METAL_BODY 230
#define ABILITY_SHADOW_SHIELD 231
#define ABILITY_PRISM_ARMOR 232
#define ABILITY_NEUROFORCE 233
#define ABILITIES_COUNT_GEN7 234
// Gen 8
#define ABILITY_INTREPID_SWORD 234
#define ABILITY_DAUNTLESS_SHIELD 235
#define ABILITY_LIBERO 236
#define ABILITY_BALL_FETCH 237
#define ABILITY_COTTON_DOWN 238
#define ABILITY_PROPELLER_TAIL 239
#define ABILITY_MIRROR_ARMOR 240
#define ABILITY_GULP_MISSILE 241
#define ABILITY_STALWART 242
#define ABILITY_STEAM_ENGINE 243
#define ABILITY_PUNK_ROCK 244
#define ABILITY_SAND_SPIT 245
#define ABILITY_ICE_SCALES 246
#define ABILITY_RIPEN 247
#define ABILITY_ICE_FACE 248
#define ABILITY_POWER_SPOT 249
#define ABILITY_MIMICRY 250
#define ABILITY_SCREEN_CLEANER 251
#define ABILITY_STEELY_SPIRIT 252
#define ABILITY_PERISH_BODY 253
#define ABILITY_WANDERING_SPIRIT 254
#define ABILITY_GORILLA_TACTICS 255
#define ABILITY_NEUTRALIZING_GAS 256
#define ABILITY_PASTEL_VEIL 257
#define ABILITY_HUNGER_SWITCH 258
#define ABILITY_QUICK_DRAW 259
#define ABILITY_UNSEEN_FIST 260
#define ABILITY_CURIOUS_MEDICINE 261
#define ABILITY_TRANSISTOR 262
#define ABILITY_DRAGONS_MAW 263
#define ABILITY_CHILLING_NEIGH 264
#define ABILITY_GRIM_NEIGH 265
#define ABILITY_AS_ONE_ICE_RIDER 266
#define ABILITY_AS_ONE_SHADOW_RIDER 267
#define ABILITIES_COUNT_GEN8 268
// Gen 9
#define ABILITY_LINGERING_AROMA 268
#define ABILITY_SEED_SOWER 269
#define ABILITY_THERMAL_EXCHANGE 270
#define ABILITY_ANGER_SHELL 271
#define ABILITY_PURIFYING_SALT 272
#define ABILITY_WELL_BAKED_BODY 273
#define ABILITY_WIND_RIDER 274
#define ABILITY_GUARD_DOG 275
#define ABILITY_ROCKY_PAYLOAD 276
#define ABILITY_WIND_POWER 277
#define ABILITY_ZERO_TO_HERO 278
#define ABILITY_COMMANDER 279
#define ABILITY_ELECTROMORPHOSIS 280
#define ABILITY_PROTOSYNTHESIS 281
#define ABILITY_QUARK_DRIVE 282
#define ABILITY_GOOD_AS_GOLD 283
#define ABILITY_VESSEL_OF_RUIN 284
#define ABILITY_SWORD_OF_RUIN 285
#define ABILITY_TABLETS_OF_RUIN 286
#define ABILITY_BEADS_OF_RUIN 287
#define ABILITY_ORICHALCUM_PULSE 288
#define ABILITY_HADRON_ENGINE 289
#define ABILITY_OPPORTUNIST 290
#define ABILITY_CUD_CHEW 291
#define ABILITY_SHARPNESS 292
#define ABILITY_SUPREME_OVERLORD 293
#define ABILITY_COSTAR 294
#define ABILITY_TOXIC_DEBRIS 295
#define ABILITY_ARMOR_TAIL 296
#define ABILITY_EARTH_EATER 297
#define ABILITY_MYCELIUM_MIGHT 298
#define ABILITY_HOSPITALITY 299
#define ABILITY_MINDS_EYE 300
#define ABILITY_EMBODY_ASPECT_TEAL_MASK 301
#define ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK 302
#define ABILITY_EMBODY_ASPECT_WELLSPRING_MASK 303
#define ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK 304
#define ABILITY_TOXIC_CHAIN 305
#define ABILITY_SUPERSWEET_SYRUP 306
#define ABILITY_TERA_SHIFT 307
#define ABILITY_TERA_SHELL 308
#define ABILITY_TERAFORM_ZERO 309
#define ABILITY_POISON_PUPPETEER 310
#define ABILITIES_COUNT_GEN9 311
#define ABILITIES_COUNT ABILITIES_COUNT_GEN9
// Gen 9
ABILITY_LINGERING_AROMA = ABILITIES_COUNT_GEN8,
ABILITY_SEED_SOWER = 269,
ABILITY_THERMAL_EXCHANGE = 270,
ABILITY_ANGER_SHELL = 271,
ABILITY_PURIFYING_SALT = 272,
ABILITY_WELL_BAKED_BODY = 273,
ABILITY_WIND_RIDER = 274,
ABILITY_GUARD_DOG = 275,
ABILITY_ROCKY_PAYLOAD = 276,
ABILITY_WIND_POWER = 277,
ABILITY_ZERO_TO_HERO = 278,
ABILITY_COMMANDER = 279,
ABILITY_ELECTROMORPHOSIS = 280,
ABILITY_PROTOSYNTHESIS = 281,
ABILITY_QUARK_DRIVE = 282,
ABILITY_GOOD_AS_GOLD = 283,
ABILITY_VESSEL_OF_RUIN = 284,
ABILITY_SWORD_OF_RUIN = 285,
ABILITY_TABLETS_OF_RUIN = 286,
ABILITY_BEADS_OF_RUIN = 287,
ABILITY_ORICHALCUM_PULSE = 288,
ABILITY_HADRON_ENGINE = 289,
ABILITY_OPPORTUNIST = 290,
ABILITY_CUD_CHEW = 291,
ABILITY_SHARPNESS = 292,
ABILITY_SUPREME_OVERLORD = 293,
ABILITY_COSTAR = 294,
ABILITY_TOXIC_DEBRIS = 295,
ABILITY_ARMOR_TAIL = 296,
ABILITY_EARTH_EATER = 297,
ABILITY_MYCELIUM_MIGHT = 298,
ABILITY_HOSPITALITY = 299,
ABILITY_MINDS_EYE = 300,
ABILITY_EMBODY_ASPECT_TEAL_MASK = 301,
ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK = 302,
ABILITY_EMBODY_ASPECT_WELLSPRING_MASK = 303,
ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK = 304,
ABILITY_TOXIC_CHAIN = 305,
ABILITY_SUPERSWEET_SYRUP = 306,
ABILITY_TERA_SHIFT = 307,
ABILITY_TERA_SHELL = 308,
ABILITY_TERAFORM_ZERO = 309,
ABILITY_POISON_PUPPETEER = 310,
ABILITIES_COUNT_GEN9,
ABILITIES_COUNT = ABILITIES_COUNT_GEN9,
};
#endif // GUARD_CONSTANTS_ABILITIES_H

View File

@ -93,12 +93,10 @@ enum BattlerId
#define BATTLE_TYPE_FRONTIER (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_DOME | BATTLE_TYPE_PALACE | BATTLE_TYPE_ARENA | BATTLE_TYPE_FACTORY | BATTLE_TYPE_PIKE | BATTLE_TYPE_PYRAMID)
#define BATTLE_TYPE_FRONTIER_NO_PYRAMID (BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_DOME | BATTLE_TYPE_PALACE | BATTLE_TYPE_ARENA | BATTLE_TYPE_FACTORY | BATTLE_TYPE_PIKE)
#define BATTLE_TYPE_RECORDED_INVALID ((BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_FIRST_BATTLE \
| BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \
| BATTLE_TYPE_CATCH_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \
| BATTLE_TYPE_LEGENDARY \
| BATTLE_TYPE_RECORDED | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE))
#define IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(flags) ((flags) & BATTLE_TYPE_GHOST && !((flags) & BATTLE_TYPE_GHOST_UNVEILED))
#define IS_BATTLE_TYPE_GHOST_WITH_SCOPE(flags) ((flags) & BATTLE_TYPE_GHOST && (flags) & BATTLE_TYPE_GHOST_UNVEILED)
#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))))
#define RECORDED_WILD_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_RECORDED) && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER)))
#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && TRAINER_BATTLE_PARAM.opponentB == 0xFFFF))
@ -139,136 +137,119 @@ enum BattlerId
#define STATUS1_PSN_ANY (STATUS1_POISON | STATUS1_TOXIC_POISON)
#define STATUS1_ANY (STATUS1_SLEEP | STATUS1_POISON | STATUS1_BURN | STATUS1_FREEZE | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)
#define STATUS1_REFRESH (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)
#define STATUS1_CAN_MOVE (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)
#define STATUS1_INCAPACITATED (STATUS1_SLEEP | STATUS1_FREEZE)
#define STATUS1_ICY_ANY (STATUS1_FREEZE | STATUS1_FROSTBITE)
#define STATUS1_DAMAGING (STATUS1_PSN_ANY | STATUS1_BURN | STATUS1_FROSTBITE)
enum VolatileFlags
{
V_BATON_PASSABLE = (1 << 0),
};
// Volatile status ailments
// These are removed after exiting the battle or switching
/* Definitions with names e.g. "Confusion" are accessible in the debug menu
* Enum, Type, (Field name, (optional)bitSize), Flags, (optional)(Debug menu header, (optional)max. value)
*/
/* Volatile status ailments
* These are removed after exiting the battle or switching
* Enum, Type Type, max value, flags */
#define VOLATILE_DEFINITIONS(F) \
F(VOLATILE_CONFUSION, confusionTurns, (u32, 3), V_BATON_PASSABLE) \
F(VOLATILE_FLINCHED, flinched, (u32, 1)) \
F(VOLATILE_UPROAR, uproarTurns, (u32, 3)) \
F(VOLATILE_TORMENT, torment, (u32, 1)) \
F(VOLATILE_BIDE, bideTurns, (u32, 2)) \
F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 2)) \
F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \
F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \
F(VOLATILE_POWDER, powder, (u32, 1)) \
F(VOLATILE_UNUSED, padding, (u32, 1)) \
F(VOLATILE_INFATUATION, infatuation, (u32, 4)) \
F(VOLATILE_DEFENSE_CURL, defenseCurl, (u32, 1)) \
F(VOLATILE_TRANSFORMED, transformed, (u32, 1)) \
F(VOLATILE_RECHARGE, recharge, (u32, 1)) \
F(VOLATILE_RAGE, rage, (u32, 1)) \
F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 1)) \
F(VOLATILE_ESCAPE_PREVENTION, escapePrevention, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \
F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \
F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE)
F(VOLATILE_CONFUSION, confusionTurns, (u32, 6), V_BATON_PASSABLE) \
F(VOLATILE_FLINCHED, flinched, (u32, 1)) \
F(VOLATILE_UPROAR, uproarTurns, (u32, 5)) \
F(VOLATILE_TORMENT, torment, (u32, 1)) \
F(VOLATILE_BIDE, bideTurns, (u32, 3)) \
F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 3)) \
F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \
F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \
F(VOLATILE_POWDER, powder, (u32, 1)) \
F(VOLATILE_UNUSED, padding, (u32, 1)) \
F(VOLATILE_INFATUATION, infatuation, (enum BattlerId, MAX_BITS(4))) \
F(VOLATILE_DEFENSE_CURL, defenseCurl, (u32, 1)) \
F(VOLATILE_TRANSFORMED, transformed, (u32, 1)) \
F(VOLATILE_RECHARGE, recharge, (u32, 1)) \
F(VOLATILE_RAGE, rage, (u32, 1)) \
F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 2)) \
F(VOLATILE_ESCAPE_PREVENTION, escapePrevention, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \
F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \
F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, 5)) \
F(VOLATILE_ELECTRIFIED, electrified, (u32, 1)) \
F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_INFINITE_CONFUSION, infiniteConfusion, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_SALT_CURE, saltCure, (u32, 1)) \
F(VOLATILE_SYRUP_BOMB, syrupBomb, (u32, 1)) \
F(VOLATILE_GLAIVE_RUSH, glaiveRush, (u32, 1)) \
F(VOLATILE_LEECH_SEED, leechSeed, (enum BattlerId, MAX_BITS(4)), V_BATON_PASSABLE) \
F(VOLATILE_LOCK_ON, lockOn, (u32, 2), V_BATON_PASSABLE) \
F(VOLATILE_PERISH_SONG, perishSong, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_MINIMIZE, minimize, (u32, 1)) \
F(VOLATILE_CHARGE, charge, (u32, 1)) \
F(VOLATILE_ROOT, root, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_YAWN, yawn, (u32, 2)) \
F(VOLATILE_IMPRISON, imprison, (u32, 1)) \
F(VOLATILE_GRUDGE, grudge, (u32, 1)) \
F(VOLATILE_GASTRO_ACID, gastroAcid, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_EMBARGO, embargo, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_SMACK_DOWN, smackDown, (u32, 1)) \
F(VOLATILE_TELEKINESIS, telekinesis, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_MIRACLE_EYE, miracleEye, (u32, 1)) \
F(VOLATILE_MAGNET_RISE, magnetRise, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_HEAL_BLOCK, healBlock, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_AQUA_RING, aquaRing, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_LASER_FOCUS, laserFocus, (u32, 1)) \
F(VOLATILE_POWER_TRICK, powerTrick, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_NO_RETREAT, noRetreat, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_VESSEL_OF_RUIN, vesselOfRuin, (u32, 1)) \
F(VOLATILE_SWORD_OF_RUIN, swordOfRuin, (u32, 1)) \
F(VOLATILE_TABLETS_OF_RUIN, tabletsOfRuin, (u32, 1)) \
F(VOLATILE_BEADS_OF_RUIN, beadsOfRuin, (u32, 1))
/* Use within a macro to get the maximum allowed value for a volatile. Requires _typeBitSize and debug parameters as input. */
#define GET_VOLATILE_MAXIMUM(_typeBitSize, ...) INVOKE_WITH_B(GET_VOLATILE_MAXIMUM_, _typeBitSize)
#define GET_VOLATILE_MAXIMUM_(_type, ...) FIRST(__VA_OPT__(MAX_BITS(FIRST(__VA_ARGS__)),) MAX_BITS((sizeof(_type) * 8)))
/* Use within a macro to get the maximum allowed value for a volatile. Requires _typeMaxValue as input. */
#define GET_VOLATILE_MAXIMUM(_typeMaxValue, ...) INVOKE_WITH_B(GET_VOLATILE_MAXIMUM_, _typeMaxValue)
#define GET_VOLATILE_MAXIMUM_(_type, ...) FIRST(__VA_OPT__(FIRST(__VA_ARGS__),) MAX_BITS((sizeof(_type) * 8)))
#define UNPACK_VOLATILE_ENUMS(_enum, ...) _enum,
enum Volatile
{
VOLATILE_NONE,
VOLATILE_DEFINITIONS(UNPACK_VOLATILE_ENUMS)
/* Expands to VOLATILE_CONFUSION, VOLATILE_FLINCHED, etc. */
};
// Old flags
#define STATUS2_CONFUSION (1 << 0 | 1 << 1 | 1 << 2)
#define STATUS2_CONFUSION_TURN(num) ((num) << 0)
#define STATUS2_FLINCHED (1 << 3)
#define STATUS2_UPROAR (1 << 4 | 1 << 5 | 1 << 6)
#define STATUS2_UPROAR_TURN(num) ((num) << 4)
#define STATUS2_TORMENT (1 << 7)
#define STATUS2_BIDE (1 << 8 | 1 << 9)
#define STATUS2_BIDE_TURN(num) (((num) << 8) & STATUS2_BIDE)
#define STATUS2_LOCK_CONFUSE (1 << 10 | 1 << 11) // e.g. Thrash
#define STATUS2_LOCK_CONFUSE_TURN(num)((num) << 10)
#define STATUS2_MULTIPLETURNS (1 << 12)
#define STATUS2_WRAPPED (1 << 13)
#define STATUS2_POWDER (1 << 14)
//#define STATUS2_UNUSED (1 << 15)
#define STATUS2_INFATUATION (1 << 16 | 1 << 17 | 1 << 18 | 1 << 19) // 4 bits, one for every battler
#define STATUS2_INFATUATED_WITH(battler) (1u << (battler + 16))
#define STATUS2_DEFENSE_CURL (1 << 20)
#define STATUS2_TRANSFORMED (1 << 21)
#define STATUS2_RECHARGE (1 << 22)
#define STATUS2_RAGE (1 << 23)
#define STATUS2_SUBSTITUTE (1 << 24)
#define STATUS2_DESTINY_BOND (1 << 25)
#define STATUS2_ESCAPE_PREVENTION (1 << 26)
#define STATUS2_NIGHTMARE (1 << 27)
#define STATUS2_CURSED (1 << 28)
#define STATUS2_FORESIGHT (1 << 29)
#define STATUS2_DRAGON_CHEER (1 << 30)
#define STATUS2_FOCUS_ENERGY (1 << 31)
#define STATUS2_FOCUS_ENERGY_ANY (STATUS2_DRAGON_CHEER | STATUS2_FOCUS_ENERGY)
// Helper macros
#define INFATUATED_WITH(battler) (battler + 1)
#define LEECHSEEDED_BY(battler) (battler + 1)
#define STATUS3_LEECHSEED_BATTLER (1 << 0 | 1 << 1) // The battler to receive HP from Leech Seed
#define STATUS3_LEECHSEED (1 << 2)
#define STATUS3_ALWAYS_HITS (1 << 3 | 1 << 4)
#define STATUS3_ALWAYS_HITS_TURN(num) (((num) << 3) & STATUS3_ALWAYS_HITS) // "Always Hits" is set as a 2 turn timer, i.e. next turn is the last turn when it's active
#define STATUS3_PERISH_SONG (1 << 5)
#define STATUS3_ON_AIR (1 << 6)
#define STATUS3_UNDERGROUND (1 << 7)
#define STATUS3_MINIMIZED (1 << 8)
#define STATUS3_CHARGED_UP (1 << 9)
#define STATUS3_ROOTED (1 << 10)
#define STATUS3_YAWN (1 << 11 | 1 << 12) // Number of turns to sleep
#define STATUS3_YAWN_TURN(num) (((num) << 11) & STATUS3_YAWN)
#define STATUS3_IMPRISONED_OTHERS (1 << 13)
#define STATUS3_GRUDGE (1 << 14)
#define STATUS3_COMMANDER (1 << 15)
#define STATUS3_GASTRO_ACID (1 << 16)
#define STATUS3_EMBARGO (1 << 17)
#define STATUS3_UNDERWATER (1 << 18)
#define STATUS3_UNUSED_19 (1 << 19)
#define STATUS3_UNUSED_20 (1 << 20)
#define STATUS3_SMACKED_DOWN (1 << 21)
#define STATUS3_UNUSED_22 (1 << 22)
#define STATUS3_TELEKINESIS (1 << 23)
#define STATUS3_PHANTOM_FORCE (1 << 24)
#define STATUS3_MIRACLE_EYED (1 << 25)
#define STATUS3_MAGNET_RISE (1 << 26)
#define STATUS3_HEAL_BLOCK (1 << 27)
#define STATUS3_AQUA_RING (1 << 28)
#define STATUS3_LASER_FOCUS (1 << 29)
#define STATUS3_POWER_TRICK (1 << 30)
#define STATUS3_SKY_DROPPED (1 << 31) // Target of Sky Drop
#define STATUS3_SEMI_INVULNERABLE_NO_COMMANDER (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) // Exception for Transform / Imposter
#define STATUS3_SEMI_INVULNERABLE (STATUS3_SEMI_INVULNERABLE_NO_COMMANDER | STATUS3_COMMANDER)
enum SemiInvulnerableState
{
STATE_NONE,
STATE_UNDERGROUND,
STATE_UNDERWATER,
STATE_ON_AIR,
STATE_PHANTOM_FORCE,
STATE_SKY_DROP,
STATE_COMMANDER,
};
#define STATUS4_ELECTRIFIED (1 << 0)
#define STATUS4_MUD_SPORT (1 << 1) // Only used if B_SPORT_TURNS < GEN_6
#define STATUS4_WATER_SPORT (1 << 2) // Only used if B_SPORT_TURNS < GEN_6
#define STATUS4_INFINITE_CONFUSION (1 << 3) // Used for Berserk Gene
#define STATUS4_SALT_CURE (1 << 4)
#define STATUS4_SYRUP_BOMB (1 << 5)
#define STATUS4_GLAIVE_RUSH (1 << 6)
enum SemiInvulnerableExclusion
{
CHECK_ALL,
EXCLUDE_COMMANDER,
};
#define HITMARKER_STRING_PRINTED (1 << 4)
#define HITMARKER_IGNORE_BIDE (1 << 5)
#define HITMARKER_DESTINYBOND (1 << 6)
#define HITMARKER_NO_ANIMATIONS (1 << 7) // set from battleSceneOff. Never changed during battle
#define HITMARKER_IGNORE_SUBSTITUTE (1 << 8)
#define HITMARKER_NO_ATTACKSTRING (1 << 9)
#define HITMARKER_ATTACKSTRING_PRINTED (1 << 10)
#define HITMARKER_NO_PPDEDUCT (1 << 11)
#define HITMARKER_ATTACKSTRING_PRINTED (1 << 9)
#define HITMARKER_UNUSED_10 (1 << 10)
#define HITMARKER_UNUSED_11 (1 << 11)
#define HITMARKER_UNUSED_12 (1 << 12)
#define HITMARKER_STATUS_ABILITY_EFFECT (1 << 13)
#define HITMARKER_UNUSED_14 (1 << 14)
@ -277,10 +258,10 @@ enum Volatile
#define HITMARKER_DISABLE_ANIMATION (1 << 17) // disable animations during battle scripts, e.g. for Bug Bite
#define HITMARKER_UNUSED_18 (1 << 18)
#define HITMARKER_UNABLE_TO_USE_MOVE (1 << 19)
#define HITMARKER_PASSIVE_DAMAGE (1 << 20)
#define HITMARKER_PASSIVE_HP_UPDATE (1 << 20)
#define HITMARKER_UNUSED_21 (1 << 21)
#define HITMARKER_PLAYER_FAINTED (1 << 22)
#define HITMARKER_ALLOW_NO_PP (1 << 23)
#define HITMARKER_UNUSED_23 (1 << 23)
#define HITMARKER_GRUDGE (1 << 24)
#define HITMARKER_OBEYS (1 << 25)
#define HITMARKER_UNUSED_26 (1 << 26)
@ -291,27 +272,33 @@ enum Volatile
// Per-side statuses that affect an entire party
#define SIDE_STATUS_REFLECT (1 << 0)
#define SIDE_STATUS_LIGHTSCREEN (1 << 1)
#define SIDE_STATUS_STICKY_WEB (1 << 2)
#define SIDE_STATUS_SPIKES (1 << 4)
#define SIDE_STATUS_SAFEGUARD (1 << 5)
#define SIDE_STATUS_FUTUREATTACK (1 << 6)
#define SIDE_STATUS_MIST (1 << 8)
// (1 << 9) previously was SIDE_STATUS_SPIKES_DAMAGED
#define SIDE_STATUS_TAILWIND (1 << 10)
#define SIDE_STATUS_AURORA_VEIL (1 << 11)
#define SIDE_STATUS_LUCKY_CHANT (1 << 12)
#define SIDE_STATUS_TOXIC_SPIKES (1 << 13)
#define SIDE_STATUS_STEALTH_ROCK (1 << 14)
// Missing flags previously were SIDE_STATUS_TOXIC_SPIKES_DAMAGED, SIDE_STATUS_STEALTH_ROCK_DAMAGED, SIDE_STATUS_STICKY_WEB_DAMAGED
#define SIDE_STATUS_STEELSURGE (1 << 18)
#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 19)
#define SIDE_STATUS_RAINBOW (1 << 20)
#define SIDE_STATUS_SEA_OF_FIRE (1 << 21)
#define SIDE_STATUS_SWAMP (1 << 22)
#define SIDE_STATUS_SAFEGUARD (1 << 2)
#define SIDE_STATUS_FUTUREATTACK (1 << 3)
#define SIDE_STATUS_MIST (1 << 4)
#define SIDE_STATUS_TAILWIND (1 << 5)
#define SIDE_STATUS_AURORA_VEIL (1 << 6)
#define SIDE_STATUS_LUCKY_CHANT (1 << 7)
#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 8)
#define SIDE_STATUS_RAINBOW (1 << 9)
#define SIDE_STATUS_SEA_OF_FIRE (1 << 10)
#define SIDE_STATUS_SWAMP (1 << 11)
#define SIDE_STATUS_HAZARDS_ANY (SIDE_STATUS_SPIKES | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STEELSURGE)
#define SIDE_STATUS_SCREEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)
#define SIDE_STATUS_PLEDGE_ANY (SIDE_STATUS_RAINBOW | SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_SWAMP)
#define SIDE_STATUS_GOOD_FOG (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST)
#define SIDE_STATUS_GOOD_COURT (SIDE_STATUS_GOOD_FOG | SIDE_STATUS_TAILWIND | SIDE_STATUS_LUCKY_CHANT | SIDE_STATUS_RAINBOW)
#define SIDE_STATUS_BAD_COURT (SIDE_STATUS_DAMAGE_NON_TYPES | SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_SWAMP)
enum Hazards
{
HAZARDS_NONE,
HAZARDS_SPIKES,
HAZARDS_STICKY_WEB,
HAZARDS_TOXIC_SPIKES,
HAZARDS_STEALTH_ROCK,
HAZARDS_STEELSURGE,
HAZARDS_MAX_COUNT,
};
// Used for damaging entry hazards based on type
enum TypeSideHazard
@ -347,6 +334,7 @@ enum TypeSideHazard
#define MOVE_RESULT_FOE_HUNG_ON (1 << 7)
#define MOVE_RESULT_STURDIED (1 << 8)
#define MOVE_RESULT_FOE_ENDURED_AFFECTION (1 << 9)
#define MOVE_RESULT_SYNCHRONOISE_AFFECTED (1 << 10)
#define MOVE_RESULT_NO_EFFECT (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED)
enum BattleWeather
@ -380,18 +368,22 @@ enum BattleWeather
#define B_WEATHER_STRONG_WINDS (1 << BATTLE_WEATHER_STRONG_WINDS)
#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW | B_WEATHER_FOG)
#define B_WEATHER_DAMAGING_ANY (B_WEATHER_HAIL | B_WEATHER_SANDSTORM)
#define B_WEATHER_ICY_ANY (B_WEATHER_HAIL | B_WEATHER_SNOW)
#define B_WEATHER_LOW_LIGHT (B_WEATHER_FOG | B_WEATHER_ICY_ANY | B_WEATHER_RAIN | B_WEATHER_SANDSTORM)
#define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS)
enum MoveEffects
// Explicit numbers until frostbite because those shouldn't be shifted
enum __attribute__((packed)) MoveEffect
{
MOVE_EFFECT_NONE,
MOVE_EFFECT_SLEEP,
MOVE_EFFECT_POISON,
MOVE_EFFECT_BURN,
MOVE_EFFECT_FREEZE,
MOVE_EFFECT_PARALYSIS,
MOVE_EFFECT_TOXIC,
MOVE_EFFECT_FROSTBITE,
MOVE_EFFECT_NONE = 0,
MOVE_EFFECT_SLEEP = 1,
MOVE_EFFECT_POISON = 2,
MOVE_EFFECT_BURN = 3,
MOVE_EFFECT_FREEZE = 4,
MOVE_EFFECT_PARALYSIS = 5,
MOVE_EFFECT_TOXIC = 6,
MOVE_EFFECT_FROSTBITE = 7,
MOVE_EFFECT_CONFUSION,
MOVE_EFFECT_FLINCH,
MOVE_EFFECT_TRI_ATTACK,
@ -415,7 +407,6 @@ enum MoveEffects
MOVE_EFFECT_REMOVE_ARG_TYPE,
MOVE_EFFECT_RECHARGE,
MOVE_EFFECT_RAGE,
MOVE_EFFECT_STEAL_ITEM,
MOVE_EFFECT_PREVENT_ESCAPE,
MOVE_EFFECT_NIGHTMARE,
MOVE_EFFECT_ALL_STATS_UP,
@ -451,8 +442,6 @@ enum MoveEffects
MOVE_EFFECT_TRAP_BOTH,
MOVE_EFFECT_ROUND,
MOVE_EFFECT_DIRE_CLAW,
MOVE_EFFECT_STEALTH_ROCK,
MOVE_EFFECT_SPIKES,
MOVE_EFFECT_SYRUP_BOMB,
MOVE_EFFECT_FLORAL_HEALING,
MOVE_EFFECT_SECRET_POWER,
@ -466,6 +455,11 @@ enum MoveEffects
MOVE_EFFECT_LIGHT_SCREEN,
MOVE_EFFECT_SALT_CURE,
MOVE_EFFECT_EERIE_SPELL,
// Max move effects happen earlier in the execution chain.
// For example stealth rock from G-Max Stonesurge is set up before abilities but from Stone Axe after.
// Stone Axe can also fail to set up rocks if user faints where as Stonesurge will always go up.
// This means we need to be careful if we want to re-use those effects for (new) vanilla moves
MOVE_EFFECT_RAISE_TEAM_ATTACK,
MOVE_EFFECT_RAISE_TEAM_DEFENSE,
MOVE_EFFECT_RAISE_TEAM_SPEED,
@ -507,11 +501,14 @@ enum MoveEffects
MOVE_EFFECT_LOWER_EVASIVENESS_SIDE,
MOVE_EFFECT_AROMATHERAPY,
MOVE_EFFECT_CONFUSE_SIDE,
MOVE_EFFECT_STEELSURGE,
MOVE_EFFECT_STEELSURGE, // Steel type rocks
MOVE_EFFECT_STEALTH_ROCK, // Max Move rocks, not to be confused for rocks set up from Ceasless Edge (same but differ in execution order)
MOVE_EFFECT_TORMENT_SIDE,
MOVE_EFFECT_LOWER_SPEED_2_SIDE,
MOVE_EFFECT_FIRE_SPIN_SIDE,
MOVE_EFFECT_FIXED_POWER,
// Max move effects end. They can be used for (custom) normal moves.
NUM_MOVE_EFFECTS
};
@ -687,4 +684,18 @@ enum MonState
MON_OUTSIDE_BATTLE,
};
enum __attribute__((packed)) CalcDamageState
{
CAN_DAMAGE,
WILL_FAIL,
CHECK_ACCURACY,
};
enum SubmoveState
{
SUBMOVE_NO_EFFECT,
SUBMOVE_SUCCESS,
SUBMOVE_FAILURE,
};
#endif // GUARD_CONSTANTS_BATTLE_H

View File

@ -3,52 +3,53 @@
// AI Flags. Most run specific functions to update score, new flags are used for internal logic in other scripts
// See docs/ai_flags.md for more details.
#define AI_FLAG_CHECK_BAD_MOVE (1 << 0) // AI will avoid using moves that are likely to fail or be ineffective in the current situation.
#define AI_FLAG_TRY_TO_FAINT (1 << 1) // AI will prioritize KOing the player's mon if able.
#define AI_FLAG_CHECK_VIABILITY (1 << 2) // AI damaging moves and move effects to determine the best available move in the current situation.
#define AI_FLAG_FORCE_SETUP_FIRST_TURN (1 << 3) // AI will prioritize using setup moves on the first turn at the expensve of all else. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense.
#define AI_FLAG_RISKY (1 << 4) // AI will generally behave more recklessly, prioritizing damage over accuracy, explosions, etc.
#define AI_FLAG_TRY_TO_2HKO (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
#define AI_FLAG_PREFER_BATON_PASS (1 << 6) // AI prefers raising its own stats and setting for / using Baton Pass.
#define AI_FLAG_DOUBLE_BATTLE (1 << 7) // Automatically set for double battles, handles AI behaviour with partner.
#define AI_FLAG_HP_AWARE (1 << 8) // AI will favour certain move effects based on how much remaining HP it and the player's mon have.
#define AI_FLAG_POWERFUL_STATUS (1 << 9) // AI prefers moves that set up field effects or side statuses, even if the user can faint the target.
#define AI_FLAG(x) ((u64)1 << x)
#define AI_FLAG_CHECK_BAD_MOVE AI_FLAG(0) // AI will avoid using moves that are likely to fail or be ineffective in the current situation.
#define AI_FLAG_TRY_TO_FAINT AI_FLAG(1) // AI will prioritize KOing the player's mon if able.
#define AI_FLAG_CHECK_VIABILITY AI_FLAG(2) // AI damaging moves and move effects to determine the best available move in the current situation.
#define AI_FLAG_FORCE_SETUP_FIRST_TURN AI_FLAG(3) // AI will prioritize using setup moves on the first turn at the expensve of all else. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense.
#define AI_FLAG_RISKY AI_FLAG(4) // AI will generally behave more recklessly, prioritizing damage over accuracy, explosions, etc.
#define AI_FLAG_TRY_TO_2HKO AI_FLAG(5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
#define AI_FLAG_PREFER_BATON_PASS AI_FLAG(6) // AI prefers raising its own stats and setting for / using Baton Pass.
#define AI_FLAG_DOUBLE_BATTLE AI_FLAG(7) // Automatically set for double battles, handles AI behaviour with partner.
#define AI_FLAG_HP_AWARE AI_FLAG(8) // AI will favour certain move effects based on how much remaining HP it and the player's mon have.
#define AI_FLAG_POWERFUL_STATUS AI_FLAG(9) // AI prefers moves that set up field effects or side statuses, even if the user can faint the target.
// New, Trainer Handicap Flags
#define AI_FLAG_NEGATE_UNAWARE (1 << 10) // AI is NOT aware of negating effects like wonder room, mold breaker, etc.
#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc.
#define AI_FLAG_NEGATE_UNAWARE AI_FLAG(10) // AI is NOT aware of negating effects like wonder room, mold breaker, etc.
#define AI_FLAG_WILL_SUICIDE AI_FLAG(11) // AI will use explosion / self destruct / final gambit / etc.
// New, Trainer Strategy Flags
#define AI_FLAG_PREFER_STATUS_MOVES (1 << 12) // AI gets a score bonus for status moves. Should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves.
#define AI_FLAG_STALL (1 << 13) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished.
#define AI_FLAG_SMART_SWITCHING (1 << 14) // AI includes a lot more switching checks. Automatically includes AI_FLAG_SMART_MON_CHOICES.
#define AI_FLAG_ACE_POKEMON (1 << 15) // AI has an Ace Pokemon. The last Pokemon in the party will not be used until it's the last one remaining.
#define AI_FLAG_OMNISCIENT (1 << 16) // AI has full knowledge of player moves, abilities, hold items.
#define AI_FLAG_SMART_MON_CHOICES (1 << 17) // AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are separate decisions. Automatically included by AI_FLAG_SMART_SWITCHING.
#define AI_FLAG_CONSERVATIVE (1 << 18) // AI assumes all moves will low roll damage.
#define AI_FLAG_SEQUENCE_SWITCHING (1 << 19) // AI switches in mons in exactly party order, and never switches mid-battle.
#define AI_FLAG_DOUBLE_ACE_POKEMON (1 << 20) // AI has *two* Ace Pokémon. The last two Pokémons in the party won't be used unless they're the last ones remaining. Goes well in battles where the trainer ID equals to twins, couples, etc.
#define AI_FLAG_WEIGH_ABILITY_PREDICTION (1 << 21) // AI will predict player's ability based on aiRating
#define AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE (1 << 22) // AI adds score to highest damage move regardless of accuracy or secondary effect
#define AI_FLAG_PREDICT_SWITCH (1 << 23) // AI will predict the player's switches and switchins based on how it would handle the situation. Recommend using AI_FLAG_OMNISCIENT
#define AI_FLAG_PREDICT_INCOMING_MON (1 << 24) // AI will score against the predicting incoming mon if it predicts the player to switch. Requires AI_FLAG_PREDICT_SWITCH
#define AI_FLAG_PP_STALL_PREVENTION (1 << 25) // AI keeps track of the player's switches where the incoming mon is immune to the chosen move
#define AI_FLAG_PREDICT_MOVE (1 << 26) // AI will predict the player's move based on what move it would use in the same situation. Recommend using AI_FLAG_OMNISCIENT
#define AI_FLAG_SMART_TERA (1 << 27) // AI will make smarter decisions when choosing whether to terrastalize (default is to always tera whenever available).
#define AI_FLAG_COUNT 28
// Flags at and after 32 need different formatting, as in
// #define AI_FLAG_PLACEHOLDER ((u64)1 << 32)
#define AI_FLAG_PREFER_STATUS_MOVES AI_FLAG(12) // AI gets a score bonus for status moves. Should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves.
#define AI_FLAG_STALL AI_FLAG(13) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished.
#define AI_FLAG_SMART_SWITCHING AI_FLAG(14) // AI includes a lot more switching checks. Automatically includes AI_FLAG_SMART_MON_CHOICES.
#define AI_FLAG_ACE_POKEMON AI_FLAG(15) // AI has an Ace Pokemon. The last Pokemon in the party will not be used until it's the last one remaining.
#define AI_FLAG_OMNISCIENT AI_FLAG(16) // AI has full knowledge of player moves, abilities, hold items.
#define AI_FLAG_SMART_MON_CHOICES AI_FLAG(17) // AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are separate decisions. Automatically included by AI_FLAG_SMART_SWITCHING.
#define AI_FLAG_CONSERVATIVE AI_FLAG(18) // AI assumes all moves will low roll damage.
#define AI_FLAG_SEQUENCE_SWITCHING AI_FLAG(19) // AI switches in mons in exactly party order, and never switches mid-battle.
#define AI_FLAG_DOUBLE_ACE_POKEMON AI_FLAG(20) // AI has *two* Ace Pokémon. The last two Pokémons in the party won't be used unless they're the last ones remaining. Goes well in battles where the trainer ID equals to twins, couples, etc.
#define AI_FLAG_WEIGH_ABILITY_PREDICTION AI_FLAG(21) // AI will predict player's ability based on aiRating
#define AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE AI_FLAG(22) // AI adds score to highest damage move regardless of accuracy or secondary effect
#define AI_FLAG_PREDICT_SWITCH AI_FLAG(23) // AI will predict the player's switches and switchins based on how it would handle the situation. Recommend using AI_FLAG_OMNISCIENT
#define AI_FLAG_PREDICT_INCOMING_MON AI_FLAG(24) // AI will score against the predicting incoming mon if it predicts the player to switch. Requires AI_FLAG_PREDICT_SWITCH
#define AI_FLAG_PP_STALL_PREVENTION AI_FLAG(25) // AI keeps track of the player's switches where the incoming mon is immune to the chosen move
#define AI_FLAG_PREDICT_MOVE AI_FLAG(26) // AI will predict the player's move based on what move it would use in the same situation. Recommend using AI_FLAG_OMNISCIENT
#define AI_FLAG_SMART_TERA AI_FLAG(27) // AI will make smarter decisions when choosing whether to terrastalize (default is to always tera whenever available).
#define AI_FLAG_ASSUME_STAB AI_FLAG(28) // AI knows player's STAB moves, but nothing else. Restricted version of AI_FLAG_OMNISCIENT.
#define AI_FLAG_ASSUME_STATUS_MOVES AI_FLAG(29) // AI has a chance to know certain non-damaging moves, and also Fake Out and Super Fang. Restricted version of AI_FLAG_OMNISCIENT.
#define AI_FLAG_ATTACKS_PARTNER AI_FLAG(30) // AI specific to double battles; AI can deliberately attack its 'partner.'
// The following options are enough to have a basic/smart trainer. Any other addtion could make the trainer worse/better depending on the flag
#define AI_FLAG_BASIC_TRAINER (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY)
#define AI_FLAG_SMART_TRAINER (AI_FLAG_BASIC_TRAINER | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION | AI_FLAG_SMART_TERA)
#define AI_FLAG_PREDICTION (AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON | AI_FLAG_PREDICT_MOVE)
#define AI_FLAG_ASSUMPTIONS (AI_FLAG_ASSUME_STAB | AI_FLAG_ASSUME_STATUS_MOVES | AI_FLAG_WEIGH_ABILITY_PREDICTION)
// 'other' ai logic flags
#define AI_FLAG_DYNAMIC_FUNC ((u64)1 << 60) // Create custom AI functions for specific battles via "setdynamicaifunc" cmd
#define AI_FLAG_ROAMING ((u64)1 << 61)
#define AI_FLAG_SAFARI ((u64)1 << 62)
#define AI_FLAG_FIRST_BATTLE ((u64)1 << 63)
#define AI_FLAG_DYNAMIC_FUNC AI_FLAG(60) // Create custom AI functions for specific battles via "setdynamicaifunc" cmd
#define AI_FLAG_ROAMING AI_FLAG(61)
#define AI_FLAG_SAFARI AI_FLAG(62)
#define AI_FLAG_FIRST_BATTLE AI_FLAG(63)
#define AI_SCORE_DEFAULT 100 // Default score for all AI moves.

View File

@ -419,6 +419,10 @@
#define ANIM_TAG_PINKVIO_ORB (ANIM_SPRITES_START + 405)
#define ANIM_TAG_STARSTORM (ANIM_SPRITES_START + 406)
#define ANIM_TAG_SALT_PARTICLE (ANIM_SPRITES_START + 407)
#define ANIM_TAG_TERA_SYMBOL (ANIM_SPRITES_START + 408)
#define ANIM_TAG_TATSUGIRI_CURLY (ANIM_SPRITES_START + 409)
#define ANIM_TAG_TATSUGIRI_DROOPY (ANIM_SPRITES_START + 410)
#define ANIM_TAG_TATSUGIRI_STRETCHY (ANIM_SPRITES_START + 411)
// battlers
#define ANIM_ATTACKER 0
@ -588,9 +592,9 @@
#define B_ANIM_SIMPLE_HEAL 52
#define B_ANIM_POWER_CONSTRUCT 53
// pokefirered
#define B_ANIM_MON_SCARED (B_ANIM_POWER_CONSTRUCT + 1)
#define B_ANIM_GHOST_GET_OUT (B_ANIM_MON_SCARED + 1)
#define B_ANIM_SILPH_SCOPED (B_ANIM_GHOST_GET_OUT + 1)
#define B_ANIM_MON_SCARED 54
#define B_ANIM_GHOST_GET_OUT 55
#define B_ANIM_SILPH_SCOPED 56
#define B_ANIM_ROCK_THROW (B_ANIM_SILPH_SCOPED + 1)
#define B_ANIM_SAFARI_REACTION (B_ANIM_ROCK_THROW + 1)
@ -618,8 +622,9 @@
#define B_ANIM_STATUS_FRZ 6
#define B_ANIM_STATUS_CURSED 7
#define B_ANIM_STATUS_NIGHTMARE 8
#define B_ANIM_STATUS_FRB 9
#define NUM_B_ANIMS_STATUS 9
#define NUM_B_ANIMS_STATUS 10
// Tasks with return values often assign them to gBattleAnimArgs[7].
#define ARG_RET_ID 7
@ -663,6 +668,12 @@
#define ANIM_SURF_PAL_MUDDY_WATER 1
#define ANIM_SURF_PAL_SLUDGE_WAVE 2
// Order Up palettes for Commander
#define ANIM_ORDER_UP_NONE 0
#define ANIM_ORDER_UP_CURLY 1
#define ANIM_ORDER_UP_DROOPY 2
#define ANIM_ORDER_UP_STRETCHY 3
// Flags given to various functions to indicate which palettes to consider.
// Handled by UnpackSelectedBattlePalettes
#define F_PAL_BG (1 << 0)

View File

@ -1,7 +1,7 @@
#ifndef GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H
#define GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H
enum BattleMoveEffects
enum __attribute__((packed)) BattleMoveEffects
{
EFFECT_PLACEHOLDER,
EFFECT_HIT,
@ -9,7 +9,7 @@ enum BattleMoveEffects
EFFECT_ABSORB,
EFFECT_EXPLOSION,
EFFECT_MISTY_EXPLOSION, // Same as EFFECT_EXPLOSION but it's boosted on Misty Terrain
EFFECT_DREAM_EATER,
EFFECT_DREAM_EATER, // Same as EFFECT_ABSORB but it can only be used on sleeping targets
EFFECT_MIRROR_MOVE,
EFFECT_ATTACK_UP,
EFFECT_DEFENSE_UP,
@ -157,6 +157,7 @@ enum BattleMoveEffects
EFFECT_BRICK_BREAK,
EFFECT_YAWN,
EFFECT_KNOCK_OFF,
EFFECT_STEAL_ITEM,
EFFECT_ENDEAVOR,
EFFECT_POWER_BASED_ON_USER_HP,
EFFECT_SKILL_SWAP,
@ -310,7 +311,7 @@ enum BattleMoveEffects
EFFECT_MAX_HP_50_RECOIL,
EFFECT_CHLOROBLAST, // Same effect as EFFECT_MAX_HP_50_RECOIL but follows the same rules as EFFECT_RECOIL
EFFECT_EXTREME_EVOBOOST,
EFFECT_HIT_SET_REMOVE_TERRAIN,
EFFECT_HIT_SET_TERRAIN,
EFFECT_DARK_VOID,
EFFECT_VICTORY_DANCE,
EFFECT_TEATIME,
@ -348,6 +349,11 @@ enum BattleMoveEffects
EFFECT_SPECTRAL_THIEF,
EFFECT_RECOIL,
EFFECT_SMACK_DOWN,
EFFECT_LIFE_DEW,
EFFECT_ICE_SPINNER, // Removes terrain unless attacker is removed from field either by fainting or ejected out
EFFECT_STEEL_ROLLER, // Will fail if there is no terrain up but removes it regardless if attacker is removed from field or not
EFFECT_STONE_AXE, // Not to be confused with MOVE_EFFECT_STEALTH_ROCK. They have two different activation timings.
EFFECT_CEASELESS_EDGE, // Same applies to spikes
NUM_BATTLE_MOVE_EFFECTS,
};

View File

@ -33,7 +33,7 @@
#define sSAVED_DMG (gBattleScripting + 0x28) // savedDmg
#define sSAVED_MOVE_EFFECT (gBattleScripting + 0x2C) // savedMoveEffect
#define sMOVE_EFFECT (gBattleScripting + 0x2E) // moveEffect
#define sMULTIHIT_EFFECT (gBattleScripting + 0x30) // multihitMoveEffect
#define sUNUSED_0x30 (gBattleScripting + 0x30) // unused_0x30
#define sILLUSION_NICK_HACK (gBattleScripting + 0x32) // illusionNickHack
#define sFIXED_ABILITY_POPUP (gBattleScripting + 0x33) // fixedPopup
#define sABILITY_OVERWRITE (gBattleScripting + 0x34) // abilityPopupOverwrite
@ -88,126 +88,10 @@
#define CMP_COMMON_BITS 4
#define CMP_NO_COMMON_BITS 5
// Veriouses have been deprecated but the enum and function will be supported for one more release cycle
enum CmdVarious
{
VARIOUS_CANCEL_MULTI_TURN_MOVES,
VARIOUS_IS_RUNNING_IMPOSSIBLE,
VARIOUS_GET_MOVE_TARGET,
VARIOUS_GET_BATTLER_FAINTED,
VARIOUS_RESET_SWITCH_IN_ABILITY_BITS,
VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP,
VARIOUS_RESET_PLAYER_FAINTED,
VARIOUS_PALACE_FLAVOR_TEXT,
VARIOUS_ARENA_JUDGMENT_WINDOW,
VARIOUS_ARENA_OPPONENT_MON_LOST,
VARIOUS_ARENA_PLAYER_MON_LOST,
VARIOUS_ARENA_BOTH_MONS_LOST,
VARIOUS_EMIT_YESNOBOX,
VARIOUS_DRAW_ARENA_REF_TEXT_BOX,
VARIOUS_ERASE_ARENA_REF_TEXT_BOX,
VARIOUS_ARENA_JUDGMENT_STRING,
VARIOUS_ARENA_WAIT_STRING,
VARIOUS_WAIT_CRY,
VARIOUS_RETURN_OPPONENT_MON1,
VARIOUS_RETURN_OPPONENT_MON2,
VARIOUS_VOLUME_DOWN,
VARIOUS_VOLUME_UP,
VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT,
VARIOUS_PALACE_TRY_ESCAPE_STATUS,
VARIOUS_SET_TELEPORT_OUTCOME,
VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC,
VARIOUS_STAT_TEXT_BUFFER,
VARIOUS_SWITCHIN_ABILITIES,
VARIOUS_INSTANT_HP_DROP,
VARIOUS_CLEAR_STATUS,
VARIOUS_RESTORE_PP,
VARIOUS_PLAY_MOVE_ANIMATION,
VARIOUS_SET_LUCKY_CHANT,
VARIOUS_SUCKER_PUNCH_CHECK,
VARIOUS_SET_SIMPLE_BEAM,
VARIOUS_TRY_ENTRAINMENT,
VARIOUS_SET_LAST_USED_ABILITY,
VARIOUS_INVERT_STAT_STAGES,
VARIOUS_TRY_ME_FIRST,
VARIOUS_JUMP_IF_BATTLE_END,
VARIOUS_TRY_ELECTRIFY,
VARIOUS_TRY_SOAK,
VARIOUS_TRY_LAST_RESORT,
VARIOUS_TRY_AUTOTOMIZE,
VARIOUS_ABILITY_POPUP,
VARIOUS_JUMP_IF_TARGET_ALLY,
VARIOUS_TRY_SYNCHRONOISE,
VARIOUS_PSYCHO_SHIFT,
VARIOUS_CURE_STATUS,
VARIOUS_POWER_TRICK,
VARIOUS_AFTER_YOU,
VARIOUS_BESTOW,
VARIOUS_JUMP_IF_NOT_GROUNDED,
VARIOUS_HANDLE_TRAINER_SLIDE_MSG,
VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF,
VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON,
VARIOUS_SET_AURORA_VEIL,
VARIOUS_TRY_THIRD_TYPE,
VARIOUS_ACUPRESSURE,
VARIOUS_SET_POWDER,
VARIOUS_GRAVITY_ON_AIRBORNE_MONS,
VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS,
VARIOUS_JUMP_IF_ROAR_FAILS,
VARIOUS_TRY_INSTRUCT,
VARIOUS_JUMP_IF_NOT_BERRY,
VARIOUS_TRACE_ABILITY,
VARIOUS_UPDATE_NICK,
VARIOUS_TRY_ILLUSION_OFF,
VARIOUS_SET_SPRITEIGNORE0HP,
VARIOUS_HANDLE_FORM_CHANGE,
VARIOUS_GET_STAT_VALUE,
VARIOUS_JUMP_IF_FULL_HP,
VARIOUS_LOSE_TYPE,
VARIOUS_TRY_ACTIVATE_SOULHEART,
VARIOUS_TRY_ACTIVATE_RECEIVER,
VARIOUS_TRY_FRISK,
VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED,
VARIOUS_TRY_FAIRY_LOCK,
VARIOUS_JUMP_IF_NO_ALLY,
VARIOUS_JUMP_IF_HOLD_EFFECT,
VARIOUS_INFATUATE_WITH_BATTLER,
VARIOUS_SET_LAST_USED_ITEM,
VARIOUS_JUMP_IF_ABSENT,
VARIOUS_DESTROY_ABILITY_POPUP,
VARIOUS_TOTEM_BOOST,
VARIOUS_MOVEEND_ITEM_EFFECTS,
VARIOUS_TERRAIN_SEED,
VARIOUS_MAKE_INVISIBLE,
VARIOUS_ROOM_SERVICE,
VARIOUS_JUMP_IF_TEAM_HEALTHY,
VARIOUS_TRY_HEAL_QUARTER_HP,
VARIOUS_JUMP_IF_PRANKSTER_BLOCKED,
VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER,
VARIOUS_GET_ROTOTILLER_TARGETS,
VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED,
VARIOUS_CONSUME_BERRY,
VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL,
VARIOUS_JUMP_IF_SPECIES,
VARIOUS_UPDATE_ABILITY_POPUP,
VARIOUS_JUMP_IF_WEATHER_AFFECTED,
VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED,
VARIOUS_SET_ATTACKER_STICKY_WEB_USER,
VARIOUS_TRY_NO_RETREAT,
VARIOUS_CHECK_POLTERGEIST,
VARIOUS_CUT_1_3_HP_RAISE_STATS,
VARIOUS_TRY_END_NEUTRALIZING_GAS,
VARIOUS_JUMP_IF_UNDER_200,
VARIOUS_SET_SKY_DROP,
VARIOUS_CLEAR_SKY_DROP,
VARIOUS_SKY_DROP_YAWN,
VARIOUS_CURE_CERTAIN_STATUSES,
VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES,
VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY,
VARIOUS_SAVE_BATTLER_ITEM,
VARIOUS_RESTORE_BATTLER_ITEM,
VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM,
// pokefirered
VARIOUS_GET_BATTLERS_FOR_RECALL, // for battle tower
VARIOUS_NONE,
};
// Cmd_manipulatedamage
@ -241,10 +125,10 @@ enum CmdVarious
#define PARTY_SCREEN_OPTIONAL (1 << 7) // Flag for first argument to openpartyscreen
// cases for Cmd_moveend
// cases for Cmd_moveend - Order matters!
enum MoveEndEffects
{
MOVEEND_SUM_DAMAGE,
MOVEEND_SET_VALUES,
MOVEEND_PROTECT_LIKE_EFFECT,
MOVEEND_ABSORB,
MOVEEND_RAGE,
@ -253,12 +137,10 @@ enum MoveEndEffects
MOVEEND_ABILITIES_ATTACKER,
MOVEEND_STATUS_IMMUNITY_ABILITIES,
MOVEEND_SYNCHRONIZE_ATTACKER,
MOVEEND_CHOICE_MOVE,
MOVEEND_ATTACKER_INVISIBLE,
MOVEEND_ATTACKER_VISIBLE,
MOVEEND_TARGET_VISIBLE,
MOVEEND_ITEM_EFFECTS_TARGET,
MOVEEND_FIRST_MOVE_BLOCK,
MOVEEND_ITEM_EFFECTS_ALL,
MOVEEND_SYMBIOSIS,
MOVEEND_KINGSROCK, // These item effects will occur each strike of a multi-hit move
@ -269,20 +151,23 @@ enum MoveEndEffects
MOVEEND_DEFROST,
MOVEEND_NEXT_TARGET, // Everything up until here is handled for each strike of a spread move
MOVEEND_MULTIHIT_MOVE,
MOVEEND_SECOND_MOVE_BLOCK,
MOVEEND_MOVE_BLOCK,
MOVEEND_ITEM_EFFECTS_ATTACKER,
MOVEEND_ABILITY_BLOCK,
MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell
MOVEEND_RED_CARD,
MOVEEND_EJECT_BUTTON,
MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc
MOVEEND_LIFEORB_SHELLBELL,
MOVEEND_FORM_CHANGE,
MOVEEND_EMERGENCY_EXIT,
MOVEEND_EJECT_PACK,
MOVEEND_HIT_ESCAPE,
MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts
MOVEEND_OPPORTUNIST,
MOVEEND_MIRROR_HERB,
MOVEEND_PICKPOCKET,
MOVEEND_WHITE_HERB,
MOVEEND_THIRD_MOVE_BLOCK,
MOVEEND_CHANGED_ITEMS,
MOVEEND_SAME_MOVE_TURNS,
MOVEEND_CLEAR_BITS,
@ -296,11 +181,6 @@ enum MoveEndEffects
#define B_SWITCH_HIT 1 // dragon tail, circle throw
#define B_SWITCH_RED_CARD 2
// Argument labels for EFFECT_HIT_SET_REMOVE_TERRAIN
#define ARG_SET_PSYCHIC_TERRAIN 0
#define ARG_TRY_REMOVE_TERRAIN_HIT 1
#define ARG_TRY_REMOVE_TERRAIN_FAIL 2
enum StatusTrigger
{
TRIGGER_ON_MOVE,

View File

@ -41,7 +41,6 @@ enum StringID
STRINGID_PKMNMADESLEEP,
STRINGID_PKMNALREADYASLEEP,
STRINGID_PKMNALREADYASLEEP2,
STRINGID_PKMNWASNTAFFECTED,
STRINGID_PKMNWASPOISONED,
STRINGID_PKMNPOISONEDBY,
STRINGID_PKMNHURTBYPOISON,
@ -62,11 +61,8 @@ enum StringID
STRINGID_PKMNISPARALYZED,
STRINGID_PKMNISALREADYPARALYZED,
STRINGID_PKMNHEALEDPARALYSIS,
STRINGID_PKMNDREAMEATEN,
STRINGID_STATSWONTINCREASE,
STRINGID_STATSWONTDECREASE,
STRINGID_TEAMSTOPPEDWORKING,
STRINGID_FOESTOPPEDWORKING,
STRINGID_PKMNISCONFUSED,
STRINGID_PKMNHEALEDCONFUSION,
STRINGID_PKMNWASCONFUSED,
@ -74,7 +70,6 @@ enum StringID
STRINGID_PKMNFELLINLOVE,
STRINGID_PKMNINLOVE,
STRINGID_PKMNIMMOBILIZEDBYLOVE,
STRINGID_PKMNBLOWNAWAY,
STRINGID_PKMNCHANGEDTYPE,
STRINGID_PKMNFLINCHED,
STRINGID_PKMNREGAINEDHEALTH,
@ -118,7 +113,6 @@ enum StringID
STRINGID_PKMNCALMEDDOWN,
STRINGID_PKMNCANTSLEEPINUPROAR,
STRINGID_PKMNSTOCKPILED,
STRINGID_PKMNCANTSTOCKPILE,
STRINGID_PKMNCANTSLEEPINUPROAR2,
STRINGID_UPROARKEPTPKMNAWAKE,
STRINGID_PKMNSTAYEDAWAKEUSING,
@ -180,7 +174,6 @@ enum StringID
STRINGID_PKMNREADYTOHELP,
STRINGID_PKMNSWITCHEDITEMS,
STRINGID_PKMNCOPIEDFOE,
STRINGID_PKMNMADEWISH,
STRINGID_PKMNWISHCAMETRUE,
STRINGID_PKMNPLANTEDROOTS,
STRINGID_PKMNABSORBEDNUTRIENTS,
@ -197,14 +190,11 @@ enum StringID
STRINGID_PKMNWAITSFORTARGET,
STRINGID_PKMNSNATCHEDMOVE,
STRINGID_PKMNMADEITRAIN,
STRINGID_PKMNRAISEDSPEED,
STRINGID_PKMNPROTECTEDBY,
STRINGID_PKMNPREVENTSUSAGE,
STRINGID_PKMNRESTOREDHPUSING,
STRINGID_PKMNCHANGEDTYPEWITH,
STRINGID_PKMNPREVENTSPARALYSISWITH,
STRINGID_PKMNPREVENTSROMANCEWITH,
STRINGID_PKMNPREVENTSPOISONINGWITH,
STRINGID_PKMNPREVENTSCONFUSIONWITH,
STRINGID_PKMNRAISEDFIREPOWERWITH,
STRINGID_PKMNANCHORSITSELFWITH,
@ -234,7 +224,6 @@ enum StringID
STRINGID_BUTNOTHINGHAPPENED,
STRINGID_BUTITFAILED,
STRINGID_ITHURTCONFUSION,
STRINGID_MIRRORMOVEFAILED,
STRINGID_STARTEDTORAIN,
STRINGID_DOWNPOURSTARTED,
STRINGID_RAINCONTINUES,
@ -249,9 +238,6 @@ enum StringID
STRINGID_STARTEDHAIL,
STRINGID_HAILCONTINUES,
STRINGID_HAILSTOPPED,
STRINGID_FAILEDTOSPITUP,
STRINGID_FAILEDTOSWALLOW,
STRINGID_WINDBECAMEHEATWAVE,
STRINGID_STATCHANGESGONE,
STRINGID_COINSSCATTERED,
STRINGID_TOOWEAKFORSUBSTITUTE,
@ -308,7 +294,6 @@ enum StringID
STRINGID_ITEMALLOWSONLYYMOVE,
STRINGID_PKMNHUNGONWITHX,
STRINGID_EMPTYSTRING3,
STRINGID_PKMNSXPREVENTSBURNS,
STRINGID_PKMNSXBLOCKSY,
STRINGID_PKMNSXRESTOREDHPALITTLE2,
STRINGID_PKMNSXWHIPPEDUPSANDSTORM,
@ -327,8 +312,8 @@ enum StringID
STRINGID_PLAYERDEFEATEDTRAINER1,
STRINGID_SOOTHINGAROMA,
STRINGID_ITEMSCANTBEUSEDNOW,
STRINGID_FORXCOMMAYZ,
STRINGID_USINGITEMSTATOFPKMNROSE,
STRINGID_USINGITEMSTATOFPKMNFELL,
STRINGID_PKMNUSEDXTOGETPUMPED,
STRINGID_PKMNSXMADEYUSELESS,
STRINGID_PKMNTRAPPEDBYSANDTOMB,
@ -344,7 +329,6 @@ enum StringID
STRINGID_PKMNFLEDUSINGITS,
STRINGID_PKMNFLEDUSING,
STRINGID_PKMNWASDRAGGEDOUT,
STRINGID_PREVENTEDFROMWORKING,
STRINGID_PKMNSITEMNORMALIZEDSTATUS,
STRINGID_TRAINER1USEDITEM,
STRINGID_BOXISFULL,
@ -355,17 +339,13 @@ enum StringID
STRINGID_STATSWONTDECREASE2,
STRINGID_PKMNSXBLOCKSY2,
STRINGID_PKMNSXWOREOFF,
STRINGID_PKMNRAISEDDEFALITTLE,
STRINGID_PKMNRAISEDSPDEFALITTLE,
STRINGID_THEWALLSHATTERED,
STRINGID_PKMNSXPREVENTSYSZ,
STRINGID_PKMNSXCUREDITSYPROBLEM,
STRINGID_ATTACKERCANTESCAPE,
STRINGID_PKMNOBTAINEDX,
STRINGID_PKMNOBTAINEDX2,
STRINGID_PKMNOBTAINEDXYOBTAINEDZ,
STRINGID_BUTNOEFFECT,
STRINGID_PKMNSXHADNOEFFECTONY,
STRINGID_TWOENEMIESDEFEATED,
STRINGID_TRAINER2LOSETEXT,
STRINGID_PKMNINCAPABLEOFPOWER,
@ -424,10 +404,8 @@ enum StringID
STRINGID_FELLSTRAIGHTDOWN,
STRINGID_TARGETCHANGEDTYPE,
STRINGID_PKMNACQUIREDSIMPLE,
STRINGID_EMPTYSTRING5,
STRINGID_KINDOFFER,
STRINGID_RESETSTARGETSSTATLEVELS,
STRINGID_EMPTYSTRING6,
STRINGID_ALLYSWITCHPOSITION,
STRINGID_RESTORETARGETSHEALTH,
STRINGID_TOOKPJMNINTOTHESKY,
@ -481,7 +459,7 @@ enum StringID
STRINGID_HEALINGWISHCAMETRUE,
STRINGID_HEALINGWISHHEALED,
STRINGID_LUNARDANCECAMETRUE,
STRINGID_CUSEDBODYDISABLED,
STRINGID_CURSEDBODYDISABLED,
STRINGID_ATTACKERACQUIREDABILITY,
STRINGID_TARGETABILITYSTATLOWER,
STRINGID_TARGETSTATWONTGOHIGHER,
@ -558,10 +536,8 @@ enum StringID
STRINGID_COMATOSEENTERS,
STRINGID_SCREENCLEANERENTERS,
STRINGID_FETCHEDPOKEBALL,
STRINGID_BATTLERABILITYRAISEDSTAT,
STRINGID_ASANDSTORMKICKEDUP,
STRINGID_PKMNSWILLPERISHIN3TURNS,
STRINGID_ABILITYRAISEDSTATDRASTICALLY,
STRINGID_AURAFLAREDTOLIFE,
STRINGID_ASONEENTERS,
STRINGID_CURIOUSMEDICINEENTERS,
@ -598,7 +574,6 @@ enum StringID
STRINGID_BROKETHROUGHPROTECTION,
STRINGID_ABILITYALLOWSONLYMOVE,
STRINGID_SWAPPEDABILITIES,
STRINGID_PASTELVEILPROTECTED,
STRINGID_PASTELVEILENTERS,
STRINGID_BATTLERTYPECHANGEDTO,
STRINGID_BOTHCANNOLONGERESCAPE,
@ -766,33 +741,24 @@ enum StringID
// They are assigned to the MULTISTRING_CHOOSER byte of gBattleCommunication
// and read when e.g. the command printfromtable is used.
// gStatUpStringIds
enum StatUpStringID
// gStatUpStringIds and gStatDownStringIds
enum StatChangedStringID
{
B_MSG_ATTACKER_STAT_ROSE,
B_MSG_DEFENDER_STAT_ROSE,
B_MSG_STAT_WONT_INCREASE,
B_MSG_STAT_ROSE_EMPTY,
B_MSG_STAT_ROSE_ITEM,
B_MSG_ATTACKER_STAT_CHANGED,
B_MSG_DEFENDER_STAT_CHANGED,
B_MSG_STAT_WONT_CHANGE,
B_MSG_STAT_CHANGE_EMPTY,
B_MSG_STAT_CHANGED_ITEM,
B_MSG_USED_DIRE_HIT,
};
// gStatDownStringIds
enum StatDownStringID
{
B_MSG_ATTACKER_STAT_FELL = 0,
B_MSG_DEFENDER_STAT_FELL = 1,
B_MSG_STAT_WONT_DECREASE,
B_MSG_STAT_FELL_EMPTY,
};
// gMissStringIds
enum MissStringID
{
B_MSG_MISSED,
B_MSG_PROTECTED,
B_MSG_AVOIDED_ATK,
// Ability-related messages need to below this comment
// Ability-related messages need to be below this comment
B_MSG_AVOIDED_DMG,
B_MSG_GROUND_MISS,
};
@ -908,20 +874,6 @@ enum UproarOverTurnStringID
B_MSG_UPROAR_ENDS,
};
// gStockpileUsedStringIds
enum StockpileUsedStringID
{
B_MSG_STOCKPILED,
B_MSG_CANT_STOCKPILE,
};
// gSwallowFailStringIds
enum SwallowFailStringID
{
B_MSG_SWALLOW_FAILED,
B_MSG_SWALLOW_FULL_HP,
};
// gKOFailedStringIds
enum KOFailedStringID
{
@ -1070,17 +1022,6 @@ enum GotStatusedStringID
B_MSG_STATUSED_BY_ABILITY,
};
// gStatusPreventionStringIds
enum StatusPreventionStringID
{
B_MSG_ABILITY_PREVENTS_MOVE_BURN,
B_MSG_ABILITY_PREVENTS_MOVE_PARALYSIS,
B_MSG_ABILITY_PREVENTS_MOVE_POISON,
B_MSG_ABILITY_PREVENTS_ABILITY_STATUS,
B_MSG_STATUS_HAD_NO_EFFECT,
B_MSG_ABILITY_PASTEL_VEIL,
};
// gGotDefrostedStringIds
enum GotDefrostedStringID
{

View File

@ -20,6 +20,27 @@ enum GenConfigTag
GEN_CONFIG_DEFIANT_STICKY_WEB,
GEN_CONFIG_ENCORE_TARGET,
GEN_CONFIG_TIME_OF_DAY_HEALING_MOVES,
GEN_PICKUP_WILD,
GEN_PROTEAN_LIBERO,
GEN_INTREPID_SWORD,
GEN_DAUNTLESS_SHIELD,
GEN_ILLUMINATE_EFFECT,
GEN_STEAL_WILD_ITEMS,
GEN_SNOW_WARNING,
GEN_ALLY_SWITCH_FAIL_CHANCE,
GEN_DREAM_EATER_LIQUID_OOZE,
GEN_CONFIG_TRANSISTOR_BOOST,
GEN_CONFIG_RECALC_TURN_AFTER_ACTIONS,
GEN_CONFIG_UPDATED_INTIMIDATE,
GEN_CONFIG_DISGUISE_HP_LOSS,
GEN_CONFIG_AFTER_YOU_TURN_ORDER,
GEN_CONFIG_HEALING_WISH_SWITCH,
GEN_CONFIG_MEGA_EVO_TURN_ORDER,
GEN_CONFIG_SHEER_COLD_IMMUNITY,
GEN_CONFIG_WEAK_ARMOR_SPEED,
GEN_CONFIG_PRANKSTER_DARK_TYPES,
GEN_CONFIG_DESTINY_BOND_FAIL,
GEN_CONFIG_POWDER_RAIN,
GEN_CONFIG_COUNT
};

View File

@ -142,10 +142,9 @@ enum ItemHoldEffect
HOLD_EFFECT_OGERPON_MASK,
// Gen2 hold effect
HOLD_EFFECT_BERSERK_GENE,
HOLD_EFFECT_COUNT
};
#define HOLD_EFFECT_CHOICE(holdEffect) ((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS))
// Terrain seed params
#define HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN 0
#define HOLD_EFFECT_PARAM_GRASSY_TERRAIN 1

View File

@ -2,11 +2,11 @@
#define GUARD_CONSTANTS_ITEM_EFFECTS_H
// field 0 masks
#define ITEM0_DIRE_HIT 0x30 // Works the same way as move Focus Energy.
#define ITEM0_DIRE_HIT 0x30 // Works the same way as the move Focus Energy.
#define ITEM0_SACRED_ASH 0x40
#define ITEM0_INFATUATION 0x80
// field 1 masks
// new field 1 masks
#define ITEM1_X_ATTACK STAT_ATK
#define ITEM1_X_DEFENSE STAT_DEF
#define ITEM1_X_SPEED STAT_SPEED
@ -50,7 +50,7 @@
#define ITEM10_IS_VITAMIN 0x1
// fields 6 and onwards are item-specific arguments
// fields 6 and onwards (except field 10) are item-specific arguments
#define ITEM_EFFECT_ARG_START 6
// Special HP recovery amounts for ITEM4_HEAL_HP
@ -75,7 +75,7 @@
#define ITEM_EFFECT_CURE_POISON 3
#define ITEM_EFFECT_CURE_SLEEP 4
#define ITEM_EFFECT_CURE_BURN 5
#define ITEM_EFFECT_CURE_FREEZE 6
#define ITEM_EFFECT_CURE_FREEZE_FROSTBITE 6
#define ITEM_EFFECT_CURE_PARALYSIS 7
#define ITEM_EFFECT_CURE_CONFUSION 8
#define ITEM_EFFECT_CURE_INFATUATION 9
@ -93,4 +93,8 @@
#define ITEM_EFFECT_HEAL_PP 21
#define ITEM_EFFECT_NONE 22
// Since X item stat increases are now handled by battle scripts, the friendship increase effect is now handled by the battle controller in HandleAction_UseItem.
#define X_ITEM_FRIENDSHIP_INCREASE 1 // The amount of friendship gained by using an X item on a Pokémon in battle.
#define X_ITEM_MAX_FRIENDSHIP 200 // Friendship threshold at which Pokémon stop receiving a friendship increase from using X items on them in battle.
#endif // GUARD_CONSTANTS_ITEM_EFFECTS_H

View File

@ -1033,9 +1033,6 @@
#define MAIL_NONE 0xFF
#define ITEM_TO_MULCH(itemId)(((itemId) - ITEM_GROWTH_MULCH) + 1)
#define NUM_TECHNICAL_MACHINES 100
#define NUM_HIDDEN_MACHINES 8
#define MAX_BAG_ITEM_CAPACITY 999
#define MAX_PC_ITEM_CAPACITY 999
#define MAX_PYRAMID_BAG_ITEM_CAPACITY 99 // Values higher than 255 require free SaveBlock2 space.

View File

@ -301,6 +301,8 @@ enum EvolutionConditions {
IF_PID_MODULO_100_LT, // The Pokémon's personality value's modulo by 100 is lower than the defined value.
IF_MIN_OVERWORLD_STEPS, // The Player has taken a specific amount of steps in the overworld with the Pokémon following them or in the first slot of the party.
IF_BAG_ITEM_COUNT, // The Player has the specific amount of an item in the bag. It then removes those items.
IF_REGION, // The Player is in the specific region.
IF_NOT_REGION, // The Player is NOT in the specific region.
CONDITIONS_END
};
@ -323,6 +325,7 @@ enum EvolutionMode {
EVO_MODE_ITEM_CHECK, // If an Everstone is being held, still want to show that the stone *could* be used on that Pokémon to evolve
EVO_MODE_BATTLE_SPECIAL,
EVO_MODE_OVERWORLD_SPECIAL,
EVO_MODE_SCRIPT_TRIGGER,
EVO_MODE_BATTLE_ONLY, // This mode is only used in battles to support Tandemaus' unique requirement
};

View File

@ -42,9 +42,9 @@ struct TrainerSprite
struct TrainerBacksprite
{
struct MonCoords coordinates;
struct CompressedSpriteSheet backPic;
struct SpritePalette palette;
const struct MonCoords coordinates;
const struct SpriteFrameImage backPic;
const struct SpritePalette palette;
const union AnimCmd *const *const animation;
};
@ -105,6 +105,8 @@ struct Trainer
/*0x22*/ u8 poolRuleIndex;
/*0x23*/ u8 poolPickIndex;
/*0x24*/ u8 poolPruneIndex;
/*0x25*/ u16 overrideTrainer;
/*0x26*/ u8 trainerBackPic;
};
struct TrainerClass

View File

@ -1,7 +1,7 @@
// #ifndef GUARD_FOLLOWER_NPC_H
// #define GUARD_FOLLOWER_NPC_H
#ifndef GUARD_FOLLOWER_NPC_H
#define GUARD_FOLLOWER_NPC_H
// #include "constants/follower_npc.h"
#include "constants/follower_npc.h"
// #define MOVEMENT_INVALID 0xFE
@ -126,4 +126,4 @@
// void Task_MoveNPCFollowerAfterForcedMovement(u8 taskId);
// void Task_HideNPCFollowerAfterMovementFinish(u8 taskId);
// #endif // GUARD_FOLLOWER_NPC_H
#endif // GUARD_FOLLOWER_NPC_H

View File

@ -27,6 +27,8 @@
#define ALIGNED(n) __attribute__((aligned(n)))
#define PACKED __attribute__((packed))
#define TRANSPARENT __attribute__ ((__transparent_union__))
#define ALWAYS_INLINE inline __attribute__((always_inline))
#define NONNULL __attribute__((__nonnull__))
#define SOUND_INFO_PTR (*(struct SoundInfo **)0x3007FF0)
#define INTR_CHECK (*(u16 *)0x3007FF8)

View File

@ -23,6 +23,27 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
[GEN_CONFIG_DEFIANT_STICKY_WEB] = B_DEFIANT_STICKY_WEB,
[GEN_CONFIG_ENCORE_TARGET] = B_ENCORE_TARGET,
[GEN_CONFIG_TIME_OF_DAY_HEALING_MOVES] = B_TIME_OF_DAY_HEALING_MOVES,
[GEN_PICKUP_WILD] = B_PICKUP_WILD,
[GEN_PROTEAN_LIBERO] = B_PROTEAN_LIBERO,
[GEN_INTREPID_SWORD] = B_INTREPID_SWORD,
[GEN_DAUNTLESS_SHIELD] = B_DAUNTLESS_SHIELD,
[GEN_ILLUMINATE_EFFECT] = B_ILLUMINATE_EFFECT,
[GEN_STEAL_WILD_ITEMS] = B_STEAL_WILD_ITEMS,
[GEN_SNOW_WARNING] = B_SNOW_WARNING,
[GEN_ALLY_SWITCH_FAIL_CHANCE] = B_ALLY_SWITCH_FAIL_CHANCE,
[GEN_DREAM_EATER_LIQUID_OOZE] = B_DREAM_EATER_LIQUID_OOZE,
[GEN_CONFIG_TRANSISTOR_BOOST] = B_TRANSISTOR_BOOST,
[GEN_CONFIG_RECALC_TURN_AFTER_ACTIONS] = B_RECALC_TURN_AFTER_ACTIONS,
[GEN_CONFIG_UPDATED_INTIMIDATE] = B_UPDATED_INTIMIDATE,
[GEN_CONFIG_DISGUISE_HP_LOSS] = B_DISGUISE_HP_LOSS,
[GEN_CONFIG_AFTER_YOU_TURN_ORDER] = B_AFTER_YOU_TURN_ORDER,
[GEN_CONFIG_HEALING_WISH_SWITCH] = B_HEALING_WISH_SWITCH,
[GEN_CONFIG_MEGA_EVO_TURN_ORDER] = B_MEGA_EVO_TURN_ORDER,
[GEN_CONFIG_SHEER_COLD_IMMUNITY] = B_SHEER_COLD_IMMUNITY,
[GEN_CONFIG_WEAK_ARMOR_SPEED] = B_WEAK_ARMOR_SPEED,
[GEN_CONFIG_PRANKSTER_DARK_TYPES] = B_PRANKSTER_DARK_TYPES,
[GEN_CONFIG_DESTINY_BOND_FAIL] = B_DESTINY_BOND_FAIL,
[GEN_CONFIG_POWDER_RAIN] = B_POWDER_RAIN,
};
#if TESTING

View File

@ -2,8 +2,87 @@
#define GUARD_ITEM_H
#include "constants/item.h"
#include "constants/item_effects.h"
#include "constants/items.h"
#include "constants/moves.h"
#include "constants/tms_hms.h"
#include "constants/item_effects.h"
#include "constants/hold_effects.h"
/* Expands to:
* enum
* {
* ITEM_TM_FOCUS_PUNCH = ITEM_TM01,
* ...
* ITEM_HM_CUT = ITM_HM01,
* ...
* }; */
#define ENUM_TM(n, id) CAT(ITEM_TM_, id) = CAT(ITEM_TM, n),
#define ENUM_HM(n, id) CAT(ITEM_HM_, id) = CAT(ITEM_HM, n),
#define TO_TMHM_NUMS(a, ...) (__VA_ARGS__)
enum TMHMItemId
{
RECURSIVELY(R_ZIP(ENUM_TM, TO_TMHM_NUMS NUMBERS_256, (FOREACH_TM(APPEND_COMMA))))
RECURSIVELY(R_ZIP(ENUM_HM, TO_TMHM_NUMS NUMBERS_256, (FOREACH_HM(APPEND_COMMA))))
};
#undef ENUM_TM
#undef ENUM_HM
#undef TO_TMHM_NUMS
/* Each of these TM_HM enums corresponds an index in the list of TMs + HMs item ids in
* gTMHMItemMoveIds. The index for an item can be retrieved with GetItemTMHMIndex below.
*/
#define UNPACK_TM_HM_ENUM(_tmHm) CAT(ENUM_TM_HM_, _tmHm),
enum TMHMIndex
{
FOREACH_TMHM(UNPACK_TM_HM_ENUM)
NUM_ALL_MACHINES,
NUM_TECHNICAL_MACHINES = (0 FOREACH_TM(PLUS_ONE)),
NUM_HIDDEN_MACHINES = (0 FOREACH_HM(PLUS_ONE)),
};
#undef UNPACK_TM_HM_ENUM
enum PACKED ItemSortType
{
ITEM_TYPE_UNCATEGORIZED,
ITEM_TYPE_FIELD_USE,
ITEM_TYPE_LEVEL_UP_ITEM,
ITEM_TYPE_HEALTH_RECOVERY,
ITEM_TYPE_STATUS_RECOVERY,
ITEM_TYPE_PP_RECOVERY,
ITEM_TYPE_NATURE_MINT,
ITEM_TYPE_STAT_BOOST_DRINK,
ITEM_TYPE_STAT_BOOST_FEATHER,
ITEM_TYPE_STAT_BOOST_MOCHI,
ITEM_TYPE_BATTLE_ITEM,
ITEM_TYPE_FLUTE,
ITEM_TYPE_X_ITEM,
ITEM_TYPE_AUX_ITEM,
ITEM_TYPE_EVOLUTION_STONE,
ITEM_TYPE_EVOLUTION_ITEM,
ITEM_TYPE_SPECIAL_HELD_ITEM,
ITEM_TYPE_MEGA_STONE,
ITEM_TYPE_Z_CRYSTAL,
ITEM_TYPE_TERA_SHARD,
ITEM_TYPE_HELD_ITEM,
ITEM_TYPE_TYPE_BOOST_HELD_ITEM,
ITEM_TYPE_CONTEST_HELD_ITEM,
ITEM_TYPE_EV_BOOST_HELD_ITEM,
ITEM_TYPE_GEM,
ITEM_TYPE_PLATE,
ITEM_TYPE_MEMORY,
ITEM_TYPE_DRIVE,
ITEM_TYPE_INCENSE,
ITEM_TYPE_NECTAR,
ITEM_TYPE_GROWTH,
ITEM_TYPE_SHARD,
ITEM_TYPE_SELLABLE,
ITEM_TYPE_RELIC,
ITEM_TYPE_FOSSIL,
ITEM_TYPE_MAIL,
};
typedef void (*ItemUseFunc)(u8);
@ -14,14 +93,14 @@ struct Item
ItemUseFunc fieldUseFunc;
const u8 *description;
const u8 *effect;
u8 name[ITEM_NAME_LENGTH];
u8 pluralName[ITEM_NAME_PLURAL_LENGTH];
const u8 *name;
const u8 *pluralName;
u8 holdEffect;
u8 holdEffectParam;
u8 importance:2;
u8 notConsumed:1;
u8 padding:5;
u8 pocket;
enum Pocket pocket:5;
enum ItemSortType sortType;
u8 type;
u8 battleUsage;
u8 flingPower;
@ -35,8 +114,69 @@ struct BagPocket
u8 capacity;
};
struct TmHmIndexKey
{
enum TMHMItemId itemId:16;
u16 moveId;
};
extern const struct Item gItemsInfo[];
extern struct BagPocket gBagPockets[];
extern const struct TmHmIndexKey gTMHMItemMoveIds[];
#define UNPACK_ITEM_TO_TM_INDEX(_tm) case CAT(ITEM_TM_, _tm): return CAT(ENUM_TM_HM_, _tm) + 1;
#define UNPACK_ITEM_TO_HM_INDEX(_hm) case CAT(ITEM_HM_, _hm): return CAT(ENUM_TM_HM_, _hm) + 1;
#define UNPACK_ITEM_TO_TM_MOVE_ID(_tm) case CAT(ITEM_TM_, _tm): return CAT(MOVE_, _tm);
#define UNPACK_ITEM_TO_HM_MOVE_ID(_hm) case CAT(ITEM_HM_, _hm): return CAT(MOVE_, _hm);
static inline enum TMHMIndex GetItemTMHMIndex(u16 item)
{
switch (item)
{
/* Expands to:
* case ITEM_TM_FOCUS_PUNCH:
* return 1;
* case ITEM_TM_DRAGON_CLAW:
* return 2;
* etc */
FOREACH_TM(UNPACK_ITEM_TO_TM_INDEX)
FOREACH_HM(UNPACK_ITEM_TO_HM_INDEX)
default:
return 0;
}
}
static inline u16 GetItemTMHMMoveId(u16 item)
{
switch (item)
{
/* Expands to:
* case ITEM_TM_FOCUS_PUNCH:
* return MOVE_FOCUS_PUNCH;
* case ITEM_TM_DRAGON_CLAW:
* return MOVE_DRAGON_CLAW;
* etc */
FOREACH_TM(UNPACK_ITEM_TO_TM_MOVE_ID)
FOREACH_HM(UNPACK_ITEM_TO_HM_MOVE_ID)
default:
return MOVE_NONE;
}
}
#undef UNPACK_ITEM_TO_TM_INDEX
#undef UNPACK_ITEM_TO_HM_INDEX
#undef UNPACK_ITEM_TO_TM_MOVE_ID
#undef UNPACK_ITEM_TO_HM_MOVE_ID
static inline enum TMHMItemId GetTMHMItemId(enum TMHMIndex index)
{
return gTMHMItemMoveIds[index].itemId;
}
static inline u16 GetTMHMMoveId(enum TMHMIndex index)
{
return gTMHMItemMoveIds[index].moveId;
}
u16 GetBagItemQuantity(enum Pocket pocketId, u32 pocketPos);
void GetBerryCountString(u8 *dst, const u8 *berryName, u32 quantity);
@ -94,28 +234,9 @@ bool8 IsItemBall(u16 itemId);
const u8 *GetItemEffect(u32 itemId);
u32 GetItemStatus1Mask(u16 itemId);
u32 GetItemStatus2Mask(u16 itemId);
bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile volatile);
u32 GetItemSellPrice(u32 itemId);
bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect);
/* Expands to:
* enum
* {
* ITEM_TM_FOCUS_PUNCH,
* ...
* ITEM_HM_CUT,
* ...
* }; */
#define ENUM_TM(id) CAT(ITEM_TM_, id),
#define ENUM_HM(id) CAT(ITEM_HM_, id),
enum
{
ENUM_TM_START_ = ITEM_TM01 - 1,
FOREACH_TM(ENUM_TM)
ENUM_HM_START_ = ITEM_HM01 - 1,
FOREACH_HM(ENUM_HM)
};
#undef ENUM_TM
#undef ENUM_HM
#endif // GUARD_ITEM_H

View File

@ -1,8 +1,6 @@
#ifndef GUARD_MATH_UTIL_H
#define GUARD_MATH_UTIL_H
// Fixed-point arithmetic library.
s16 MathUtil_Mul16(s16 x, s16 y);
s16 MathUtil_Mul16Shift(u8 s, s16 x, s16 y);
s32 MathUtil_Mul32(s32 x, s32 y);
@ -12,6 +10,7 @@ s32 MathUtil_Div32(s32 x, s32 y);
s16 MathUtil_Inv16(s16 y);
s16 MathUtil_Inv16Shift(u8 s, s16 y);
s32 MathUtil_Inv32(s32 y);
u32 MathUtil_Exponent(u32 x, u32 y);
// x * y
s16 Q_8_8_mul(s16 x, s16 y);
@ -28,4 +27,4 @@ s16 Q_8_8_inv(s16 y);
s16 Q_N_S_inv(u8 s, s16 y);
s32 Q_24_8_inv(s32 y);
#endif //GUARD_MATH_UTIL_H
#endif // GUARD_MATH_UTIL_H

View File

@ -26,11 +26,18 @@
#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) #__VA_ARGS__
/* You'll never guess what this one does */
/* You'll never guess what these do */
#define APPEND_SEMICOLON(a) a;
#define APPEND_COMMA(a) a,
/* Converts a string to a compound literal, essentially making it a pointer to const u8 */
#define COMPOUND_STRING(str) (const u8[]) _(str)
#define COMPOUND_STRING_SIZE_LIMIT(str, limit) (const u8[COMPOUND_STRING_CHECK_SIZE(str, limit)]) _(str)
/* Used for COMPOUND_STRING_SIZE_LIMIT. Stupid, but makes sure we only get
* one error message regardless of how many characters over the limit we are.
* Otherwise, GCC gives an error for each and every character (which is annoying). */
#define COMPOUND_STRING_CHECK_SIZE(str, limit) (sizeof(COMPOUND_STRING(str)) > limit ? sizeof(COMPOUND_STRING(str)) - 1 : sizeof(COMPOUND_STRING(str)))
/* Expands to the first/second/third/fourth argument. */
#define FIRST(a, ...) a
@ -44,26 +51,26 @@
#define EXCEPT_3(a, ...) __VA_OPT__(EXCEPT_2(__VA_ARGS__))
#define EXCEPT_4(a, ...) __VA_OPT__(EXCEPT_3(__VA_ARGS__))
/* 'UNPACK (x, y, z)' expands to 'x, y, z'.
/* 'UNPACK_META (x, y, z)' expands to 'x, y, z'.
* Useful for passing arguments which may contain commas into a macro. */
#define UNPACK(...) __VA_ARGS__
#define UNPACK_META(...) __VA_ARGS__
/* Updated version that can extract arguments from brackets as well.
/* Updated version that can extract arguments from brackets as well.
* Examples:
*
*
* UNPACK_B(a, b) => a, b
* UNPACK_B((a, b)) => a, b
* UNPACK_B((a)) => a
*
*
* The simple UNPACK is used for extracting non-bracketed arguments.
* */
#define UNPACK_EXTRA(...) IF_YOU_SEE_ME_SOMETHING_IS_WRONG, __VA_ARGS__
#define UNPACK_B(a) INVOKE(UNPACK_B_, a, UNPACK_EXTRA a)
#define UNPACK_B_(a, b, ...) __VA_OPT__(UNPACK)a
#define UNPACK_B(a) INVOKE_WITH_(UNPACK_B_, a, UNPACK_EXTRA a)
#define UNPACK_B_(a, b, ...) __VA_OPT__(UNPACK_META)a
/* Expands to 'macro(...args, ...)'. */
#define INVOKE_WITH(macro, args, ...) INVOKE(macro, UNPACK args __VA_OPT__(, __VA_ARGS__))
#define INVOKE(macro, ...) macro(__VA_ARGS__)
#define INVOKE_WITH(macro, args, ...) INVOKE_WITH_(macro, UNPACK_META args __VA_OPT__(, __VA_ARGS__))
#define INVOKE_WITH_(macro, ...) macro(__VA_ARGS__)
/* Same as INVOKE_WITH but uses UNPACK_B to unpack arguments and only applies macro to args if there are any. */
#define INVOKE_WITH_B(macro, args, ...) INVOKE_B(macro, UNPACK_B(args) __VA_OPT__(, __VA_ARGS__))
@ -98,48 +105,72 @@
#define R_FOR_EACH_WITH_(macro, args, a, ...) INVOKE_WITH(macro, args, a) __VA_OPT__(R_FOR_EACH_WITH_P PARENS (macro, args, __VA_ARGS__))
#define R_FOR_EACH_WITH_P() R_FOR_EACH_WITH_
/* Expands to 'macro(a, b)' for each 'a' in 'as' and 'b' in 'bs'.
* Uses the shorter of 'as' and 'bs'. (Credit to MGriffin) */
#define R_ZIP(macro, as, bs) CAT(R_ZIP_, CAT(R_ZIP_NONEMPTY(as), R_ZIP_NONEMPTY(bs)))(macro, FIRST as, FIRST bs, (EXCEPT_1 as), (EXCEPT_1 bs))
#define R_ZIP_00(macro, a, b, as, bs)
#define R_ZIP_01(macro, a, b, as, bs)
#define R_ZIP_10(macro, a, b, as, bs)
#define R_ZIP_11(macro, a, b, as, bs) macro(a, b) R_ZIP_P PARENS (macro, as, bs)
#define R_ZIP_P() R_ZIP
#define R_ZIP_NONEMPTY(as) R_ZIP_NONEMPTY_ as
#define R_ZIP_NONEMPTY_(...) FIRST(__VA_OPT__(1,) 0)
/* Just a lot of numbers (with leading zeroes - remove with REMOVE_LEADING_ZEROES) */
#define NUMBERS_256 (00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255)
/* Picks the xth VA_ARG if it exists, otherwise returns a default value */
#define DEFAULT(_default, ...) FIRST(__VA_OPT__(__VA_ARGS__, ) _default)
#define DEFAULT_2(_default, ...) DEFAULT(_default __VA_OPT__(, SECOND(__VA_ARGS__)))
#define DEFAULT_3(_default, ...) DEFAULT(_default __VA_OPT__(, THIRD(__VA_ARGS__)))
#define DEFAULT_4(_default, ...) DEFAULT(_default __VA_OPT__(, FOURTH(__VA_ARGS__)))
/* Simply a lists numbers 0-31, allows for word-spanning macros */
#define BITS_32(F, ...) \
F(0, __VA_ARGS__) \
F(1, __VA_ARGS__) \
F(2, __VA_ARGS__) \
F(3, __VA_ARGS__) \
F(4, __VA_ARGS__) \
F(5, __VA_ARGS__) \
F(6, __VA_ARGS__) \
F(7, __VA_ARGS__) \
F(8, __VA_ARGS__) \
F(9, __VA_ARGS__) \
F(10, __VA_ARGS__) \
F(11, __VA_ARGS__) \
F(12, __VA_ARGS__) \
F(13, __VA_ARGS__) \
F(14, __VA_ARGS__) \
F(15, __VA_ARGS__) \
F(16, __VA_ARGS__) \
F(17, __VA_ARGS__) \
F(18, __VA_ARGS__) \
F(19, __VA_ARGS__) \
F(20, __VA_ARGS__) \
F(21, __VA_ARGS__) \
F(22, __VA_ARGS__) \
F(23, __VA_ARGS__) \
F(24, __VA_ARGS__) \
F(25, __VA_ARGS__) \
F(26, __VA_ARGS__) \
F(27, __VA_ARGS__) \
F(28, __VA_ARGS__) \
F(29, __VA_ARGS__) \
F(30, __VA_ARGS__) \
F(31, __VA_ARGS__)
/* Compares _n to 1 shifted by _b by _operation (==, <, > etc) */
#define OP_BIT_SHIFT(_b, _n, _operation) (_n) _operation (1 << _b) ? _b :
/* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word.
Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */
#define BIT_INDEX(n) \
(n) == (1 << 0) ? 0 : \
(n) == (1 << 1) ? 1 : \
(n) == (1 << 2) ? 2 : \
(n) == (1 << 3) ? 3 : \
(n) == (1 << 4) ? 4 : \
(n) == (1 << 5) ? 5 : \
(n) == (1 << 6) ? 6 : \
(n) == (1 << 7) ? 7 : \
(n) == (1 << 8) ? 8 : \
(n) == (1 << 9) ? 9 : \
(n) == (1 << 10) ? 10 : \
(n) == (1 << 11) ? 11 : \
(n) == (1 << 12) ? 12 : \
(n) == (1 << 13) ? 13 : \
(n) == (1 << 14) ? 14 : \
(n) == (1 << 15) ? 15 : \
(n) == (1 << 16) ? 16 : \
(n) == (1 << 17) ? 17 : \
(n) == (1 << 18) ? 18 : \
(n) == (1 << 19) ? 19 : \
(n) == (1 << 20) ? 20 : \
(n) == (1 << 21) ? 21 : \
(n) == (1 << 22) ? 22 : \
(n) == (1 << 23) ? 23 : \
(n) == (1 << 24) ? 24 : \
(n) == (1 << 25) ? 25 : \
(n) == (1 << 26) ? 26 : \
(n) == (1 << 27) ? 27 : \
(n) == (1 << 28) ? 28 : \
(n) == (1 << 29) ? 29 : \
(n) == (1 << 30) ? 30 : \
(n) == (1 << 31) ? 31 : \
*(u32 *)NULL
#define BIT_INDEX(_n) BITS_32(OP_BIT_SHIFT, _n, ==) *(u32 *)NULL
/* (Credit to MGriffin) A way to find the minimum required number of bits to
store a number (max: 32). Sample: https://godbolt.org/z/xb4KdPMhT */
#define BIT_SIZE(_n) (BITS_32(OP_BIT_SHIFT, _n, <) 32)
#define COMPRESS_BITS_0 0, 1
#define COMPRESS_BITS_1 1, 1
@ -151,11 +182,10 @@ Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1
#define COMPRESS_BITS_7 7, 1
/* Will try and compress a set bit (or up to three sequential bits) into a single byte
Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */
Input must be of the form (upper << lower) where upper can be up to 7, lower up to 31 */
#define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val
#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked)
#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__)
#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower)))
#define COMPRESS_BITS_STEP_2(_unpacked) INVOKE_WITH_(COMPRESS_BITS_STEP_3, COMPRESS_BITS_## _unpacked)
#define COMPRESS_BITS_STEP_3(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower)))
/* Will read a compressed bit stored by COMPRESS_BIT into a single byte */
#define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F))
@ -171,4 +201,10 @@ Input must be of the form (upper << lower) where upper can be up to 3, lower up
/* Finds the required digits to display the number (maximum 4) */
#define MAX_DIGITS(_num) 1 + !!(_num / 10) + !!(_num / 100) + !!(_num / 1000)
/* Converts a number with leading zeroes to a normal int (base 10 and up to three digits only!) */
#define REMOVE_LEADING_ZEROES(_num) (((0x##_num / 256) * 100) + ((0x##_num / 16) * 10) + (0x##_num % 16))
/* Useful for counting arguments */
#define PLUS_ONE(...) + 1
#endif

View File

@ -4,6 +4,7 @@
#include "contest_effect.h"
#include "constants/battle.h"
#include "constants/battle_move_effects.h"
#include "constants/battle_string_ids.h"
#include "constants/moves.h"
// For defining EFFECT_HIT etc. with battle TV scores and flags etc.
@ -21,21 +22,17 @@ struct __attribute__((packed, aligned(2))) BattleMoveEffect
#define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__}
#define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ ))
enum SheerForceBoost
{
SHEER_FORCE_AUTO_BOOST, // This is the default state when a move has a move effect with a chance
SHEER_FORCE_BOOST, // If a move effect doesn't have an effect with a chance this can force a boost
SHEER_FORCE_NO_BOOST, // Prevents a Sheer Force boost
};
struct AdditionalEffect
{
u16 moveEffect;
enum MoveEffect moveEffect;
u8 self:1;
u8 onlyIfTargetRaisedStats:1;
u8 onChargeTurnOnly:1;
u8 sheerForceBoost:2; // Handles edge cases for Sheer Force
u8 padding:3;
u8 sheerForceOverride:1; // Handles edge cases for Sheer Force - if TRUE, boosts when it shouldn't, or doesn't boost when it should
u8 padding:4;
union PACKED {
enum WrappedStringID wrapped;
} multistring;
u8 chance; // 0% = effect certain, primary effect
};
@ -67,7 +64,7 @@ struct MoveInfo
{
const u8 *name;
const u8 *description;
u16 effect;
enum BattleMoveEffects effect;
u16 type:5; // Up to 32
enum DamageCategory category:2;
u16 power:9; // up to 511
@ -492,7 +489,7 @@ static inline u32 GetMoveTwoTurnAttackStringId(u32 moveId)
static inline u32 GetMoveTwoTurnAttackStatus(u32 moveId)
{
return UNCOMPRESS_BITS(gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.status);
return gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.status;
}
static inline u32 GetMoveTwoTurnAttackWeather(u32 moveId)
@ -505,6 +502,11 @@ static inline enum ProtectMethod GetMoveProtectMethod(u32 moveId)
return gMovesInfo[SanitizeMoveId(moveId)].argument.protectMethod;
}
static inline u32 GetMoveTerrainFlag(u32 moveId)
{
return gMovesInfo[SanitizeMoveId(moveId)].argument.moveProperty;
}
static inline u32 GetMoveEffectArg_Status(u32 moveId)
{
return gMovesInfo[SanitizeMoveId(moveId)].argument.status;

View File

@ -10,13 +10,17 @@
#include "constants/map_groups.h"
#include "constants/regions.h"
#include "constants/region_map_sections.h"
#include "constants/map_groups.h"
#include "constants/battle.h"
#include "constants/abilities.h"
#include "contest_effect.h"
#include "constants/trainers.h"
#define GET_BASE_SPECIES_ID(speciesId) (GetFormSpeciesId(speciesId, 0))
#define FORM_SPECIES_END (0xffff)
// Property labels for Get(Box)MonData / Set(Box)MonData
enum {
enum MonData {
MON_DATA_PERSONALITY,
MON_DATA_STATUS,
MON_DATA_OT_ID,
@ -232,6 +236,14 @@ struct PokemonSubstruct3
max(sizeof(struct PokemonSubstruct2), \
sizeof(struct PokemonSubstruct3)))))
enum SubstructType
{
SUBSTRUCT_TYPE_0,
SUBSTRUCT_TYPE_1,
SUBSTRUCT_TYPE_2,
SUBSTRUCT_TYPE_3,
};
union PokemonSubstruct
{
struct PokemonSubstruct0 type0;
@ -337,8 +349,8 @@ struct BattleTowerPokemon
/*0x2B*/ u8 friendship;
};
#define UNPACK_VOLATILE_STRUCT(_enum, _fieldName, _typeBitSize, ...) INVOKE(UNPACK_VOLATILE_STRUCT_, _fieldName, UNPACK_B(_typeBitSize));
#define UNPACK_VOLATILE_STRUCT_(_fieldName, _type, ...) _type FIRST(__VA_OPT__(_fieldName:FIRST(__VA_ARGS__),) _fieldName)
#define UNPACK_VOLATILE_STRUCT(_enum, _fieldName, _typeMaxValue, ...) INVOKE_WITH_(UNPACK_VOLATILE_STRUCT_, _fieldName, UNPACK_B(_typeMaxValue));
#define UNPACK_VOLATILE_STRUCT_(_fieldName, _type, ...) _type FIRST(__VA_OPT__(_fieldName:BIT_SIZE(FIRST(__VA_ARGS__)),) _fieldName)
struct Volatiles
{
@ -386,7 +398,7 @@ struct BattlePokemon
/*0x17*/ u32 spDefenseIV:5;
/*0x17*/ u32 abilityNum:2;
/*0x18*/ s8 statStages[NUM_BATTLE_STATS];
/*0x20*/ u16 ability;
/*0x20*/ enum Ability ability;
/*0x22*/ u8 types[3];
/*0x25*/ u8 pp[MAX_MON_MOVES];
/*0x29*/ u16 hp;
@ -400,12 +412,7 @@ struct BattlePokemon
/*0x45*/ u32 experience;
/*0x49*/ u32 personality;
/*0x4D*/ u32 status1;
/*0x51*/ union {
struct {
u32 status2; // To be expanded to include Status3/4
};
struct Volatiles volatiles;
};
/*0x51*/ struct Volatiles volatiles;
/*0x5D*/ u32 otId;
/*0x61*/ u8 metLevel;
/*0x62*/ bool8 isShiny;
@ -453,7 +460,7 @@ struct SpeciesInfo /*0xC4*/
u8 friendship;
u8 growthRate;
u8 eggGroups[2];
u16 abilities[NUM_ABILITY_SLOTS]; // 3 abilities, no longer u8 because we have over 255 abilities now.
enum Ability abilities[NUM_ABILITY_SLOTS]; // 3 abilities, no longer u8 because we have over 255 abilities now.
u8 safariZoneFleeRate;
// Pokédex data
@ -557,7 +564,7 @@ struct SpeciesInfo /*0xC4*/
#endif //OW_POKEMON_OBJECT_EVENTS
};
struct Ability
struct AbilityInfo
{
u8 name[ABILITY_NAME_LENGTH + 1];
const u8 *description;
@ -700,7 +707,7 @@ extern const u8 gStatStageRatios[MAX_STAT_STAGE + 1][2];
extern const u16 gUnionRoomFacilityClasses[];
extern const struct SpriteTemplate gBattlerSpriteTemplates[];
extern const u32 sExpCandyExperienceTable[];
extern const struct Ability gAbilitiesInfo[];
extern const struct AbilityInfo gAbilitiesInfo[];
extern const struct NatureInfo gNaturesInfo[];
#if P_TUTOR_MOVES_ARRAY
extern const u16 gTutorMoves[];
@ -775,8 +782,8 @@ u8 CalculateEnemyPartyCount(void);
u8 CalculateEnemyPartyCountInSide(u32 battler);
u8 GetMonsStateToDoubles(void);
u8 GetMonsStateToDoubles_2(void);
u16 GetAbilityBySpecies(u16 species, u8 abilityNum);
u16 GetMonAbility(struct Pokemon *mon);
enum Ability GetAbilityBySpecies(u16 species, u8 abilityNum);
enum Ability GetMonAbility(struct Pokemon *mon);
// void CreateSecretBaseEnemyParty(struct SecretBase *secretBaseRecord);
u8 GetSecretBaseTrainerPicIndex(void);
enum TrainerClassID GetSecretBaseTrainerClass(void);
@ -788,7 +795,7 @@ const u8 *GetSpeciesPokedexDescription(u16 species);
u32 GetSpeciesHeight(u16 species);
u32 GetSpeciesWeight(u16 species);
u32 GetSpeciesType(u16 species, u8 slot);
u32 GetSpeciesAbility(u16 species, u8 slot);
enum Ability GetSpeciesAbility(u16 species, u8 slot);
u32 GetSpeciesBaseHP(u16 species);
u32 GetSpeciesBaseAttack(u16 species);
u32 GetSpeciesBaseDefense(u16 species);
@ -858,7 +865,8 @@ void CreateTask_PlayMapChosenOrBattleBGM(u16 songId);
const u16 *GetMonFrontSpritePal(struct Pokemon *mon);
const u16 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, bool32 isShiny, u32 personality);
const u16 *GetMonSpritePalFromSpecies(u16 species, bool32 isShiny, bool32 isFemale);
bool8 IsMoveHM(u16 move);
bool32 IsMoveHM(u16 move);
bool32 CannotForgetMove(u16 move);
bool8 IsMonSpriteNotFlipped(u16 species);
s8 GetMonFlavorRelation(struct Pokemon *mon, u8 flavor);
s8 GetFlavorRelationByPersonality(u32 personality, u8 flavor);
@ -911,9 +919,11 @@ uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier)
u32 GetRegionalFormByRegion(u32 species, u32 region);
bool32 IsSpeciesForeignRegionalForm(u32 species, u32 currentRegion);
u32 GetTeraTypeFromPersonality(struct Pokemon *mon);
bool8 ShouldSkipFriendshipChange(void);
struct Pokemon *GetSavedPlayerPartyMon(u32 index);
u8 *GetSavedPlayerPartyCount(void);
void SavePlayerPartyMon(u32 index, struct Pokemon *mon);
u32 IsSpeciesOfType(u32 species, u32 type);
// pokefirered
u16 GetFirstPartnerMove(u16 species);

View File

@ -193,7 +193,9 @@ enum RandomTag
RNG_AI_SWITCH_ALL_MOVES_BAD,
RNG_AI_CONSERVE_TERA,
RNG_AI_SWITCH_ALL_SCORES_BAD,
RNG_AI_SWITCH_ABSORBING_HIDDEN_POWER,
RNG_AI_PP_STALL_DISREGARD_MOVE,
RNG_AI_SUCKER_PUNCH,
RNG_SHELL_SIDE_ARM,
RNG_RANDOM_TARGET,
RNG_AI_PREDICT_ABILITY,
@ -201,8 +203,23 @@ enum RandomTag
RNG_AI_PREDICT_MOVE,
RNG_AI_STATUS_FOCUS_PUNCH,
RNG_AI_BOOST_INTO_HAZE,
RNG_AI_SHOULD_RECOVER,
RNG_AI_PRIORITIZE_LAST_CHANCE,
RNG_HEALER,
RNG_DEXNAV_ENCOUNTER_LEVEL,
RNG_AI_ASSUME_STATUS_SLEEP,
RNG_AI_ASSUME_STATUS_NONVOLATILE,
RNG_AI_ASSUME_STATUS_HIGH_ODDS,
RNG_AI_ASSUME_STATUS_MEDIUM_ODDS,
RNG_AI_ASSUME_STATUS_LOW_ODDS,
RNG_AI_ASSUME_ALL_STATUS,
RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN,
RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM,
RNG_WRAP,
RNG_BALLTHROW_CRITICAL,
RNG_BALLTHROW_SHAKE,
RNG_PRESENT,
RNG_MAGNITUDE,
};
#define RandomWeighted(tag, ...) \

View File

@ -329,5 +329,6 @@ void ResetAffineAnimData(void);
u32 GetSpanPerImage(u32 shape, u32 size);
void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images);
void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip);
u8 IndexOfSpriteTileTag(u16 tag);
#endif //GUARD_SPRITE_H

View File

@ -332,6 +332,7 @@ extern const u8 gText_EscapeFromHereAndReturnTo[];
extern const u8 gText_PkmnCuredOfPoison[];
extern const u8 gText_PkmnWokeUp2[];
extern const u8 gText_PkmnBurnHealed[];
extern const u8 gText_PkmnFrostbiteHealed[];
extern const u8 gText_PkmnThawedOut[];
extern const u8 gText_PkmnCuredOfParalysis[];
extern const u8 gText_PkmnSnappedOutOfConfusion[];

View File

@ -16,5 +16,7 @@ u16 FreeAndDestroyMonPicSpriteNoPalette(u16 spriteId);
u16 FreeAndDestroyTrainerPicSprite(u16);
u16 LoadMonPicInWindow(u16 species, bool32 isShiny, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId);
u16 CreateMonPicSprite(u16 species, bool32 isShiny, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag);
u16 PlayerGenderToFrontTrainerPicId_Debug(u8 gender, bool8 getClass);
void CopyTrainerBackspriteFramesToDest(u8 trainerPicId, u8 *dest);
#endif // GUARD_TRAINER_POKEMON_SPRITES_H

View File

@ -56,10 +56,12 @@ enum PoolTags {
struct PoolRules
{
bool8 speciesClause;
bool8 excludeForms;
bool8 itemClause;
bool8 itemClauseExclusions;
u8 speciesClause:1;
u8 excludeForms:1;
u8 itemClause:1;
u8 itemClauseExclusions:1;
u8 megaStoneClause:1;
u8 zCrystalClause:1;
u8 tagMaxMembers[POOL_NUM_TAGS];
bool8 tagRequired[POOL_NUM_TAGS];
};

View File

@ -0,0 +1,498 @@
#include "global.h"
#include "battle_z_move.h"
#include "malloc.h"
#include "battle.h"
#include "battle_anim.h"
#include "battle_ai_field_statuses.h"
#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"
#include "item.h"
#include "move.h"
#include "pokemon.h"
#include "random.h"
#include "recorded_battle.h"
#include "util.h"
#include "constants/abilities.h"
#include "constants/battle_ai.h"
#include "constants/battle_move_effects.h"
#include "constants/hold_effects.h"
#include "constants/moves.h"
#include "constants/items.h"
static bool32 DoesAbilityBenefitFromWeather(enum Ability ability, u32 weather);
static bool32 DoesAbilityBenefitFromFieldStatus(enum Ability ability, u32 fieldStatus);
// A move is light sensitive if it is boosted by Sunny Day and weakened by low light weathers.
static bool32 IsLightSensitiveMove(u32 move);
static bool32 HasLightSensitiveMove(u32 battler);
// The following functions all feed into WeatherChecker, which is then called by ShouldSetWeather and ShouldClearWeather.
// BenefitsFrom functions all return FIELD_EFFECT_POSITIVE if the weather or field effect is good to have in place from the perspective of the battler, FIELD_EFFECT_NEUTRAL if it is neither good nor bad, and FIELD_EFFECT_NEGATIVE if it is bad.
// The purpose of WeatherChecker and FieldStatusChecker is to cleanly homogenize the logic that's the same with all of them, and to more easily apply single battle logic to double battles.
// ShouldSetWeather and ShouldClearWeather are looking for a positive or negative result respectively, and check the entire side.
// If one pokemon has a positive result and the other has a negative result, it defaults to the opinion of the battler that may change the weather or field status.
static enum FieldEffectOutcome BenefitsFromSun(u32 battler);
static enum FieldEffectOutcome BenefitsFromSandstorm(u32 battler);
static enum FieldEffectOutcome BenefitsFromHailOrSnow(u32 battler, u32 weather);
static enum FieldEffectOutcome BenefitsFromRain(u32 battler);
// The following functions all feed into FieldStatusChecker, which is then called by ShouldSetFieldStatus and ShouldClearFieldStatus.
// They work approximately the same as the weather functions.
static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler);
static enum FieldEffectOutcome BenefitsFromGrassyTerrain(u32 battler);
static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler);
static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler);
static enum FieldEffectOutcome BenefitsFromGravity(u32 battler);
static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler);
bool32 WeatherChecker(u32 battler, u32 weather, enum FieldEffectOutcome desiredResult)
{
if (IsWeatherActive(B_WEATHER_PRIMAL_ANY) != WEATHER_INACTIVE)
return (FIELD_EFFECT_BLOCKED == desiredResult);
enum FieldEffectOutcome result = FIELD_EFFECT_NEUTRAL;
enum FieldEffectOutcome firstResult = FIELD_EFFECT_NEUTRAL;
u32 i;
u32 battlersOnSide = 1;
if (HasPartner(battler))
battlersOnSide = 2;
for (i = 0; i < battlersOnSide; i++)
{
if (weather & B_WEATHER_RAIN)
result = BenefitsFromRain(battler);
else if (weather & B_WEATHER_SUN)
result = BenefitsFromSun(battler);
else if (weather & B_WEATHER_SANDSTORM)
result = BenefitsFromSandstorm(battler);
else if (weather & B_WEATHER_ICY_ANY)
result = BenefitsFromHailOrSnow(battler, weather);
battler = BATTLE_PARTNER(battler);
if (result != FIELD_EFFECT_NEUTRAL)
{
if (weather & B_WEATHER_DAMAGING_ANY && i == 0 && battlersOnSide == 2)
firstResult = result;
}
}
if (firstResult != FIELD_EFFECT_NEUTRAL)
return (firstResult == result) && (result == desiredResult);
return (result == desiredResult);
}
bool32 FieldStatusChecker(u32 battler, u32 fieldStatus, enum FieldEffectOutcome desiredResult)
{
enum FieldEffectOutcome result = FIELD_EFFECT_NEUTRAL;
enum FieldEffectOutcome firstResult = FIELD_EFFECT_NEUTRAL;
u32 i;
u32 battlersOnSide = 1;
if (HasPartner(battler))
battlersOnSide = 2;
for (i = 0; i < battlersOnSide; i++)
{
// terrains
if (fieldStatus & STATUS_FIELD_ELECTRIC_TERRAIN)
result = BenefitsFromElectricTerrain(battler);
if (fieldStatus & STATUS_FIELD_GRASSY_TERRAIN)
result = BenefitsFromGrassyTerrain(battler);
if (fieldStatus & STATUS_FIELD_MISTY_TERRAIN)
result = BenefitsFromMistyTerrain(battler);
if (fieldStatus & STATUS_FIELD_PSYCHIC_TERRAIN)
result = BenefitsFromPsychicTerrain(battler);
// other field statuses
if (fieldStatus & STATUS_FIELD_GRAVITY)
result = BenefitsFromGravity(battler);
if (fieldStatus & STATUS_FIELD_TRICK_ROOM)
result = BenefitsFromTrickRoom(battler);
battler = BATTLE_PARTNER(battler);
if (result != FIELD_EFFECT_NEUTRAL)
{
// Trick room wants both pokemon to agree, not just one
if (fieldStatus & STATUS_FIELD_TRICK_ROOM && i == 0 && battlersOnSide == 2)
firstResult = result;
}
}
if (firstResult != FIELD_EFFECT_NEUTRAL)
return (firstResult == result) && (result == desiredResult);
return (result == desiredResult);
}
static bool32 DoesAbilityBenefitFromWeather(enum Ability ability, u32 weather)
{
switch (ability)
{
case ABILITY_FORECAST:
return (weather & (B_WEATHER_RAIN | B_WEATHER_SUN | B_WEATHER_ICY_ANY));
case ABILITY_MAGIC_GUARD:
case ABILITY_OVERCOAT:
return (weather & B_WEATHER_DAMAGING_ANY);
case ABILITY_SAND_FORCE:
case ABILITY_SAND_RUSH:
case ABILITY_SAND_VEIL:
return (weather & B_WEATHER_SANDSTORM);
case ABILITY_ICE_BODY:
case ABILITY_ICE_FACE:
case ABILITY_SNOW_CLOAK:
return (weather & B_WEATHER_ICY_ANY);
case ABILITY_SLUSH_RUSH:
return (weather & B_WEATHER_SNOW);
case ABILITY_DRY_SKIN:
case ABILITY_HYDRATION:
case ABILITY_RAIN_DISH:
case ABILITY_SWIFT_SWIM:
return (weather & B_WEATHER_RAIN);
case ABILITY_CHLOROPHYLL:
case ABILITY_FLOWER_GIFT:
case ABILITY_HARVEST:
case ABILITY_LEAF_GUARD:
case ABILITY_ORICHALCUM_PULSE:
case ABILITY_PROTOSYNTHESIS:
case ABILITY_SOLAR_POWER:
return (weather & B_WEATHER_SUN);
default:
break;
}
return FALSE;
}
static bool32 DoesAbilityBenefitFromFieldStatus(enum Ability ability, u32 fieldStatus)
{
switch (ability)
{
case ABILITY_MIMICRY:
return (fieldStatus & STATUS_FIELD_TERRAIN_ANY);
case ABILITY_HADRON_ENGINE:
case ABILITY_QUARK_DRIVE:
case ABILITY_SURGE_SURFER:
return (fieldStatus & STATUS_FIELD_ELECTRIC_TERRAIN);
case ABILITY_GRASS_PELT:
return (fieldStatus & STATUS_FIELD_GRASSY_TERRAIN);
// no abilities inherently benefit from Misty or Psychic Terrains
// return (fieldStatus & STATUS_FIELD_MISTY_TERRAIN);
// return (fieldStatus & STATUS_FIELD_PSYCHIC_TERRAIN);
default:
break;
}
return FALSE;
}
static bool32 IsLightSensitiveMove(u32 move)
{
switch (GetMoveEffect(move))
{
case EFFECT_SOLAR_BEAM:
case EFFECT_MORNING_SUN:
case EFFECT_SYNTHESIS:
case EFFECT_MOONLIGHT:
case EFFECT_GROWTH:
return TRUE;
default:
return FALSE;
}
}
static bool32 HasLightSensitiveMove(u32 battler)
{
s32 i;
u16 *moves = GetMovesArray(battler);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && IsLightSensitiveMove(moves[i]))
return TRUE;
}
return FALSE;
}
// Sun
// Utility Umbrella does NOT block Ancient Pokemon from their stat boosts.
static enum FieldEffectOutcome BenefitsFromSun(u32 battler)
{
enum Ability ability = gAiLogicData->abilities[battler];
if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_UTILITY_UMBRELLA)
{
if (ability == ABILITY_ORICHALCUM_PULSE || ability == ABILITY_PROTOSYNTHESIS)
return FIELD_EFFECT_POSITIVE;
else
return FIELD_EFFECT_NEUTRAL;
}
if (DoesAbilityBenefitFromWeather(ability, B_WEATHER_SUN)
|| HasLightSensitiveMove(battler)
|| HasDamagingMoveOfType(battler, TYPE_FIRE)
|| HasMoveWithEffect(battler, EFFECT_HYDRO_STEAM))
return FIELD_EFFECT_POSITIVE;
if (HasMoveWithFlag(battler, MoveHas50AccuracyInSun) || HasDamagingMoveOfType(battler, TYPE_WATER) || gAiLogicData->abilities[battler] == ABILITY_DRY_SKIN)
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_NEUTRAL;
}
// Sandstorm
static enum FieldEffectOutcome BenefitsFromSandstorm(u32 battler)
{
if (DoesAbilityBenefitFromWeather(gAiLogicData->abilities[battler], B_WEATHER_SANDSTORM)
|| IS_BATTLER_OF_TYPE(battler, TYPE_ROCK))
return FIELD_EFFECT_POSITIVE;
if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_SAFETY_GOGGLES || IS_BATTLER_ANY_TYPE(battler, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL))
{
if (!(IS_BATTLER_ANY_TYPE(LEFT_FOE(battler), TYPE_ROCK, TYPE_GROUND, TYPE_STEEL))
|| gAiLogicData->holdEffects[LEFT_FOE(battler)] == HOLD_EFFECT_SAFETY_GOGGLES
|| DoesAbilityBenefitFromWeather(gAiLogicData->abilities[LEFT_FOE(battler)], B_WEATHER_SANDSTORM))
return FIELD_EFFECT_POSITIVE;
else
return FIELD_EFFECT_NEUTRAL;
}
return FIELD_EFFECT_NEGATIVE;
}
// Hail or Snow
static enum FieldEffectOutcome BenefitsFromHailOrSnow(u32 battler, u32 weather)
{
if (DoesAbilityBenefitFromWeather(gAiLogicData->abilities[battler], weather)
|| IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
|| HasMoveWithFlag(battler, MoveAlwaysHitsInHailSnow)
|| HasBattlerSideMoveWithEffect(battler, EFFECT_AURORA_VEIL))
return FIELD_EFFECT_POSITIVE;
if ((weather & B_WEATHER_DAMAGING_ANY) && gAiLogicData->holdEffects[battler] != HOLD_EFFECT_SAFETY_GOGGLES)
return FIELD_EFFECT_NEGATIVE;
if (HasLightSensitiveMove(battler))
return FIELD_EFFECT_NEGATIVE;
if (HasMoveWithFlag(LEFT_FOE(battler), MoveAlwaysHitsInHailSnow))
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_NEUTRAL;
}
// Rain
static enum FieldEffectOutcome BenefitsFromRain(u32 battler)
{
if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_UTILITY_UMBRELLA)
return FIELD_EFFECT_NEUTRAL;
if (DoesAbilityBenefitFromWeather(gAiLogicData->abilities[battler], B_WEATHER_RAIN)
|| HasMoveWithFlag(battler, MoveAlwaysHitsInRain)
|| HasDamagingMoveOfType(battler, TYPE_WATER))
return FIELD_EFFECT_POSITIVE;
if (HasLightSensitiveMove(battler) || HasDamagingMoveOfType(battler, TYPE_FIRE))
return FIELD_EFFECT_NEGATIVE;
if (HasMoveWithFlag(LEFT_FOE(battler), MoveAlwaysHitsInRain))
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_NEUTRAL;
}
//TODO: when is electric terrain bad?
static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler)
{
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_ELECTRIC_TERRAIN))
return FIELD_EFFECT_POSITIVE;
if (HasMoveWithEffect(battler, EFFECT_RISING_VOLTAGE))
return FIELD_EFFECT_POSITIVE;
if ((HasMoveWithEffect(LEFT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(LEFT_FOE(battler)))
|| (HasMoveWithEffect(RIGHT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(RIGHT_FOE(battler))))
return FIELD_EFFECT_POSITIVE;
bool32 grounded = AI_IsBattlerGrounded(battler);
if (grounded && HasBattlerSideMoveWithAdditionalEffect(LEFT_FOE(battler), MOVE_EFFECT_SLEEP))
return FIELD_EFFECT_POSITIVE;
if (grounded && ((gBattleMons[battler].status1 & STATUS1_SLEEP)
|| gBattleMons[battler].volatiles.yawn
|| HasDamagingMoveOfType(battler, TYPE_ELECTRIC)))
return FIELD_EFFECT_POSITIVE;
if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_RISING_VOLTAGE))
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_NEUTRAL;
}
//TODO: when is grassy terrain bad?
static enum FieldEffectOutcome BenefitsFromGrassyTerrain(u32 battler)
{
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_GRASSY_TERRAIN))
return FIELD_EFFECT_POSITIVE;
if (HasBattlerSideMoveWithEffect(battler, EFFECT_GRASSY_GLIDE))
return FIELD_EFFECT_POSITIVE;
if (HasMoveWithAdditionalEffect(battler, MOVE_EFFECT_FLORAL_HEALING))
return FIELD_EFFECT_POSITIVE;
bool32 grounded = AI_IsBattlerGrounded(battler);
// Weaken spamming Earthquake, Magnitude, and Bulldoze.
if (grounded && (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EARTHQUAKE)
|| HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_MAGNITUDE)))
return FIELD_EFFECT_POSITIVE;
if (grounded && HasDamagingMoveOfType(battler, TYPE_GRASS))
return FIELD_EFFECT_POSITIVE;
if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_GRASSY_GLIDE))
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_NEUTRAL;
}
//TODO: when is misty terrain bad?
static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler)
{
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_MISTY_TERRAIN))
return FIELD_EFFECT_POSITIVE;
if (HasBattlerSideMoveWithEffect(battler, EFFECT_MISTY_EXPLOSION))
return FIELD_EFFECT_POSITIVE;
bool32 grounded = AI_IsBattlerGrounded(battler);
bool32 allyGrounded = FALSE;
if (HasPartner(battler))
allyGrounded = AI_IsBattlerGrounded(BATTLE_PARTNER(battler));
if ((HasMoveWithEffect(LEFT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(LEFT_FOE(battler)))
|| (HasMoveWithEffect(RIGHT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(RIGHT_FOE(battler))))
return FIELD_EFFECT_POSITIVE;
// harass dragons
if ((grounded || allyGrounded)
&& (HasDamagingMoveOfType(LEFT_FOE(battler), TYPE_DRAGON) || HasDamagingMoveOfType(RIGHT_FOE(battler), TYPE_DRAGON)))
return FIELD_EFFECT_POSITIVE;
if ((grounded || allyGrounded)
&& (HasNonVolatileMoveEffect(LEFT_FOE(battler), MOVE_EFFECT_SLEEP) || HasNonVolatileMoveEffect(RIGHT_FOE(battler), MOVE_EFFECT_SLEEP)))
return FIELD_EFFECT_POSITIVE;
if (grounded && (gBattleMons[battler].status1 & STATUS1_SLEEP || gBattleMons[battler].volatiles.yawn))
return FIELD_EFFECT_POSITIVE;
return FIELD_EFFECT_NEUTRAL;
}
//TODO: when is Psychic Terrain negative?
static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler)
{
if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_PSYCHIC_TERRAIN))
return FIELD_EFFECT_POSITIVE;
if (HasMoveWithEffect(battler, EFFECT_EXPANDING_FORCE))
return FIELD_EFFECT_POSITIVE;
bool32 grounded = AI_IsBattlerGrounded(battler);
bool32 allyGrounded = FALSE;
if (HasPartner(battler))
allyGrounded = AI_IsBattlerGrounded(BATTLE_PARTNER(battler));
// don't bother if we're not grounded
if (grounded || allyGrounded)
{
// harass priority
if (HasBattlerSideAbility(LEFT_FOE(battler), ABILITY_GALE_WINGS, gAiLogicData)
|| HasBattlerSideAbility(LEFT_FOE(battler), ABILITY_TRIAGE, gAiLogicData)
|| HasBattlerSideAbility(LEFT_FOE(battler), ABILITY_PRANKSTER, gAiLogicData))
return FIELD_EFFECT_POSITIVE;
}
if (grounded && HasDamagingMoveOfType(battler, TYPE_PSYCHIC))
return FIELD_EFFECT_POSITIVE;
if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EXPANDING_FORCE))
return FIELD_EFFECT_NEGATIVE;
if (HasBattlerSideAbility(battler, ABILITY_GALE_WINGS, gAiLogicData)
|| HasBattlerSideAbility(battler, ABILITY_TRIAGE, gAiLogicData)
|| HasBattlerSideAbility(battler, ABILITY_PRANKSTER, gAiLogicData))
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_NEUTRAL;
}
static enum FieldEffectOutcome BenefitsFromGravity(u32 battler)
{
if (!AI_IsBattlerGrounded(battler))
return FIELD_EFFECT_NEGATIVE;
if (HasBattlerSideAbility(battler, ABILITY_HUSTLE, gAiLogicData))
return FIELD_EFFECT_POSITIVE;
if (HasMoveWithFlag(battler, IsMoveGravityBanned))
return FIELD_EFFECT_NEGATIVE;
if (IsBattlerAlive(LEFT_FOE(battler)))
{
if (HasMoveWithLowAccuracy(battler, LEFT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE)
|| (!AI_IsBattlerGrounded(LEFT_FOE(battler)) && HasDamagingMoveOfType(battler, TYPE_GROUND)))
return FIELD_EFFECT_POSITIVE;
}
if (IsBattlerAlive(RIGHT_FOE(battler)))
{
if (HasMoveWithLowAccuracy(battler, RIGHT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE)
|| (!AI_IsBattlerGrounded(RIGHT_FOE(battler)) && HasDamagingMoveOfType(battler, TYPE_GROUND)))
return FIELD_EFFECT_POSITIVE;
}
return FIELD_EFFECT_NEUTRAL;
}
static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler)
{
// If we're in singles, we literally only care about speed.
if (IsBattle1v1())
{
if (gAiLogicData->speedStats[battler] < gAiLogicData->speedStats[LEFT_FOE(battler)])
return FIELD_EFFECT_POSITIVE;
// If we tie, we shouldn't change trick room state.
else if (gAiLogicData->speedStats[battler] == gAiLogicData->speedStats[LEFT_FOE(battler)])
return FIELD_EFFECT_NEUTRAL;
else
return FIELD_EFFECT_NEGATIVE;
}
// First checking if we have enough priority for one pokemon to disregard Trick Room entirely.
if (!(gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN))
{
u16* aiMoves = GetMovesArray(battler);
for (int i = 0; i < MAX_MON_MOVES; i++)
{
u16 move = aiMoves[i];
if (GetBattleMovePriority(battler, gAiLogicData->abilities[battler], move) > 0 && !(GetMovePriority(move) > 0 && IsBattleMoveStatus(move)))
{
return FIELD_EFFECT_POSITIVE;
}
}
}
// If we are faster or tie, we don't want trick room.
if ((gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[LEFT_FOE(battler)]) || (gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[RIGHT_FOE(battler)]))
return FIELD_EFFECT_NEGATIVE;
return FIELD_EFFECT_POSITIVE;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -154,7 +154,6 @@ static void AnimDoubleTeam(struct Sprite *);
static void AnimNightSlash(struct Sprite *);
static void AnimRockPolishStreak(struct Sprite *);
static void AnimRockPolishSparkle(struct Sprite *);
static void AnimPoisonJabProjectile(struct Sprite *);
static void AnimNightSlash(struct Sprite *);
static void AnimPluck(struct Sprite *);
static void AnimAcrobaticsSlashes(struct Sprite *);
@ -4595,20 +4594,18 @@ static void AnimPresent(struct Sprite *sprite)
static void AnimKnockOffOpponentsItem(struct Sprite *sprite)
{
int zero;
sprite->data[0] += ((sprite->data[3] * 128) / sprite->data[4]);
zero = 0;
if (sprite->data[0] > 0x7F)
{
sprite->data[1]++;
sprite->data[0] = zero;
sprite->data[0] = 0;
}
sprite->y2 = Sin(sprite->data[0] + 0x80, 30 - sprite->data[1] * 8);
if (moveAlongLinearPath(sprite))
{
sprite->y2 = zero;
sprite->data[0] = zero;
sprite->y2 = 0;
sprite->data[0] = 0;
DestroyAnimSprite(sprite);
}
}
@ -4686,13 +4683,11 @@ static void AnimItemSteal(struct Sprite *sprite)
static void AnimItemSteal_Step3(struct Sprite *sprite)
{
int zero;
sprite->data[0] += ((sprite->data[3] * 128) / sprite->data[4]);
zero = 0;
if (sprite->data[0] > 127)
{
sprite->data[1]++;
sprite->data[0] = zero;
sprite->data[0] = 0;
}
sprite->y2 = Sin(sprite->data[0] + 0x80, 30 - sprite->data[1] * 8);
@ -5194,7 +5189,7 @@ void AnimNeedleArmSpike(struct Sprite *sprite)
{
if (gBattleAnimArgs[0] == 0)
{
if (IsDoubleBattle())
if (gMovesInfo[gAnimMoveIndex].target == MOVE_TARGET_BOTH)
{
SetAverageBattlerPositions(gBattleAnimAttacker, TRUE, &a, &b);
}
@ -5206,7 +5201,7 @@ void AnimNeedleArmSpike(struct Sprite *sprite)
}
else
{
if (IsDoubleBattle())
if (gMovesInfo[gAnimMoveIndex].target == MOVE_TARGET_BOTH)
{
SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &a, &b);
}
@ -6868,6 +6863,51 @@ static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner)
SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp);
}
static void TrySwapAttractBattlerIds(u32 battlerAtk, u32 battlerPartner)
{
u32 attractedTo;
// our own infatuation handled with gBattleMons struct data swapping
// if another battler is infatuated with one of us, change to other battler
for (u32 i = 0; i < gBattlersCount; i++)
{
if (i == battlerAtk || i == battlerPartner || !gBattleMons[i].volatiles.infatuation)
continue;
attractedTo = INFATUATED_WITH(i);
if (attractedTo == battlerAtk)
{
gBattleMons[i].volatiles.infatuation = INFATUATED_WITH(battlerPartner);
break;
}
else if (attractedTo == battlerPartner)
{
gBattleMons[i].volatiles.infatuation = INFATUATED_WITH(battlerAtk);
break;
}
}
}
static void SwapBattlerMoveData(u32 battler1, u32 battler2)
{
u32 temp;
SWAP(gBattleStruct->chosenMovePositions[battler1], gBattleStruct->chosenMovePositions[battler2], temp);
SWAP(gChosenMoveByBattler[battler1], gChosenMoveByBattler[battler2], temp);
SWAP(gBattleStruct->moveTarget[battler1], gBattleStruct->moveTarget[battler2], temp);
SWAP(gMoveSelectionCursor[battler1], gMoveSelectionCursor[battler2], temp);
SWAP(gLockedMoves[battler1], gLockedMoves[battler2], temp);
// update last moves
SWAP(gLastPrintedMoves[battler1], gLastPrintedMoves[battler2], temp);
SWAP(gLastMoves[battler1], gLastMoves[battler2], temp);
SWAP(gLastLandedMoves[battler1], gLastLandedMoves[battler2], temp);
SWAP(gLastHitByType[battler1], gLastHitByType[battler2], temp);
SWAP(gLastUsedMoveType[battler1], gLastUsedMoveType[battler2], temp);
SWAP(gLastResultingMoves[battler1], gLastResultingMoves[battler2], temp);
SWAP(gLastHitBy[battler1], gLastHitBy[battler2], temp);
}
static void AnimTask_AllySwitchDataSwap(u8 taskId)
{
s32 i, j;
@ -6892,13 +6932,9 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
SWAP(gBattleSpritesDataPtr->battlerData[battlerAtk].invisible, gBattleSpritesDataPtr->battlerData[battlerPartner].invisible, temp);
SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp);
SWAP(gTransformedShininess[battlerAtk], gTransformedShininess[battlerPartner], temp);
SWAP(gStatuses3[battlerAtk], gStatuses3[battlerPartner], temp);
SWAP(gStatuses4[battlerAtk], gStatuses4[battlerPartner], temp);
SWAP(gBattleStruct->chosenMovePositions[battlerAtk], gBattleStruct->chosenMovePositions[battlerPartner], temp);
SWAP(gChosenMoveByBattler[battlerAtk], gChosenMoveByBattler[battlerPartner], temp);
SWAP(gLockedMoves[battlerAtk], gLockedMoves[battlerPartner], temp);
SWAP(gBattleStruct->moveTarget[battlerAtk], gBattleStruct->moveTarget[battlerPartner], temp);
SWAP(gMoveSelectionCursor[battlerAtk], gMoveSelectionCursor[battlerPartner], temp);
SwapBattlerMoveData(battlerAtk, battlerPartner);
// Swap turn order, so that all the battlers take action
SWAP(gChosenActionByBattler[battlerAtk], gChosenActionByBattler[battlerPartner], temp);
for (i = 0; i < gBattlersCount; i++)
@ -6923,11 +6959,12 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
TrySwapSkyDropTargets(battlerAtk, battlerPartner);
TrySwapStickyWebBattlerId(battlerAtk, battlerPartner);
TrySwapWishBattlerIds(battlerAtk, battlerPartner);
TrySwapAttractBattlerIds(battlerAtk, battlerPartner);
// For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target.
for (i = 0; i < gBattlersCount; i++)
{
u16 ability = GetBattlerAbility(i);
enum Ability ability = GetBattlerAbility(i);
// if not targeting a slot that got switched, continue
if (!IsBattlerAlly(gBattleStruct->moveTarget[i], battlerAtk))
continue;
@ -7454,7 +7491,7 @@ static void AnimRockPolishSparkle(struct Sprite *sprite)
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
// arg 2: duration
static void AnimPoisonJabProjectile(struct Sprite *sprite)
void AnimPoisonJabProjectile(struct Sprite *sprite)
{
s16 targetXPos;
s16 targetYPos;

View File

@ -1325,6 +1325,41 @@ const struct SpriteTemplate gTeraCrystalSpreadSpriteTemplate =
.callback = AnimTask_TeraCrystalShatter,
};
// See AnimSpriteOnMonPos in battle_anim_mons.c for more specifics
// Reuses the Mega Symbol affine animation seen in Mega Evolution
// gBattleAnimArgs 0-3 used
// 0, 1 used for position
// 2, 3 as some control variables
const struct SpriteTemplate gTeraSymbolSpriteTemplate =
{
.tileTag = ANIM_TAG_TERA_SYMBOL,
.paletteTag = ANIM_TAG_TERA_SYMBOL,
.oam = &gOamData_AffineDouble_ObjBlend_32x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gSpriteAffineAnimTable_MegaSymbol,
.callback = AnimSpriteOnMonPos,
};
// Swirls particle in vortex. Used for moves like Fire Spin or Sand Tomb
// args[0] - initial x offset
// args[1] - initial y offset
// args[2] - y increment
// args[3] - duration
// args[4] - increments some sin parameter
// args[5] - fixed sin parameter
// args[6] - attacker or target
const struct SpriteTemplate gTeraSmokeSpriteTemplate =
{
.tileTag = ANIM_TAG_SPARKLE_6,
.paletteTag = ANIM_TAG_SPARKLE_6,
.oam = &gOamData_AffineNormal_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimParticleInVortex,
};
const struct SpriteTemplate gPinkPetalVortexTemplate =
{
.tileTag = ANIM_TAG_PINK_PETAL,
@ -2515,6 +2550,31 @@ void AnimTask_HideSwapSprite(u8 taskId)
}
}
void AnimTask_HideOpponentShadows(u8 taskId)
{
u32 battlerLeft = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
gSprites[gBattleSpritesDataPtr->healthBoxesData[battlerLeft].shadowSpriteIdPrimary].callback = SpriteCB_SetInvisible;
gSprites[gBattleSpritesDataPtr->healthBoxesData[battlerLeft].shadowSpriteIdSecondary].callback = SpriteCB_SetInvisible;
if (IsDoubleBattle())
{
u32 battlerRight = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
gSprites[gBattleSpritesDataPtr->healthBoxesData[battlerRight].shadowSpriteIdPrimary].callback = SpriteCB_SetInvisible;
gSprites[gBattleSpritesDataPtr->healthBoxesData[battlerRight].shadowSpriteIdSecondary].callback = SpriteCB_SetInvisible;
}
DestroyAnimVisualTask(taskId);
}
void AnimTask_SetOpponentShadowCallbacks(u8 taskId)
{
u32 battlerLeft = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
SetBattlerShadowSpriteCallback(battlerLeft, gBattleMons[battlerLeft].species);
if (IsDoubleBattle())
{
u32 battlerRight = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
SetBattlerShadowSpriteCallback(battlerRight, gBattleMons[battlerRight].species);
}
DestroyAnimVisualTask(taskId);
}
#define megaEvo data[10]
#define trackEnemyPersonality data[11]
@ -5735,7 +5795,7 @@ static void AnimRecycle_Step(struct Sprite *sprite)
void AnimTask_GetWeather(u8 taskId)
{
bool32 utilityUmbrellaAffected = GetBattlerHoldEffect(gBattleAnimAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA;
bool32 utilityUmbrellaAffected = GetBattlerHoldEffect(gBattleAnimAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA;
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_NONE;
if (gWeatherMoveAnim & B_WEATHER_SUN && !utilityUmbrellaAffected)

View File

@ -10,7 +10,7 @@ static void AnimLightning(struct Sprite *);
static void AnimLightning_Step(struct Sprite *);
static void AnimUnusedSpinningFist(struct Sprite *);
static void AnimUnusedSpinningFist_Step(struct Sprite *);
static void AnimUnusedCirclingShock(struct Sprite *);
static void AnimCirclingElectricShock(struct Sprite *);
static void AnimZapCannonSpark_Step(struct Sprite *);
static void AnimThunderboltOrb(struct Sprite *);
static void AnimThunderboltOrb_Step(struct Sprite *);
@ -83,7 +83,9 @@ static const struct SpriteTemplate sUnusedSpinningFistSpriteTemplate =
.callback = AnimUnusedSpinningFist,
};
static const union AnimCmd sAnim_UnusedCirclingShock[] =
// Previously an unused function named sAnim_CirclingElectricShock
// Now used for Tera Blast Electric
static const union AnimCmd sAnim_CirclingElectricShock[] =
{
ANIMCMD_FRAME(0, 5),
ANIMCMD_FRAME(16, 5),
@ -94,21 +96,24 @@ static const union AnimCmd sAnim_UnusedCirclingShock[] =
ANIMCMD_JUMP(0),
};
static const union AnimCmd *const sAnims_UnusedCirclingShock[] =
// Previously an unused function named sAnims_UnusedCirclingShock
// Now used for Tera Blast Electric
const union AnimCmd *const sAnims_CirclingElectricShock[] =
{
sAnim_UnusedCirclingShock,
sAnim_CirclingElectricShock,
};
// Unused
static const struct SpriteTemplate sUnusedCirclingShockSpriteTemplate =
// Previously named sUnusedCirclingShockSpriteTemplate
// Still unused, but renamed for consistency
static const struct SpriteTemplate sCirclingElectricShockSpriteTemplate =
{
.tileTag = ANIM_TAG_SHOCK,
.paletteTag = ANIM_TAG_SHOCK,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = sAnims_UnusedCirclingShock,
.anims = sAnims_CirclingElectricShock,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimUnusedCirclingShock,
.callback = AnimCirclingElectricShock,
};
const struct SpriteTemplate gSparkElectricitySpriteTemplate =
@ -343,6 +348,19 @@ static const union AffineAnimCmd sAffineAnim_GrowingElectricOrb_2[] =
AFFINEANIMCMD_END,
};
static const union AffineAnimCmd sAffineAnim_GrowingElectricOrb_3[] =
{
AFFINEANIMCMD_FRAME(0x10, 0x10, 0, 0),
AFFINEANIMCMD_FRAME(0x4, 0x4, 0, 60),
AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
AFFINEANIMCMD_LOOP(0),
AFFINEANIMCMD_FRAME(0xFFFC, 0xFFFC, 0, 5),
AFFINEANIMCMD_FRAME(0x4, 0x4, 0, 5),
AFFINEANIMCMD_LOOP(10),
AFFINEANIMCMD_FRAME(-4, -4, 0, 60),
AFFINEANIMCMD_END,
};
static const union AffineAnimCmd sAffineAnim_GrowingElectricOrb_4[] =
{
AFFINEANIMCMD_FRAME(5, 5, 0, 0),
@ -368,6 +386,11 @@ const union AffineAnimCmd *const gAffineAnims_GrowingElectricOrb2[] =
sAffineAnim_GrowingElectricOrb_4,
};
const union AffineAnimCmd *const gAffineAnims_GrowingElectricOrb3[] =
{
sAffineAnim_GrowingElectricOrb_3,
};
const struct SpriteTemplate gGrowingChargeOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_CIRCLE_OF_LIGHT,
@ -391,6 +414,18 @@ const struct SpriteTemplate gGrowingChargeOrb2SpriteTemplate =
.callback = AnimGrowingChargeOrb,
};
// For Dynamax Cannon - orb gets smaller at the end
const struct SpriteTemplate gGrowingChargeOrb3SpriteTemplate =
{
.tileTag = ANIM_TAG_CIRCLE_OF_LIGHT,
.paletteTag = ANIM_TAG_CIRCLE_OF_LIGHT,
.oam = &gOamData_AffineNormal_ObjBlend_64x64,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gAffineAnims_GrowingElectricOrb3,
.callback = AnimGrowingChargeOrb,
};
static const union AnimCmd sAnim_ElectricPuff[] =
{
ANIMCMD_FRAME(0, 3),
@ -492,6 +527,17 @@ const struct SpriteTemplate gFairyLockChainsSpriteTemplate =
.callback = AnimVoltTackleBolt,
};
const struct SpriteTemplate gCollisionCourseSpriteTemplate =
{
.tileTag = ANIM_TAG_SMALL_EMBER,
.paletteTag = ANIM_TAG_SMALL_EMBER,
.oam = &gOamData_AffineOff_ObjNormal_64x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimVoltTackleBolt,
};
const struct SpriteTemplate gGrowingShockWaveOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_CIRCLE_OF_LIGHT,
@ -603,7 +649,7 @@ const struct SpriteTemplate gVoltSwitchSpriteTemplate =
// functions
static void AnimLightning(struct Sprite *sprite)
{
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->x -= gBattleAnimArgs[0];
else
sprite->x += gBattleAnimArgs[0];
@ -620,7 +666,7 @@ static void AnimLightning_Step(struct Sprite *sprite)
static void AnimUnusedSpinningFist(struct Sprite *sprite)
{
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->x -= gBattleAnimArgs[0];
else
sprite->x += gBattleAnimArgs[0];
@ -634,12 +680,12 @@ static void AnimUnusedSpinningFist_Step(struct Sprite *sprite)
DestroySpriteAndMatrix(sprite);
}
static void AnimUnusedCirclingShock(struct Sprite *sprite)
static void AnimCirclingElectricShock(struct Sprite *sprite)
{
sprite->x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
sprite->y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
{
sprite->x -= gBattleAnimArgs[0];
sprite->y -= gBattleAnimArgs[1];
@ -767,7 +813,7 @@ static void AnimThunderboltOrb_Step(struct Sprite *sprite)
static void AnimThunderboltOrb(struct Sprite *sprite)
{
if (IsContest() || GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER)
if (IsContest() || IsOnPlayerSide(gBattleAnimTarget))
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
sprite->x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[1];
@ -788,7 +834,7 @@ void AnimSparkElectricityFlashing(struct Sprite *sprite)
else
battler = gBattleAnimAttacker;
if (IsContest() || GetBattlerSide(battler) == B_SIDE_PLAYER)
if (IsContest() || IsOnPlayerSide(battler))
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
sprite->x = GetBattlerSpriteCoord(battler, BATTLER_COORD_X_2) + gBattleAnimArgs[0];
@ -1099,7 +1145,7 @@ static void AnimVoltTackleOrbSlide(struct Sprite *sprite)
sprite->data[6] = GetAnimBattlerSpriteId(ANIM_ATTACKER);
sprite->data[7] = 16;
if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->data[7] *= -1;
sprite->callback = AnimVoltTackleOrbSlide_Step;
@ -1130,7 +1176,7 @@ void AnimTask_VoltTackleAttackerReappear(u8 taskId)
case 0:
task->data[15] = GetAnimBattlerSpriteId(ANIM_ATTACKER);
task->data[14] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER)
if (IsOnPlayerSide(gBattleAnimAttacker))
{
task->data[14] = -32;
task->data[13] = 2;
@ -1186,7 +1232,7 @@ void AnimTask_VoltTackleBolt(u8 taskId)
switch(task->data[0])
{
case 0:
task->data[1] = GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER ? 1 : -1;
task->data[1] = IsOnPlayerSide(gBattleAnimAttacker) ? 1 : -1;
switch (gBattleAnimArgs[0])
{
@ -1256,19 +1302,25 @@ void AnimTask_VoltTackleBolt(u8 taskId)
static bool8 CreateVoltTackleBolt(struct Task *task, u8 taskId)
{
u32 spriteId;
bool32 isFairyLock = (gAnimMoveIndex == MOVE_FAIRY_LOCK);
if (isFairyLock)
spriteId = CreateSprite(&gFairyLockChainsSpriteTemplate, task->data[3], task->data[5] + 10, 35);
else
spriteId = CreateSprite(&gVoltTackleBoltSpriteTemplate, task->data[3], task->data[5], 35);
switch(gAnimMoveIndex)
{
case MOVE_FAIRY_LOCK:
spriteId = CreateSprite(&gFairyLockChainsSpriteTemplate, task->data[3], task->data[5] + 10, 35);
break;
case MOVE_COLLISION_COURSE:
spriteId = CreateSprite(&gCollisionCourseSpriteTemplate, task->data[3], task->data[5], 35);
break;
default:
spriteId = CreateSprite(&gVoltTackleBoltSpriteTemplate, task->data[3], task->data[5], 35);
}
bool32 doDestroyOamMatrix = (gAnimMoveIndex == MOVE_FAIRY_LOCK) || (gAnimMoveIndex == MOVE_COLLISION_COURSE);
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].data[6] = taskId;
gSprites[spriteId].data[7] = 7;
gSprites[spriteId].data[1] = isFairyLock ? 25 : 12; // How long the chains / bolts stay on screen.
gSprites[spriteId].data[2] = isFairyLock; // Whether to destroy the Oam Matrix.
gSprites[spriteId].data[1] = (gAnimMoveIndex == MOVE_FAIRY_LOCK) ? 25 : 12; // How long the chains / bolts stay on screen.
gSprites[spriteId].data[2] = doDestroyOamMatrix; // Whether to destroy the Oam Matrix.
task->data[7]++;
}
@ -1581,9 +1633,9 @@ static void VoltSwitch_Step(struct Sprite* sprite)
void AnimTask_VoltSwitch(struct Sprite* sprite)
{
InitSpritePosToAnimAttacker(sprite, 0);
InitSpritePosToAnimAttacker(sprite, FALSE);
if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT)
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
else
sprite->y += 10; //Move slightly down

View File

@ -7,7 +7,6 @@
#include "constants/rgb.h"
static void AnimBonemerangProjectile(struct Sprite *);
static void AnimBoneHitProjectile(struct Sprite *);
static void AnimDirtPlumeParticle_Step(struct Sprite *);
static void AnimDigDirtMound(struct Sprite *);
static void AnimBonemerangProjectile_Step(struct Sprite *);
@ -84,7 +83,7 @@ static const union AnimCmd sAnim_MudSlapMud[] =
ANIMCMD_END,
};
static const union AnimCmd *const sAnims_MudSlapMud[] =
const union AnimCmd *const sAnims_MudSlapMud[] =
{
sAnim_MudSlapMud,
};
@ -199,10 +198,10 @@ static void AnimBonemerangProjectile_End(struct Sprite *sprite)
// arg 2: target x pixel offset
// arg 3: target y pixel offset
// arg 4: duration
static void AnimBoneHitProjectile(struct Sprite *sprite)
void AnimBoneHitProjectile(struct Sprite *sprite)
{
InitSpritePosToAnimTarget(sprite, TRUE);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
sprite->data[0] = gBattleAnimArgs[4];
@ -524,7 +523,7 @@ void AnimDirtPlumeParticle(struct Sprite *sprite)
s8 battler;
s16 xOffset;
if (gBattleAnimArgs[0] == 0)
if (gBattleAnimArgs[0] == ANIM_ATTACKER)
battler = gBattleAnimAttacker;
else
battler = gBattleAnimTarget;

View File

@ -13,17 +13,21 @@
#include "constants/battle_anim.h"
#include "constants/rgb.h"
enum {
HAILSTRUCTTYPE_NEGATIVE_POS_MOD = 0,
HAILSTRUCTTYPE_POSITIVE_POS_MOD = 1,
HAILSTRUCTTYPE_FIXED_POSITION = 2,
};
struct HailStruct {
s32 x:10;
s32 y:10;
s32 bPosition:8;
s32 unk3:4;
s32 type:4;
};
static void AnimUnusedIceCrystalThrow(struct Sprite *);
static void AnimUnusedIceCrystalThrow_Step(struct Sprite *);
static void AnimIcePunchSwirlingParticle(struct Sprite *);
static void AnimIceBeamParticle(struct Sprite *);
static void AnimFlickerIceEffectParticle(struct Sprite *);
static void AnimSwirlingSnowball(struct Sprite *);
static void AnimSwirlingSnowball_Step2(struct Sprite *);
@ -382,16 +386,16 @@ const struct SpriteTemplate gPoisonGasCloudSpriteTemplate =
static const struct HailStruct sHailCoordData[] =
{
{.x = 100, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 2},
{.x = 85, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 0},
{.x = 242, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .unk3 = 1},
{.x = 66, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .unk3 = 1},
{.x = 182, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .unk3 = 0},
{.x = 60, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 2},
{.x = 214, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .unk3 = 0},
{.x = 113, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .unk3 = 1},
{.x = 210, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .unk3 = 1},
{.x = 38, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .unk3 = 0},
{.x = 100, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_FIXED_POSITION},
{.x = 85, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD},
{.x = 242, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD},
{.x = 66, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD},
{.x = 182, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD},
{.x = 60, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_FIXED_POSITION},
{.x = 214, .y = 120, .bPosition = B_POSITION_OPPONENT_LEFT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD},
{.x = 113, .y = 120, .bPosition = B_POSITION_PLAYER_LEFT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD},
{.x = 210, .y = 120, .bPosition = B_POSITION_OPPONENT_RIGHT, .type = HAILSTRUCTTYPE_POSITIVE_POS_MOD},
{.x = 38, .y = 120, .bPosition = B_POSITION_PLAYER_RIGHT, .type = HAILSTRUCTTYPE_NEGATIVE_POS_MOD},
};
static const union AffineAnimCmd sAffineAnim_HailParticle_0[] =
@ -698,12 +702,12 @@ static void AnimIcePunchSwirlingParticle(struct Sprite *sprite)
// arg 2: target x offset
// arg 3: target y offset
// arg 4: duration
static void AnimIceBeamParticle(struct Sprite *sprite)
void AnimIceBeamParticle(struct Sprite *sprite)
{
InitSpritePosToAnimAttacker(sprite, TRUE);
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->data[2] -= gBattleAnimArgs[2];
else
sprite->data[2] += gBattleAnimArgs[2];
@ -728,7 +732,7 @@ void AnimIceEffectParticle(struct Sprite *sprite)
else
{
SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &sprite->x, &sprite->y);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
sprite->x += gBattleAnimArgs[0];
@ -775,7 +779,7 @@ static void AnimSwirlingSnowball(struct Sprite *sprite)
SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &sprite->data[2], &sprite->data[4]);
}
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->data[2] -= gBattleAnimArgs[2];
else
sprite->data[2] += gBattleAnimArgs[2];
@ -821,7 +825,7 @@ void AnimSwirlingSnowball_Step1(struct Sprite *sprite)
sprite->x2 = 0;
sprite->data[0] = 128;
tempVar = GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER ? 20 : -20;
tempVar = !IsOnPlayerSide(gBattleAnimAttacker) ? 20 : -20;
sprite->data[3] = Sin(sprite->data[0], tempVar);
sprite->data[4] = Cos(sprite->data[0], 0xF);
@ -833,7 +837,7 @@ void AnimSwirlingSnowball_Step1(struct Sprite *sprite)
static void AnimSwirlingSnowball_Step2(struct Sprite *sprite)
{
s16 tempVar;
tempVar = GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER ? 20 : -20;
tempVar = !IsOnPlayerSide(gBattleAnimAttacker) ? 20 : -20;
if (sprite->data[5] <= 31)
{
@ -897,7 +901,7 @@ void AnimMoveParticleBeyondTarget(struct Sprite *sprite)
SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &sprite->data[2], &sprite->data[4]);
}
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->data[2] -= gBattleAnimArgs[2];
else
sprite->data[2] += gBattleAnimArgs[2];
@ -969,7 +973,7 @@ static void AnimWaveFromCenterOfTarget(struct Sprite *sprite)
{
SetAverageBattlerPositions(gBattleAnimTarget, FALSE, &sprite->x, &sprite->y);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
sprite->x += gBattleAnimArgs[0];
@ -1006,7 +1010,7 @@ static void InitSwirlingFogAnim(struct Sprite *sprite)
else
{
SetAverageBattlerPositions(gBattleAnimAttacker, FALSE, &sprite->x, &sprite->y);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->x -= gBattleAnimArgs[0];
else
sprite->x += gBattleAnimArgs[0];
@ -1025,7 +1029,7 @@ static void InitSwirlingFogAnim(struct Sprite *sprite)
else
{
SetAverageBattlerPositions(gBattleAnimTarget, FALSE, &sprite->x, &sprite->y);
if (GetBattlerSide(gBattleAnimTarget) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimTarget))
sprite->x -= gBattleAnimArgs[0];
else
sprite->x += gBattleAnimArgs[0];
@ -1043,7 +1047,7 @@ static void InitSwirlingFogAnim(struct Sprite *sprite)
tempVar = 0x40;
sprite->data[6] = tempVar;
if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER)
if (IsOnPlayerSide(gBattleAnimTarget))
sprite->y += 8;
sprite->data[0] = gBattleAnimArgs[3];
@ -1289,12 +1293,12 @@ static void InitPoisonGasCloudAnim(struct Sprite *sprite)
if (GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2) < GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2))
sprite->data[7] = 0x8000;
if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER)
if (IsOnPlayerSide(gBattleAnimTarget))
{
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
gBattleAnimArgs[3] = -gBattleAnimArgs[3];
if ((sprite->data[7] & 0x8000) && GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER)
if ((sprite->data[7] & 0x8000) && IsOnPlayerSide(gBattleAnimAttacker))
sprite->subpriority = gSprites[GetAnimBattlerSpriteId(ANIM_TARGET)].subpriority + 1;
sprite->data[6] = 1;
@ -1373,7 +1377,7 @@ static void MovePoisonGasCloud(struct Sprite *sprite)
sprite->data[7]++;
if (IsContest())
sprite->data[5] = 80;
else if (GetBattlerSide(gBattleAnimTarget) != B_SIDE_PLAYER)
else if (!IsOnPlayerSide(gBattleAnimTarget))
sprite->data[5] = 204;
else
sprite->data[5] = 80;
@ -1419,7 +1423,7 @@ static void MovePoisonGasCloud(struct Sprite *sprite)
sprite->data[4] = sprite->y + 4;
if (IsContest())
sprite->data[2] = -16;
else if (GetBattlerSide(gBattleAnimTarget) != B_SIDE_PLAYER)
else if (!IsOnPlayerSide(gBattleAnimTarget))
sprite->data[2] = DISPLAY_WIDTH + 16;
else
sprite->data[2] = -16;
@ -1445,6 +1449,13 @@ static void MovePoisonGasCloud(struct Sprite *sprite)
}
}
#define tState data[0]
#define tSpriteCount data[1]
#define tHailAffineAnimNum data[2]
#define tHailStructId data[3]
#define tInitialDelayTimer data[4]
#define tHailSpawnTimer data[5]
void AnimTask_Hail(u8 taskId)
{
struct Task *task = &gTasks[taskId];
@ -1455,71 +1466,86 @@ void AnimTask_Hail(u8 taskId)
static void AnimTask_Hail2(u8 taskId)
{
struct Task *task = &gTasks[taskId];
switch (task->data[0])
switch (task->tState)
{
case 0:
if (++task->data[4] > 2)
if (++task->tInitialDelayTimer > 2)
{
task->data[4] = 0;
task->data[5] = 0;
task->data[2] = 0;
task->data[0]++;
task->tInitialDelayTimer = 0;
task->tHailSpawnTimer = 0;
task->tHailAffineAnimNum = 0;
task->tState++;
}
break;
case 1:
if (task->data[5] == 0)
if (task->tHailSpawnTimer == 0)
{
if (GenerateHailParticle(task->data[3], task->data[2], taskId, 1))
task->data[1]++;
if (GenerateHailParticle(task->tHailStructId, task->tHailAffineAnimNum, taskId, 1))
task->tSpriteCount++;
if (++task->data[2] == 3)
if (++task->tHailAffineAnimNum == (int)ARRAY_COUNT(sAffineAnims_HailParticle))
{
if (++task->data[3] == 10)
task->data[0]++;
if (++task->tHailStructId == (int)ARRAY_COUNT(sHailCoordData))
task->tState++;
else
task->data[0]--;
task->tState--;
}
else
{
task->data[5] = 1;
task->tHailSpawnTimer = 1;
}
}
else
{
task->data[5]--;
task->tHailSpawnTimer--;
}
break;
case 2:
if (task->data[1] == 0)
if (task->tSpriteCount == 0)
DestroyAnimVisualTask(taskId);
break;
}
}
#undef tState
#undef tSpriteCount
#undef tHailAffineAnimNum
#undef tHailStructId
#undef tInitialDelayTimer
#undef tHailSpawnTimer
// Hail falling particle sprite vars
#define sSpawnImpactEffect data[0]
#define sTargetX data[3]
#define sTargetY data[4]
#define sAffineAnimNum data[5]
#define sOwnerTaskId data[6]
#define sOwnerTaskSpriteCountField data[7]
static bool8 GenerateHailParticle(u8 hailStructId, u8 affineAnimNum, u8 taskId, u8 c)
{
u8 id;
s16 battlerX, battlerY;
s16 spriteX;
bool8 possibleBool = FALSE;
s8 unk = sHailCoordData[hailStructId].unk3;
bool8 shouldSpawnImpactEffect = FALSE;
s8 type = sHailCoordData[hailStructId].type;
if (unk != 2)
if (type != HAILSTRUCTTYPE_FIXED_POSITION)
{
id = GetBattlerAtPosition(sHailCoordData[hailStructId].bPosition);
if (IsBattlerSpriteVisible(id))
{
possibleBool = TRUE;
shouldSpawnImpactEffect = TRUE;
battlerX = GetBattlerSpriteCoord(id, BATTLER_COORD_X_2);
battlerY = GetBattlerSpriteCoord(id, BATTLER_COORD_Y_PIC_OFFSET);
switch (unk)
switch (type)
{
case 0:
case HAILSTRUCTTYPE_NEGATIVE_POS_MOD:
battlerX -= GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_WIDTH) / 6;
battlerY -= GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_HEIGHT) / 6;
break;
case 1:
case HAILSTRUCTTYPE_POSITIVE_POS_MOD:
battlerX += GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_WIDTH) / 6;
battlerY += GetBattlerSpriteCoordAttr(id, BATTLER_COORD_ATTR_HEIGHT) / 6;
break;
@ -1545,12 +1571,12 @@ static bool8 GenerateHailParticle(u8 hailStructId, u8 affineAnimNum, u8 taskId,
else
{
StartSpriteAffineAnim(&gSprites[id], affineAnimNum);
gSprites[id].data[0] = possibleBool;
gSprites[id].data[3] = battlerX;
gSprites[id].data[4] = battlerY;
gSprites[id].data[5] = affineAnimNum;
gSprites[id].data[6] = taskId;
gSprites[id].data[7] = c;
gSprites[id].sSpawnImpactEffect = shouldSpawnImpactEffect;
gSprites[id].sTargetX = battlerX;
gSprites[id].sTargetY = battlerY;
gSprites[id].sAffineAnimNum = affineAnimNum;
gSprites[id].sOwnerTaskId = taskId;
gSprites[id].sOwnerTaskSpriteCountField = c;
return TRUE;
}
}
@ -1562,20 +1588,23 @@ static void AnimHailBegin(struct Sprite *sprite)
sprite->x += 4;
sprite->y += 8;
if (sprite->x < sprite->data[3] && sprite->y < sprite->data[4])
if (sprite->x < sprite->sTargetX && sprite->y < sprite->sTargetY)
return;
if (sprite->data[0] == 1 && sprite->data[5] == 0)
if (sprite->sSpawnImpactEffect == 1 && sprite->sAffineAnimNum == 0)
{
spriteId = CreateSprite(&gIceCrystalHitLargeSpriteTemplate,
sprite->data[3], sprite->data[4], sprite->subpriority);
sprite->sTargetX, sprite->sTargetY, sprite->subpriority);
sprite->data[0] = spriteId;
if (spriteId != MAX_SPRITES)
{
// The sprite template we're using is shared amongst a few other
// places, which make the sprite flicker. That's not what we want
// here, though. Override the callback.
gSprites[sprite->data[0]].callback = AnimHailContinue;
gSprites[sprite->data[0]].data[6] = sprite->data[6];
gSprites[sprite->data[0]].data[7] = sprite->data[7];
gSprites[sprite->data[0]].sOwnerTaskId = sprite->sOwnerTaskId;
gSprites[sprite->data[0]].sOwnerTaskSpriteCountField = sprite->sOwnerTaskSpriteCountField;
}
FreeOamMatrix(sprite->oam.matrixNum);
@ -1583,22 +1612,34 @@ static void AnimHailBegin(struct Sprite *sprite)
}
else
{
gTasks[sprite->data[6]].data[sprite->data[7]]--;
gTasks[sprite->sOwnerTaskId].data[sprite->sOwnerTaskSpriteCountField]--;
FreeOamMatrix(sprite->oam.matrixNum);
DestroySprite(sprite);
}
}
#undef sSpawnImpactEffect
#undef sTargetX
#undef sTargetY
#undef sAffineAnimNum
// Hail impact VFX sprite vars
#define sTimer data[0]
static void AnimHailContinue(struct Sprite *sprite)
{
if (++sprite->data[0] == 20)
if (++sprite->sTimer == 20)
{
gTasks[sprite->data[6]].data[sprite->data[7]]--;
gTasks[sprite->sOwnerTaskId].data[sprite->sOwnerTaskSpriteCountField]--;
FreeOamMatrix(sprite->oam.matrixNum);
DestroySprite(sprite);
}
}
#undef sTimer
#undef sOwnerTaskId
#undef sOwnerTaskSpriteCountField
// Initializes the animation for Ice Ball.
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
@ -1618,7 +1659,7 @@ static void InitIceBallAnim(struct Sprite *sprite)
sprite->data[0] = gBattleAnimArgs[4];
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[2];

View File

@ -4403,6 +4403,17 @@ const struct SpriteTemplate gUTurnBallBackSpriteTemplate =
.callback = AnimAbsorptionOrb,
};
// dynamax cannon
const struct SpriteTemplate gSpriteTemplate_DynamaxCannonOrb = {
.tileTag = ANIM_TAG_HYDRO_PUMP,
.paletteTag = ANIM_TAG_HYDRO_PUMP,
.oam = &gOamData_AffineDouble_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = sSpriteAffineAnimTable_HydroCannonBall,
.callback = AnimShadowBall
};
// wicked blow
static const union AffineAnimCmd sSpriteAffineAnim_DrainPunchFist[] = {
AFFINEANIMCMD_FRAME(256, 256, 0, 1), //Double sprite size
@ -4729,7 +4740,7 @@ static const union AffineAnimCmd* const sSpriteAffineAnimTable_Flutterby[] = {
const struct SpriteTemplate gSpriteTemplate_InfernalParadeFlame = {
.tileTag = ANIM_TAG_PURPLE_FLAME,
.paletteTag = ANIM_TAG_PURPLE_FLAME,
.oam = &gOamData_AffineDouble_ObjBlend_32x16,
.oam = &gOamData_AffineDouble_ObjNormal_16x32,
.anims = gAnims_GrudgeFlame,
.images = NULL,
.affineAnims = sSpriteAffineAnimTable_Flutterby,
@ -5684,7 +5695,7 @@ const struct SpriteTemplate gBlackHoleEclipseBlueRingSpriteTemplate =
const struct SpriteTemplate gBlackHoleEclipseBlackRingSpriteTemplate =
{
.tileTag = ANIM_TAG_THIN_RING,
.paletteTag = ANIM_TAG_HANDS_AND_FEET,
.paletteTag = ANIM_TAG_SHADOW_BALL,
.oam = &gOamData_AffineDouble_ObjNormal_64x64,
.anims = gDummySpriteAnimTable,
.images = NULL,
@ -7301,6 +7312,287 @@ const struct SpriteTemplate gOmegaGeyserSpriteTemplate =
.callback = SpriteCB_Geyser,
};
// Moves objects (ice crystals) in a wave-like behavior. Seen in Max Flutterby
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
// arg 2: wave amplitude
const struct SpriteTemplate gIceShardSpriteTemplate =
{
.tileTag = ANIM_TAG_ICE_CRYSTALS,
.paletteTag = ANIM_TAG_ICE_CRYSTALS,
.oam = &gOamData_AffineDouble_ObjBlend_8x8,
.anims = gAnims_IceCrystalSmall,
.images = NULL,
.affineAnims = sSpriteAffineAnimTable_Flutterby,
.callback = SpriteCB_MaxFlutterby
};
const struct SpriteTemplate gSpinningVineSpriteTemplate =
{
.tileTag = ANIM_TAG_PUNISHMENT_BLADES,
.paletteTag = ANIM_TAG_LEAF,
.oam = &gOamData_AffineNormal_ObjNormal_32x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gAffineAnims_SpinningBone,
.callback = AnimBoneHitProjectile,
};
const struct SpriteTemplate gMaxFlutterbyButterflySpriteTemplate =
{
.tileTag = ANIM_TAG_SPARKLE_6,
.paletteTag = ANIM_TAG_SPARKLE_6,
.oam = &gOamData_AffineNormal_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = sSpriteAffineAnimTable_Flutterby,
.callback = SpriteCB_MaxFlutterby
};
const struct SpriteTemplate gReallyBigRockBlastRockSpriteTemplate =
{
.tileTag = ANIM_TAG_REALLY_BIG_ROCK,
.paletteTag = ANIM_TAG_REALLY_BIG_ROCK,
.oam = &gOamData_AffineDouble_ObjNormal_64x64,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimRockBlastRock,
};
const struct SpriteTemplate gOrderUpTatsugiriCurlySpriteTemplate =
{
.tileTag = ANIM_TAG_TATSUGIRI_CURLY,
.paletteTag = ANIM_TAG_TATSUGIRI_CURLY,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gAnims_DreepyMissilePlayer,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimRockTomb,
};
const struct SpriteTemplate gOrderUpTatsugiriDroopySpriteTemplate =
{
.tileTag = ANIM_TAG_TATSUGIRI_DROOPY,
.paletteTag = ANIM_TAG_TATSUGIRI_DROOPY,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gAnims_DreepyMissilePlayer,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimRockTomb,
};
const struct SpriteTemplate gOrderUpTatsugiriStretchySpriteTemplate =
{
.tileTag = ANIM_TAG_TATSUGIRI_STRETCHY,
.paletteTag = ANIM_TAG_TATSUGIRI_STRETCHY,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gAnims_DreepyMissilePlayer,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimRockTomb,
};
// Start of Tera Blast sprite templates
const struct SpriteTemplate gFireSpreadBlastSpriteTemplate =
{
.tileTag = ANIM_TAG_SMALL_EMBER,
.paletteTag = ANIM_TAG_SMALL_EMBER,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gAnims_BasicFire,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimIceBeamParticle,
};
const struct SpriteTemplate gPurpleFlameSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_PURPLE_FLAME,
.paletteTag = ANIM_TAG_PURPLE_FLAME,
.oam = &gOamData_AffineOff_ObjBlend_16x32,
.anims = gAnims_GrudgeFlame,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate gAirWaveSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_AIR_WAVE_2,
.paletteTag = ANIM_TAG_AIR_WAVE_2,
.oam = &gOamData_AffineOff_ObjNormal_32x16,
.anims = gAffineAnims_AirWaveCrescent,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate gPinkVioletOrbSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_PINKVIO_ORB,
.paletteTag = ANIM_TAG_PINKVIO_ORB,
.oam = &gOamData_AffineNormal_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate gHydroPumpSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_HYDRO_PUMP,
.paletteTag = ANIM_TAG_HYDRO_PUMP,
.oam = &gOamData_AffineOff_ObjBlend_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sCirclingShockSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_SHOCK,
.paletteTag = ANIM_TAG_SHOCK,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = sAnims_CirclingElectricShock,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sIceCrystalSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_ICE_CRYSTALS,
.paletteTag = ANIM_TAG_ICE_CRYSTALS,
.oam = &gOamData_AffineDouble_ObjBlend_8x16,
.anims = gAnims_IceCrystalLarge,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sMudSandSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_MUD_SAND,
.paletteTag = ANIM_TAG_MUD_SAND,
.oam = &gOamData_AffineOff_ObjNormal_16x16,
.anims = sAnims_MudSlapMud,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sPoisonSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_POISON_BUBBLE,
.paletteTag = ANIM_TAG_POISON_BUBBLE,
.oam = &gOamData_AffineDouble_ObjNormal_16x16,
.anims = &gAnims_PoisonProjectile[0],
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sRockSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_ROCKS,
.paletteTag = ANIM_TAG_ROCKS,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gAnims_FlyingRock,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sMetalBallSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_METAL_BALL,
.paletteTag = ANIM_TAG_METAL_BALL,
.oam = &gOamData_AffineOff_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate sPinkHeartSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_PINK_HEART,
.paletteTag = ANIM_TAG_PINK_HEART,
.oam = &gOamData_AffineOff_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate gDragonDanceOrbSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_HOLLOW_ORB,
.paletteTag = ANIM_TAG_HOLLOW_ORB,
.oam = &gOamData_AffineOff_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate gYellowStarSpiralOutwardSpriteTemplate =
{
.tileTag = ANIM_TAG_YELLOW_STAR,
.paletteTag = ANIM_TAG_YELLOW_STAR,
.oam = &gOamData_AffineNormal_ObjNormal_32x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimFireSpiralOutward,
};
const struct SpriteTemplate gTeraBlastFlyingSpriteTemplate =
{
.tileTag = ANIM_TAG_METAL_SOUND_WAVES,
.paletteTag = ANIM_TAG_METAL_SOUND_WAVES,
.oam = &gOamData_AffineDouble_ObjNormal_32x64,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gAffineAnims_SpinningBone,
.callback = AnimShadowBall,
};
const struct SpriteTemplate gTeraBlastWaterSpriteTemplate =
{
.tileTag = ANIM_TAG_HYDRO_PUMP,
.paletteTag = ANIM_TAG_HYDRO_PUMP,
.oam = &gOamData_AffineDouble_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimDracoMeteorRock,
};
const struct SpriteTemplate gTeraBlastRockSpriteTemplate =
{
.tileTag = ANIM_TAG_ROCKS,
.paletteTag = ANIM_TAG_ROCKS,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = sAnims_BasicRock,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimDracoMeteorRock,
};
const struct SpriteTemplate gGhostProjectileSpriteTemplate =
{
.tileTag = ANIM_TAG_GHOSTLY_SPIRIT,
.paletteTag = ANIM_TAG_GHOSTLY_SPIRIT,
.oam = &gOamData_AffineOff_ObjBlend_32x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimPoisonJabProjectile,
};
// End of Tera Blast sprite templates
const union AnimCmd gSproutAnimCmds[] =
{
ANIMCMD_FRAME(96, 5),
@ -7965,7 +8257,7 @@ void SpriteCB_RandomCentredHits(struct Sprite *sprite)
StartSpriteAffineAnim(sprite, gBattleAnimArgs[1]);
if (gBattleAnimArgs[0] == 0)
if (gBattleAnimArgs[0] == ANIM_ATTACKER)
{
if (IsDoubleBattle())
InitSpritePosToAnimAttackersCentre(sprite, FALSE);
@ -8766,7 +9058,7 @@ void AnimTask_ShellSideArm(u8 taskId)
void AnimTask_TerrainPulse(u8 taskId)
{
if (IsBattlerTerrainAffected(gBattleAnimAttacker, STATUS_FIELD_TERRAIN_ANY))
if (IsBattlerTerrainAffected(gBattleAnimAttacker, GetBattlerAbility(gBattleAnimAttacker), GetBattlerHoldEffect(gBattleAnimAttacker), STATUS_FIELD_TERRAIN_ANY))
{
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
gBattleAnimArgs[0] = TYPE_ELECTRIC;
@ -9137,6 +9429,18 @@ static void SpriteCB_DragonEnergyShot(struct Sprite* sprite)
//arg 2: wave amplitude
static void SpriteCB_MaxFlutterby(struct Sprite* sprite)
{
s16 target_x;
s16 target_y;
if (gMovesInfo[gAnimMoveIndex].target == MOVE_TARGET_BOTH)
{
SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &target_x, &target_y);
}
else
{
target_x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
target_y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
}
InitSpritePosToAnimAttacker(sprite, FALSE);
sprite->data[0] = 0x10; //Speed delay
@ -9152,7 +9456,8 @@ static void SpriteCB_MaxFlutterbyStep1(struct Sprite* sprite)
{
if (!FuncIsActiveTask(AnimTask_DynamaxGrowthStep))
{
if (gAnimMoveIndex != MOVE_INFERNAL_PARADE)
if (gAnimMoveIndex != MOVE_INFERNAL_PARADE
&& gAnimMoveIndex != MOVE_ASTRAL_BARRAGE)
PlaySE(SE_M_SAND_ATTACK);
StartSpriteAffineAnim(sprite, 1);
@ -9327,7 +9632,7 @@ void AnimTask_RandomBool(u8 taskId)
// Credit to Skeli
#define PRIMAL_PULSE_SCALE_SIZE 16
#define PRIMAL_PULSE_FRAME_COUNT 4
static const union AffineAnimCmd sSpriteAffineAnim_PrimalSymbol[] =
static const union AffineAnimCmd sSpriteAffineAnim_PrimalSymbol[] =
{
AFFINEANIMCMD_FRAME(16, 16, 0, 0),
AFFINEANIMCMD_FRAME(32, 32, 0, 15),
@ -9370,3 +9675,25 @@ const union AffineAnimCmd* const gSpriteAffineAnimTable_MegaSymbol[] =
{
sSpriteAffineAnim_MegaSymbol,
};
// Used for determining which animation to use for Order Up
void AnimTask_GetCommanderType(u8 taskId)
{
switch (gBattleStruct->battlerState[gEffectBattler].commanderSpecies)
{
case SPECIES_TATSUGIRI_CURLY:
gBattleAnimArgs[ARG_RET_ID] = ANIM_ORDER_UP_CURLY;
break;
case SPECIES_TATSUGIRI_DROOPY:
gBattleAnimArgs[ARG_RET_ID] = ANIM_ORDER_UP_DROOPY;
break;
case SPECIES_TATSUGIRI_STRETCHY:
gBattleAnimArgs[ARG_RET_ID] = ANIM_ORDER_UP_STRETCHY;
break;
default:
gBattleAnimArgs[ARG_RET_ID] = ANIM_ORDER_UP_NONE;
break;
}
DestroyAnimVisualTask(taskId);
}

View File

@ -11,7 +11,6 @@
static void AnimTask_Rollout_Step(u8 taskId);
static void AnimRolloutParticle(struct Sprite *);
static void AnimRockTomb(struct Sprite *);
static void AnimRockTomb_Step(struct Sprite *sprite);
static void AnimRockScatter(struct Sprite *);
static void AnimRockScatter_Step(struct Sprite *sprite);
@ -174,7 +173,7 @@ static const union AnimCmd sAnim_Rock_Smallest[] =
ANIMCMD_END,
};
static const union AnimCmd *const sAnims_BasicRock[] =
const union AnimCmd *const sAnims_BasicRock[] =
{
sAnim_Rock_Biggest,
sAnim_Rock_Bigger,
@ -378,7 +377,7 @@ static void AnimStealthRock(struct Sprite *sprite)
InitSpritePosToAnimAttacker(sprite, TRUE);
SetAverageBattlerPositions(gBattleAnimTarget, FALSE, &x, &y);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
sprite->data[0] = gBattleAnimArgs[4];
@ -454,7 +453,7 @@ void AnimRockFragment(struct Sprite *sprite)
StartSpriteAnim(sprite, gBattleAnimArgs[5]);
AnimateSprite(sprite);
if (GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->x -= gBattleAnimArgs[0];
else
sprite->x += gBattleAnimArgs[0];
@ -485,11 +484,7 @@ void AnimRockFragment(struct Sprite *sprite)
// args[6] - attacker or target
void AnimParticleInVortex(struct Sprite *sprite)
{
if (IsDoubleBattle()
&& (gAnimMoveIndex == MOVE_BLEAKWIND_STORM
|| gAnimMoveIndex == MOVE_SANDSEAR_STORM
|| gAnimMoveIndex == MOVE_SPRINGTIDE_STORM
|| gAnimMoveIndex == MOVE_WILDBOLT_STORM))
if (IsDoubleBattle() && GetMoveTarget(gAnimMoveIndex) == MOVE_TARGET_BOTH)
InitSpritePosToAnimTargetsCentre(sprite, FALSE);
else
InitSpritePosToAnimBattler(gBattleAnimArgs[6], sprite, FALSE);
@ -515,6 +510,11 @@ static void AnimParticleInVortex_Step(struct Sprite *sprite)
}
}
#define tBlendTimer data[10]
#define tBlend data[11]
#define tFullAlphaTimer data[11] // not a typo; this data field is used for multiple purposes
#define tState data[12]
void AnimTask_LoadSandstormBackground(u8 taskId)
{
int var0;
@ -539,7 +539,7 @@ void AnimTask_LoadSandstormBackground(u8 taskId)
AnimLoadCompressedBgTilemapHandleContest(&animBg, gBattleAnimBgTilemap_Sandstorm, FALSE);
LoadPalette(gBattleAnimSpritePal_FlyingDirt, BG_PLTT_ID(animBg.paletteId), PLTT_SIZE_4BPP);
if (gBattleAnimArgs[0] && GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (gBattleAnimArgs[0] && !IsOnPlayerSide(gBattleAnimAttacker))
var0 = 1;
gTasks[taskId].data[0] = var0;
@ -557,45 +557,45 @@ static void AnimTask_LoadSandstormBackground_Step(u8 taskId)
gBattle_BG1_Y += -1;
switch (gTasks[taskId].data[12])
switch (gTasks[taskId].tState)
{
case 0:
if (++gTasks[taskId].data[10] == 4)
if (++gTasks[taskId].tBlendTimer == 4)
{
gTasks[taskId].data[10] = 0;
gTasks[taskId].data[11]++;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[11], 16 - gTasks[taskId].data[11]));
if (gTasks[taskId].data[11] == 7)
gTasks[taskId].tBlendTimer = 0;
gTasks[taskId].tBlend++;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].tBlend, 16 - gTasks[taskId].tBlend));
if (gTasks[taskId].tBlend == 7)
{
gTasks[taskId].data[12]++;
gTasks[taskId].data[11] = 0;
gTasks[taskId].tState++;
gTasks[taskId].tFullAlphaTimer = 0;
}
}
break;
case 1:
if (++gTasks[taskId].data[11] == 101)
if (++gTasks[taskId].tFullAlphaTimer == 101)
{
gTasks[taskId].data[11] = 7;
gTasks[taskId].data[12]++;
gTasks[taskId].tBlend = 7;
gTasks[taskId].tState++;
}
break;
case 2:
if (++gTasks[taskId].data[10] == 4)
if (++gTasks[taskId].tBlendTimer == 4)
{
gTasks[taskId].data[10] = 0;
gTasks[taskId].data[11]--;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].data[11], 16 - gTasks[taskId].data[11]));
if (gTasks[taskId].data[11] == 0)
gTasks[taskId].tBlendTimer = 0;
gTasks[taskId].tBlend--;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(gTasks[taskId].tBlend, 16 - gTasks[taskId].tBlend));
if (gTasks[taskId].tBlend == 0)
{
gTasks[taskId].data[12]++;
gTasks[taskId].data[11] = 0;
gTasks[taskId].tState++;
gTasks[taskId].tFullAlphaTimer = 0;
}
}
break;
case 3:
GetBattleAnimBg1Data(&animBg);
ClearBattleAnimBg(animBg.bgId);
gTasks[taskId].data[12]++;
gTasks[taskId].tState++;
break;
case 4:
if (!IsContest())
@ -611,21 +611,36 @@ static void AnimTask_LoadSandstormBackground_Step(u8 taskId)
}
}
#undef tBlendTimer
#undef tBlend
#undef tFullAlphaTimer
#undef tState
// Animates the sprites that fly diagonally across the screen
// in Sandstorm and Heat Wave.
// arg 0: initial y pixel offset
// arg 1: projectile speed
// arg 2: y pixel drop
// arg 3: ??? unknown (possibly a color bit)
#define sState data[0]
#define sVelocityX data[1] // 256ths of a pixel // init'd from gBattleAnimArgs[1]
#define sVelocityY data[2] // 256ths of a pixel // init'd from gBattleAnimArgs[2]
#define sFractionalX data[3] // 256ths of a pixel
#define sFractionalY data[4] // 256ths of a pixel
#define sMirroredX data[5] // init'd from gBattleAnimArgs[3]
// The fields named "velocity" are arguably more like "acceleration,"
// and the fields named "fractional" are arguably more like "velocity."
//
// ...is what I WOULD say if the "fractional" fields weren't AND'd with
// 0xFF after every frame.
void AnimFlyingSandCrescent(struct Sprite *sprite)
{
if (sprite->data[0] == 0)
if (sprite->sState == 0)
{
if (gBattleAnimArgs[3] != 0 && GetBattlerSide(gBattleAnimAttacker) != B_SIDE_PLAYER)
if (gBattleAnimArgs[3] != 0 && !IsOnPlayerSide(gBattleAnimAttacker))
{
sprite->x = DISPLAY_WIDTH + 64;
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
sprite->data[5] = 1;
sprite->sMirroredX = 1;
sprite->oam.matrixNum = ST_OAM_HFLIP;
}
else
@ -635,18 +650,18 @@ void AnimFlyingSandCrescent(struct Sprite *sprite)
sprite->y = gBattleAnimArgs[0];
SetSubspriteTables(sprite, sFlyingSandSubspriteTable);
sprite->data[1] = gBattleAnimArgs[1];
sprite->data[2] = gBattleAnimArgs[2];
sprite->data[0]++;
sprite->sVelocityX = gBattleAnimArgs[1];
sprite->sVelocityY = gBattleAnimArgs[2];
sprite->sState++;
}
else
{
sprite->data[3] += sprite->data[1];
sprite->data[4] += sprite->data[2];
sprite->x2 += (sprite->data[3] >> 8);
sprite->y2 += (sprite->data[4] >> 8);
sprite->data[3] &= 0xFF;
sprite->data[4] &= 0xFF;
sprite->sFractionalX += sprite->sVelocityX;
sprite->sFractionalY += sprite->sVelocityY;
sprite->x2 += (sprite->sFractionalX >> 8);
sprite->y2 += (sprite->sFractionalY >> 8);
sprite->sFractionalX &= 0xFF;
sprite->sFractionalY &= 0xFF;
if (sprite->data[5] == 0)
{
@ -662,6 +677,13 @@ void AnimFlyingSandCrescent(struct Sprite *sprite)
}
}
#undef sState
#undef sVelocityX
#undef sVelocityY
#undef sFractionalX
#undef sFractionalY
#undef sMirroredX
// Animates the rising rocks in Ancient Power.
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
@ -737,10 +759,10 @@ void AnimTask_TectonicRageRollout(u8 taskId)
task = &gTasks[taskId];
var0 = GetBattlerSpriteCoord(gBattleAnimAttacker, 2);
var1 = GetBattlerSpriteCoord(gBattleAnimAttacker, 1) + 24;
var2 = GetBattlerSpriteCoord(gBattleAnimTarget, 2);
var3 = GetBattlerSpriteCoord(gBattleAnimTarget, 1) + 24;
var0 = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
var1 = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y) + 24;
var2 = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
var3 = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y) + 24;
if (BATTLE_PARTNER(gBattleAnimAttacker) == gBattleAnimTarget)
var3 = var1;
@ -912,7 +934,7 @@ static u8 GetRolloutCounter(void)
return retVal;
}
static void AnimRockTomb(struct Sprite *sprite)
void AnimRockTomb(struct Sprite *sprite)
{
StartSpriteAnim(sprite, gBattleAnimArgs[4]);
@ -947,7 +969,7 @@ static void AnimRockTomb_Step(struct Sprite *sprite)
void AnimRockBlastRock(struct Sprite *sprite)
{
if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT)
if (!IsOnPlayerSide(gBattleAnimAttacker))
StartSpriteAffineAnim(sprite, 1);
TranslateAnimSpriteToTargetMonLocation(sprite);
@ -1055,3 +1077,14 @@ const struct SpriteTemplate gSaltCureSwirlSpriteTemplate =
.affineAnims = gAffineAnims_Whirlpool,
.callback = AnimParticleInVortex,
};
const struct SpriteTemplate gRockPlumeSpriteTemplate =
{
.tileTag = ANIM_TAG_ROCKS,
.paletteTag = ANIM_TAG_ROCKS,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gAnims_FlyingRock,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimDirtPlumeParticle,
};

View File

@ -697,7 +697,7 @@ static void OakOldManHandlePrintString(u32 battler)
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
stringId = (u16 *)(&gBattleResources->bufferA[battler][2]);
if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL && *stringId == 1)
if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL && *stringId == STRINGID_INTROSENDOUT)
{
OakOldManBufferExecCompleted(battler);
}

View File

@ -456,31 +456,15 @@ static void OpponentHandleChooseMove(u32 battler)
target = GetBattlerAtPosition(Random() & 2);
} while (!CanTargetBattler(battler, target, move));
// Don't bother to loop through table if the move can't attack ally
// Don't bother to check if they're enemies if the move can't attack ally
if (B_WILD_NATURAL_ENEMIES == TRUE && !(GetBattlerMoveTargetType(battler, move) & MOVE_TARGET_BOTH))
{
u16 i, speciesAttacker, speciesTarget, isPartnerEnemy = FALSE;
static const u16 naturalEnemies[][2] =
{
// Attacker Target
{SPECIES_ZANGOOSE, SPECIES_SEVIPER},
{SPECIES_SEVIPER, SPECIES_ZANGOOSE},
{SPECIES_HEATMOR, SPECIES_DURANT},
{SPECIES_DURANT, SPECIES_HEATMOR},
{SPECIES_SABLEYE, SPECIES_CARBINK},
{SPECIES_MAREANIE, SPECIES_CORSOLA},
};
u32 speciesAttacker, speciesTarget;
speciesAttacker = gBattleMons[battler].species;
speciesTarget = gBattleMons[GetBattlerAtPosition(BATTLE_PARTNER(battler))].species;
for (i = 0; i < ARRAY_COUNT(naturalEnemies); i++)
{
if (speciesAttacker == naturalEnemies[i][0] && speciesTarget == naturalEnemies[i][1])
{
isPartnerEnemy = TRUE;
break;
}
}
bool32 isPartnerEnemy = IsNaturalEnemy(speciesAttacker, speciesTarget);
if (isPartnerEnemy && CanTargetBattler(battler, target, move))
BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, (chosenMoveIndex) | (GetBattlerAtPosition(BATTLE_PARTNER(battler)) << 8));
else
@ -524,6 +508,7 @@ static void OpponentHandleChoosePokemon(u32 battler)
{
s32 chosenMonId;
s32 pokemonInBattle = 1;
enum SwitchType switchType = SWITCH_AFTER_KO;
// Choosing Revival Blessing target
if (gBattleResources->bufferA[battler][1] == PARTY_ACTION_CHOOSE_FAINTED_MON)
@ -533,7 +518,9 @@ static void OpponentHandleChoosePokemon(u32 battler)
// Switching out
else if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE)
{
chosenMonId = GetMostSuitableMonToSwitchInto(battler, SWITCH_AFTER_KO);
if (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch)
switchType = SWITCH_MID_BATTLE;
chosenMonId = GetMostSuitableMonToSwitchInto(battler, switchType);
if (chosenMonId == PARTY_SIZE)
{
s32 battler1, battler2, firstId, lastId;

View File

@ -892,7 +892,10 @@ void HandleInputChooseMove(u32 battler)
}
else if (JOY_NEW(START_BUTTON))
{
if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE && !HasTrainerUsedGimmick(battler, gBattleStruct->gimmick.usableGimmick[battler]))
if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE
&& !HasTrainerUsedGimmick(battler, gBattleStruct->gimmick.usableGimmick[battler])
&& !(gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE
&& GetUsableZMove(battler, moveInfo->moves[gMoveSelectionCursor[battler]]) == MOVE_NONE))
{
gBattleStruct->gimmick.playerSelect ^= 1;
ReloadMoveNames(battler);
@ -1028,7 +1031,7 @@ void HandleMoveSwitching(u32 battler)
gBattleMons[battler].pp[i] = moveInfo->currentPp[i];
}
if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED))
if (!(gBattleMons[battler].volatiles.transformed))
{
for (i = 0; i < MAX_MON_MOVES; i++)
{
@ -1085,10 +1088,12 @@ void HandleMoveSwitching(u32 battler)
PlaySE(SE_SELECT);
MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
gBattlerControllerFuncs[battler] = OakOldManHandleInputChooseMove;
else
gBattlerControllerFuncs[battler] = HandleInputChooseMove;
if (B_SHOW_EFFECTIVENESS)
MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler);
else
@ -2084,7 +2089,7 @@ static void PlayerHandleChooseAction(u32 battler)
if (B_SHOW_PARTNER_TARGET && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && IsBattlerAlive(B_POSITION_PLAYER_RIGHT))
{
StringCopy(gStringVar1, COMPOUND_STRING("Partner will use:\n"));
u32 move = gBattleMons[B_POSITION_PLAYER_RIGHT].moves[gBattleStruct->chosenMovePositions[B_POSITION_PLAYER_RIGHT]];
u32 move = GetChosenMoveFromPosition(B_POSITION_PLAYER_RIGHT);
StringAppend(gStringVar1, GetMoveName(move));
u32 moveTarget = GetBattlerMoveTargetType(B_POSITION_PLAYER_RIGHT, move);
if (moveTarget == MOVE_TARGET_SELECTED)
@ -2430,7 +2435,7 @@ enum
static bool32 ShouldShowTypeEffectiveness(u32 targetId)
{
if (IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags))
if (IsGhostBattleWithoutScope())
return FALSE;
if (B_SHOW_EFFECTIVENESS == SHOW_EFFECTIVENESS_CAUGHT)
@ -2453,8 +2458,8 @@ static u32 CheckTypeEffectiveness(u32 battlerAtk, u32 battlerDef)
ctx.updateFlags = FALSE;
ctx.abilityAtk = GetBattlerAbility(battlerAtk);
ctx.abilityDef = GetBattlerAbility(battlerDef);
ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE);
ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk);
ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef);
uq4_12_t modifier = CalcTypeEffectivenessMultiplier(&ctx);

View File

@ -12,9 +12,11 @@
// #include "battle_tv.h"
#include "cable_club.h"
#include "event_object_movement.h"
#include "item.h"
#include "link.h"
#include "link_rfu.h"
#include "m4a.h"
#include "overworld.h"
#include "palette.h"
#include "party_menu.h"
#include "recorded_battle.h"
@ -26,6 +28,7 @@
#include "text.h"
#include "constants/abilities.h"
#include "constants/battle_string_ids.h"
#include "constants/item_effects.h"
#include "constants/songs.h"
#include "constants/sound.h"
#include "pokemon_animation.h"
@ -1057,24 +1060,20 @@ void BtlController_EmitExpUpdate(u32 battler, u32 bufferId, u8 partyId, s32 expP
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 6);
}
void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status1, u32 status2)
void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status)
{
gBattleResources->transferBuffer[0] = CONTROLLER_STATUSICONUPDATE;
gBattleResources->transferBuffer[1] = status1;
gBattleResources->transferBuffer[2] = (status1 & 0x0000FF00) >> 8;
gBattleResources->transferBuffer[3] = (status1 & 0x00FF0000) >> 16;
gBattleResources->transferBuffer[4] = (status1 & 0xFF000000) >> 24;
gBattleResources->transferBuffer[5] = status2;
gBattleResources->transferBuffer[6] = (status2 & 0x0000FF00) >> 8;
gBattleResources->transferBuffer[7] = (status2 & 0x00FF0000) >> 16;
gBattleResources->transferBuffer[8] = (status2 & 0xFF000000) >> 24;
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 9);
gBattleResources->transferBuffer[1] = status;
gBattleResources->transferBuffer[2] = (status & 0x0000FF00) >> 8;
gBattleResources->transferBuffer[3] = (status & 0x00FF0000) >> 16;
gBattleResources->transferBuffer[4] = (status & 0xFF000000) >> 24;
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 5);
}
void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 status2, u32 status)
void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 isVolatile, u32 status)
{
gBattleResources->transferBuffer[0] = CONTROLLER_STATUSANIMATION;
gBattleResources->transferBuffer[1] = status2;
gBattleResources->transferBuffer[1] = isVolatile;
gBattleResources->transferBuffer[2] = status;
gBattleResources->transferBuffer[3] = (status & 0x0000FF00) >> 8;
gBattleResources->transferBuffer[4] = (status & 0x00FF0000) >> 16;
@ -1399,7 +1398,7 @@ static u32 GetBattlerMonData(u32 battler, struct Pokemon *party, u32 monId, u8 *
u32 side = GetBattlerSide(battler);
u32 partyIndex = gBattlerPartyIndexes[battler];
if (TestRunner_Battle_GetForcedAbility(side, partyIndex))
gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex);
gBattleMons[battler].ability = TestRunner_Battle_GetForcedAbility(side, partyIndex);
}
#endif
break;
@ -1919,9 +1918,7 @@ void StartSendOutAnim(u32 battler, bool32 dontClearTransform, bool32 dontClearSu
ClearTemporarySpeciesSpriteData(battler, dontClearTransform, dontClearSubstituteBit);
gBattlerPartyIndexes[battler] = gBattleResources->bufferA[battler][1];
species = GetIllusionMonSpecies(battler);
if (species == SPECIES_NONE)
species = GetMonData(mon, MON_DATA_SPECIES);
species = GetBattlerVisualSpecies(battler);
gBattleControllerData[battler] = CreateInvisibleSpriteWithCallback(SpriteCB_WaitForBattlerBallReleaseAnim);
// Load sprite for opponent only, player sprite is expected to be already loaded.
if (!IsOnPlayerSide(battler))
@ -2081,6 +2078,7 @@ void Controller_WaitForHealthBar(u32 battler)
{
if (IsOnPlayerSide(battler))
HandleLowHpMusicChange(GetBattlerMon(battler), battler);
if (GetBattlerSide(battler) == B_SIDE_OPPONENT && !BtlCtrl_OakOldMan_TestState2Flag(1) && (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE))
{
BtlCtrl_OakOldMan_SetState2Flag(1);
@ -2266,11 +2264,11 @@ void BtlController_HandleLoadMonSprite(u32 battler)
{
u32 y;
struct Pokemon *mon = GetBattlerMon(battler);
u16 species = GetMonData(mon, MON_DATA_SPECIES);
u16 species = GetBattlerVisualSpecies(battler);
if (gBattleTypeFlags & BATTLE_TYPE_GHOST && GetBattlerSide(battler) == B_SIDE_OPPONENT)
{
DecompressGhostFrontPic(mon, battler);
DecompressGhostFrontPic(battler);
y = GetGhostSpriteDefault_Y(battler);
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = TRUE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = TRUE;
@ -2296,9 +2294,7 @@ void BtlController_HandleLoadMonSprite(u32 battler)
if (!(gBattleTypeFlags & BATTLE_TYPE_GHOST))
SetBattlerShadowSpriteCallback(battler, species);
if (IsControllerOpponent(battler)
&& IsControllerLinkOpponent(battler)
&& IsControllerRecordedOpponent(battler))
if (IsControllerOpponent(battler) || IsControllerLinkOpponent(battler) || IsControllerRecordedOpponent(battler))
gBattlerControllerFuncs[battler] = TryShinyAnimAfterMonAnim;
else if (IsControllerPokedude(battler))
gBattlerControllerFuncs[battler] = CompleteOnBattlerSpritePosX_0;
@ -2314,7 +2310,7 @@ void BtlController_HandleSwitchInAnim(u32 battler)
|| IsControllerLinkPartner(battler)
|| (IsControllerPokedude(battler) && GetBattlerSide(battler) == B_SIDE_PLAYER));
if (IsControllerPlayer(battler) || IsControllerPokedude(battler))
if (IsControllerPlayer(battler))
{
gActionSelectionCursor[battler] = 0;
gMoveSelectionCursor[battler] = 0;
@ -2566,7 +2562,7 @@ void BtlController_HandlePrintString(u32 battler)
BattlePutTextOnWindow(gDisplayedStringBattle, (B_WIN_MSG | B_TEXT_FLAG_NPC_CONTEXT_FONT));
else
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && GetBattlerSide(battler) == B_SIDE_OPPONENT)
{
switch (*stringId)
@ -2579,6 +2575,7 @@ void BtlController_HandlePrintString(u32 battler)
return;
}
}
gBattlerControllerFuncs[battler] = Controller_WaitForString;
}
@ -2936,6 +2933,15 @@ void BtlController_HandleBattleAnimation(u32 battler)
}
}
void AnimateMonAfterPokeBallFail(u32 battler)
{
if (B_ANIMATE_MON_AFTER_FAILED_POKEBALL == FALSE)
return;
LaunchKOAnimation(battler, ReturnAnimIdForBattler(TRUE, battler), TRUE);
TryShinyAnimation(gBattlerTarget, GetBattlerMon(gBattlerTarget));
}
static void AnimateMonAfterKnockout(u32 battler)
{
if (B_ANIMATE_MON_AFTER_KO == FALSE)
@ -2957,6 +2963,8 @@ static void LaunchKOAnimation(u32 battlerId, u16 animId, bool32 isFront)
u32 species = GetBattlerVisualSpecies(battlerId);
u32 spriteId = gBattlerSpriteIds[battlerId];
gBattleStruct->battlerKOAnimsRunning++;
if (isFront)
{
LaunchAnimationTaskForFrontSprite(&gSprites[spriteId], animId);
@ -2986,19 +2994,19 @@ void TrySetBattlerShadowSpriteCallback(u32 battler)
if (gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteIdPrimary].callback == SpriteCallbackDummy
&& (B_ENEMY_MON_SHADOW_STYLE <= GEN_3 || P_GBA_STYLE_SPECIES_GFX == TRUE
|| gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteIdSecondary].callback == SpriteCallbackDummy))
SetBattlerShadowSpriteCallback(battler, GetMonData(GetBattlerMon(battler), MON_DATA_SPECIES));
SetBattlerShadowSpriteCallback(battler, GetBattlerVisualSpecies(battler));
}
void TryShinyAnimAfterMonAnim(u32 battler)
{
if (gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].x2 == 0)
if (gSprites[gBattlerSpriteIds[battler]].x2 == 0)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim)
{
TryShinyAnimation(battler, GetBattlerMon(battler));
}
else if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
{
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
@ -3143,3 +3151,51 @@ void BtlController_HandleSwitchInTryShinyAnim(u32 battler)
}
}
}
void UpdateFriendshipFromXItem(u32 battler)
{
struct Pokemon *party = GetBattlerParty(battler);
u8 friendship;
gBattleResources->bufferA[battler][1] = REQUEST_FRIENDSHIP_BATTLE;
GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], &friendship);
u16 heldItem;
gBattleResources->bufferA[battler][1] = REQUEST_HELDITEM_BATTLE;
GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], (u8*)&heldItem);
if (friendship < X_ITEM_MAX_FRIENDSHIP)
{
if (GetItemHoldEffect(heldItem) == HOLD_EFFECT_FRIENDSHIP_UP)
friendship += 150 * X_ITEM_FRIENDSHIP_INCREASE / 100;
else
friendship += X_ITEM_FRIENDSHIP_INCREASE;
u8 pokeball;
gBattleResources->bufferA[battler][1] = REQUEST_POKEBALL_BATTLE;
GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], &pokeball);
if (pokeball == BALL_LUXURY)
friendship++;
u8 metLocation;
gBattleResources->bufferA[battler][1] = REQUEST_MET_LOCATION_BATTLE;
GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], &metLocation);
if (metLocation == GetCurrentRegionMapSectionId())
friendship++;
if (friendship > MAX_FRIENDSHIP)
friendship = MAX_FRIENDSHIP;
gBattleMons[battler].friendship = friendship;
gBattleResources->bufferA[battler][3] = friendship;
gBattleResources->bufferA[battler][1] = REQUEST_FRIENDSHIP_BATTLE;
SetBattlerMonData(battler, GetBattlerParty(battler), gBattlerPartyIndexes[battler]);
}
}
bool32 ShouldBattleRestrictionsApply(u32 battler)
{
return IsControllerPlayer(battler);
}

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ static const struct GMaxMove sGMaxMoveTable[] =
bool32 CanDynamax(u32 battler)
{
u16 species = GetBattlerVisualSpecies(battler);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler);
// Prevents Zigzagoon from dynamaxing in vanilla.
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && !IsOnPlayerSide(battler))
@ -181,14 +181,14 @@ void ActivateDynamax(u32 battler)
gBattleStruct->dynamax.dynamaxTurns[battler] = gBattleTurnCounter + DYNAMAX_TURNS_COUNT;
// Substitute is removed upon Dynamaxing.
gBattleMons[battler].status2 &= ~STATUS2_SUBSTITUTE;
gBattleMons[battler].volatiles.substitute = FALSE;
ClearBehindSubstituteBit(battler);
// Choiced Moves are reset upon Dynamaxing.
gBattleStruct->choicedMove[battler] = MOVE_NONE;
// Try Gigantamax form change.
if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) // Ditto cannot Gigantamax.
if (!gBattleMons[battler].volatiles.transformed) // Ditto cannot Gigantamax.
TryBattleFormChange(battler, FORM_CHANGE_BATTLE_GIGANTAMAX);
BattleScriptExecute(BattleScript_DynamaxBegins);
@ -234,21 +234,6 @@ bool32 IsMoveBlockedByMaxGuard(u32 move)
return FALSE;
}
// Weight-based moves (and some other moves in Raids) are blocked by Dynamax.
bool32 IsMoveBlockedByDynamax(u32 move)
{
// TODO: Certain moves are banned in raids.
switch (GetMoveEffect(move))
{
case EFFECT_HEAT_CRASH:
case EFFECT_LOW_KICK:
return TRUE;
default:
break;
}
return FALSE;
}
static u16 GetTypeBasedMaxMove(u32 battler, u32 type)
{
// Gigantamax check

View File

@ -163,14 +163,14 @@ static bool32 HandleEndTurnVarious(u32 battler)
for (i = 0; i < gBattlersCount; i++)
{
if (gStatuses3[i] & STATUS3_ALWAYS_HITS)
gStatuses3[i] -= STATUS3_ALWAYS_HITS_TURN(1);
if (gBattleMons[i].volatiles.lockOn > 0)
gBattleMons[i].volatiles.lockOn--;
if (gDisableStructs[i].chargeTimer && --gDisableStructs[i].chargeTimer == 0)
gStatuses3[i] &= ~STATUS3_CHARGED_UP;
gBattleMons[i].volatiles.charge = FALSE;
if (gStatuses3[i] & STATUS3_LASER_FOCUS && gDisableStructs[i].laserFocusTimer == gBattleTurnCounter)
gStatuses3[i] &= ~STATUS3_LASER_FOCUS;
if (gBattleMons[i].volatiles.laserFocus && gDisableStructs[i].laserFocusTimer == gBattleTurnCounter)
gBattleMons[i].volatiles.laserFocus = FALSE;
gBattleStruct->hpBefore[i] = gBattleMons[i].hp;
}
@ -188,7 +188,7 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler)
{
bool32 effect = FALSE;
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
u32 currBattleWeather = GetCurrentBattleWeather();
if (currBattleWeather == 0xFF)
@ -232,9 +232,10 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler)
&& ability != ABILITY_SAND_FORCE
&& ability != ABILITY_SAND_RUSH
&& ability != ABILITY_OVERCOAT
&& !IS_BATTLER_ANY_TYPE(gBattlerAttacker, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)
&& !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES
&& !IS_BATTLER_ANY_TYPE(battler, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER
&& GetBattlerHoldEffect(battler) != HOLD_EFFECT_SAFETY_GOGGLES
&& !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD))
{
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16;
@ -257,8 +258,9 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler)
if (ability != ABILITY_SNOW_CLOAK
&& ability != ABILITY_OVERCOAT
&& !IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
&& !(gStatuses3[battler] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER
&& GetBattlerHoldEffect(battler) != HOLD_EFFECT_SAFETY_GOGGLES
&& !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD))
{
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16;
@ -292,7 +294,7 @@ static bool32 HandleEndTurnGenThreeBerryActivation(u32 battler)
static bool32 HandleEndTurnEmergencyExit(u32 battler)
{
bool32 effect = FALSE;
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
gBattleStruct->turnEffectsBattlerId++;
@ -306,7 +308,7 @@ static bool32 HandleEndTurnEmergencyExit(u32 battler)
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
&& CountUsablePartyMons(battler) > 0
&& !(gStatuses3[battler] & STATUS3_SKY_DROPPED)) // Not currently held by Sky Drop
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) // Not currently held by Sky Drop
{
gBattlerAbility = battler;
gLastUsedAbility = ability;
@ -407,7 +409,7 @@ static bool32 HandleEndTurnWish(u32 battler)
}
gBattleStruct->moveDamage[battler] *= -1;
if (gStatuses3[battler] & STATUS3_HEAL_BLOCK)
if (gBattleMons[battler].volatiles.healBlock)
BattleScriptExecute(BattleScript_WishButHealBlocked);
else if (gBattleMons[battler].hp == gBattleMons[battler].maxHP)
BattleScriptExecute(BattleScript_WishButFullHp);
@ -423,17 +425,22 @@ static bool32 HandleEndTurnWish(u32 battler)
static bool32 HandleEndTurnFirstEventBlock(u32 battler)
{
bool32 effect = FALSE;
u32 side;
if (!IsBattlerAlive(battler))
{
gBattleStruct->eventBlockCounter = 0;
gBattleStruct->turnEffectsBattlerId++;
return effect;
}
switch (gBattleStruct->eventBlockCounter)
{
case FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL: // TODO: Has to be split into 3 statuses and needs a queue
side = GetBattlerSide(battler);
if (gSideStatuses[side] & SIDE_STATUS_DAMAGE_NON_TYPES)
{
if (IsBattlerAlive(battler)
&& !IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType)
if (!IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
gBattlerAttacker = battler;
@ -446,7 +453,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleStruct->eventBlockCounter++;
break;
case FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE:
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE && IsBattlerAlive(battler))
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE)
{
gBattlerAttacker = battler;
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8;
@ -458,21 +465,21 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleStruct->eventBlockCounter++;
break;
case FIRST_EVENT_BLOCK_THRASH:
if (gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE && !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
if (gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
{
gBattleMons[battler].status2 -= STATUS2_LOCK_CONFUSE_TURN(1);
gBattleMons[battler].volatiles.lockConfusionTurns--;
if (WasUnableToUseMove(battler))
{
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
}
else if (!(gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) && (gBattleMons[battler].status2 & STATUS2_MULTIPLETURNS))
else if (!gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.multipleTurns)
{
gBattleMons[battler].status2 &= ~STATUS2_MULTIPLETURNS;
if (!(gBattleMons[battler].status2 & STATUS2_CONFUSION))
gBattleMons[battler].volatiles.multipleTurns = FALSE;
if (!gBattleMons[battler].volatiles.confusionTurns)
{
gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION;
SetMoveEffect(battler, battler, TRUE, FALSE);
if (gBattleMons[battler].status2 & STATUS2_CONFUSION)
if (gBattleMons[battler].volatiles.confusionTurns)
BattleScriptExecute(BattleScript_ThrashConfuses);
effect = TRUE;
}
@ -481,10 +488,16 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleStruct->eventBlockCounter++;
break;
case FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL:
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerAlive(battler) && !IsBattlerAtMaxHp(battler) && IsBattlerGrounded(battler))
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN
&& !IsBattlerAtMaxHp(battler)
&& !gBattleMons[battler].volatiles.healBlock
&& !IsSemiInvulnerable(battler, CHECK_ALL)
&& IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler)))
{
gBattlerAttacker = battler;
gBattleStruct->moveDamage[battler] = -(GetNonDynamaxMaxHP(battler) / 16);
if (gBattleStruct->moveDamage[battler] == 0)
gBattleStruct->moveDamage[battler] = -1;
BattleScriptExecute(BattleScript_GrassyTerrainHeals);
effect = TRUE;
}
@ -492,7 +505,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
break;
case FIRST_EVENT_BLOCK_ABILITIES:
{
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
switch (ability)
{
case ABILITY_HEALER:
@ -501,28 +514,19 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE))
effect = TRUE;
break;
default:
break;
}
gBattleStruct->eventBlockCounter++;
break;
}
case FIRST_EVENT_BLOCK_HEAL_ITEMS:
{
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
switch (holdEffect)
{
case HOLD_EFFECT_LEFTOVERS:
case HOLD_EFFECT_BLACK_SLUDGE:
if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler))
effect = TRUE;
break;
default:
break;
}
if (ItemBattleEffects(ITEMEFFECT_LEFTOVERS, battler))
effect = TRUE;
gBattleStruct->eventBlockCounter = 0;
gBattleStruct->turnEffectsBattlerId++;
break;
}
}
return effect;
}
@ -533,8 +537,8 @@ static bool32 HandleEndTurnAquaRing(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_AQUA_RING
&& !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)
if (gBattleMons[battler].volatiles.aquaRing
&& !gBattleMons[battler].volatiles.healBlock
&& !IsBattlerAtMaxHp(battler)
&& IsBattlerAlive(battler))
{
@ -552,8 +556,8 @@ static bool32 HandleEndTurnIngrain(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_ROOTED
&& !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)
if (gBattleMons[battler].volatiles.root
&& !gBattleMons[battler].volatiles.healBlock
&& !IsBattlerAtMaxHp(battler)
&& IsBattlerAlive(battler))
{
@ -571,24 +575,24 @@ static bool32 HandleEndTurnLeechSeed(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_LEECHSEED
&& IsBattlerAlive(gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER)
if (gBattleMons[battler].volatiles.leechSeed
&& IsBattlerAlive(gBattleMons[battler].volatiles.leechSeed - 1)
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
gBattlerTarget = gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver.
gBattlerTarget = gBattleMons[battler].volatiles.leechSeed - 1; // leech seed receiver
gBattleScripting.animArg1 = gBattlerTarget;
gBattleScripting.animArg2 = gBattlerAttacker;
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(battler) / 8);
gBattleStruct->moveDamage[gBattlerTarget] = GetDrainedBigRootHp(gBattlerTarget, gBattleStruct->moveDamage[gBattlerAttacker]);
gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE;
gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE;
if (GetBattlerAbility(battler) == ABILITY_LIQUID_OOZE)
{
gBattleStruct->moveDamage[gBattlerTarget] = gBattleStruct->moveDamage[gBattlerTarget] * -1;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LEECH_SEED_OOZE;
BattleScriptExecute(BattleScript_LeechSeedTurnDrainLiquidOoze);
}
else if (gStatuses3[gBattlerTarget] & STATUS3_HEAL_BLOCK)
else if (gBattleMons[gBattlerTarget].volatiles.healBlock)
{
BattleScriptExecute(BattleScript_LeechSeedTurnDrainHealBlock);
}
@ -607,7 +611,7 @@ static bool32 HandleEndTurnPoison(u32 battler)
{
bool32 effect = FALSE;
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
gBattleStruct->turnEffectsBattlerId++;
@ -617,7 +621,7 @@ static bool32 HandleEndTurnPoison(u32 battler)
{
if (ability == ABILITY_POISON_HEAL)
{
if (!IsBattlerAtMaxHp(battler) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
if (!IsBattlerAtMaxHp(battler) && !gBattleMons[battler].volatiles.healBlock)
{
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8;
if (gBattleStruct->moveDamage[battler] == 0)
@ -655,7 +659,7 @@ static bool32 HandleEndTurnBurn(u32 battler)
{
bool32 effect = FALSE;
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
gBattleStruct->turnEffectsBattlerId++;
@ -705,7 +709,7 @@ static bool32 HandleEndTurnNightmare(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE
if (gBattleMons[battler].volatiles.nightmare
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
@ -719,7 +723,7 @@ static bool32 HandleEndTurnNightmare(u32 battler)
}
else
{
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
gBattleMons[battler].volatiles.nightmare = FALSE;
}
}
@ -732,7 +736,7 @@ static bool32 HandleEndTurnCurse(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gBattleMons[battler].status2 & STATUS2_CURSED
if (gBattleMons[battler].volatiles.cursed
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
@ -752,10 +756,11 @@ static bool32 HandleEndTurnWrap(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gBattleMons[battler].status2 & STATUS2_WRAPPED && IsBattlerAlive(battler))
if (gBattleMons[battler].volatiles.wrapped && IsBattlerAlive(battler))
{
if (--gDisableStructs[battler].wrapTurns != 0)
if (gDisableStructs[battler].wrapTurns != 0)
{
gDisableStructs[battler].wrapTurns--;
if (IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
return effect;
@ -763,7 +768,7 @@ static bool32 HandleEndTurnWrap(u32 battler)
gBattleScripting.animArg2 = gBattleStruct->wrappedMove[battler] >> 8;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]);
BattleScriptExecute(BattleScript_WrapTurnDmg);
if (GetBattlerHoldEffect(gBattleStruct->wrappedBy[battler], TRUE) == HOLD_EFFECT_BINDING_BAND)
if (GetBattlerHoldEffect(gBattleStruct->wrappedBy[battler]) == HOLD_EFFECT_BINDING_BAND)
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8);
else
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16);
@ -773,7 +778,7 @@ static bool32 HandleEndTurnWrap(u32 battler)
}
else // broke free
{
gBattleMons[battler].status2 &= ~STATUS2_WRAPPED;
gBattleMons[battler].volatiles.wrapped = FALSE;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]);
BattleScriptExecute(BattleScript_WrapEnds);
}
@ -789,7 +794,7 @@ static bool32 HandleEndTurnSaltCure(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses4[battler] & STATUS4_SALT_CURE
if (gBattleMons[battler].volatiles.saltCure
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
@ -830,10 +835,10 @@ static bool32 HandleEndTurnSyrupBomb(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if ((gStatuses4[battler] & STATUS4_SYRUP_BOMB) && (IsBattlerAlive(battler)))
if (gBattleMons[battler].volatiles.syrupBomb && (IsBattlerAlive(battler)))
{
if (gDisableStructs[battler].syrupBombTimer > 0 && --gDisableStructs[battler].syrupBombTimer == 0)
gStatuses4[battler] &= ~STATUS4_SYRUP_BOMB;
gBattleMons[battler].volatiles.syrupBomb = FALSE;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SYRUP_BOMB);
gBattlescriptCurrInstr = BattleScript_SyrupBombEndTurn;
BattleScriptExecute(gBattlescriptCurrInstr);
@ -867,7 +872,7 @@ static bool32 HandleEndTurnTorment(u32 battler)
if (gDisableStructs[battler].tormentTimer == gBattleTurnCounter)
{
gBattleMons[battler].status2 &= ~STATUS2_TORMENT;
gBattleMons[battler].volatiles.torment = FALSE;
BattleScriptExecute(BattleScript_TormentEnds);
effect = TRUE;
}
@ -937,9 +942,9 @@ static bool32 HandleEndTurnMagnetRise(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_MAGNET_RISE && gDisableStructs[battler].magnetRiseTimer == gBattleTurnCounter)
if (gBattleMons[battler].volatiles.magnetRise && gDisableStructs[battler].magnetRiseTimer == gBattleTurnCounter)
{
gStatuses3[battler] &= ~STATUS3_MAGNET_RISE;
gBattleMons[battler].volatiles.magnetRise = FALSE;
BattleScriptExecute(BattleScript_BufferEndTurn);
PREPARE_STRING_BUFFER(gBattleTextBuff1, STRINGID_ELECTROMAGNETISM);
effect = TRUE;
@ -954,9 +959,9 @@ static bool32 HandleEndTurnTelekinesis(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_TELEKINESIS && gDisableStructs[battler].telekinesisTimer == gBattleTurnCounter)
if (gBattleMons[battler].volatiles.telekinesis && gDisableStructs[battler].telekinesisTimer == gBattleTurnCounter)
{
gStatuses3[battler] &= ~STATUS3_TELEKINESIS;
gBattleMons[battler].volatiles.telekinesis = FALSE;
BattleScriptExecute(BattleScript_TelekinesisEndTurn);
effect = TRUE;
}
@ -970,9 +975,9 @@ static bool32 HandleEndTurnHealBlock(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_HEAL_BLOCK && gDisableStructs[battler].healBlockTimer == gBattleTurnCounter)
if (gBattleMons[battler].volatiles.healBlock && gDisableStructs[battler].healBlockTimer == gBattleTurnCounter)
{
gStatuses3[battler] &= ~STATUS3_HEAL_BLOCK;
gBattleMons[battler].volatiles.healBlock = FALSE;
BattleScriptExecute(BattleScript_BufferEndTurn);
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_HEAL_BLOCK);
effect = TRUE;
@ -987,9 +992,9 @@ static bool32 HandleEndTurnEmbargo(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_EMBARGO && gDisableStructs[battler].embargoTimer == gBattleTurnCounter)
if (gBattleMons[battler].volatiles.embargo && gDisableStructs[battler].embargoTimer == gBattleTurnCounter)
{
gStatuses3[battler] &= ~STATUS3_EMBARGO;
gBattleMons[battler].volatiles.embargo = FALSE;
BattleScriptExecute(BattleScript_EmbargoEndTurn);
effect = TRUE;
}
@ -1001,34 +1006,43 @@ static bool32 HandleEndTurnYawn(u32 battler)
{
bool32 effect = FALSE;
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses3[battler] & STATUS3_YAWN)
if (gBattleMons[battler].volatiles.yawn > 0)
{
gStatuses3[battler] -= STATUS3_YAWN_TURN(1);
if (!(gStatuses3[battler] & STATUS3_YAWN) && !(gBattleMons[battler].status1 & STATUS1_ANY)
gBattleMons[battler].volatiles.yawn--;
if (!gBattleMons[battler].volatiles.yawn
&& !(gBattleMons[battler].status1 & STATUS1_ANY)
&& ability != ABILITY_VITAL_SPIRIT
&& ability != ABILITY_INSOMNIA
&& !UproarWakeUpCheck(battler)
&& !IsLeafGuardProtected(battler, ability))
{
CancelMultiTurnMoves(battler, SKY_DROP_STATUS_YAWN);
gEffectBattler = gBattlerTarget = battler;
if (IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler);
if (IsBattlerTerrainAffected(battler, ability, holdEffect, STATUS_FIELD_ELECTRIC_TERRAIN))
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_ELECTRIC;
BattleScriptExecute(BattleScript_TerrainPreventsEnd2);
}
else if (IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
else if (IsBattlerTerrainAffected(battler, ability, holdEffect, STATUS_FIELD_MISTY_TERRAIN))
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_MISTY;
BattleScriptExecute(BattleScript_TerrainPreventsEnd2);
}
else if (IsSleepClauseActiveForSide(GetBattlerSide(battler)))
{
BattleScriptExecute(BattleScript_SleepClausePreventsEnd);
BattleScriptExecute(BattleScript_SleepClausePreventsEnd2);
}
else if ((gBattleScripting.battler = IsAbilityOnSide(battler, ABILITY_SWEET_VEIL)))
{
gBattleScripting.battler--;
gLastUsedAbility = ABILITY_SWEET_VEIL;
gBattlerAbility = gBattleScripting.battler;
RecordAbilityBattle(gBattleScripting.battler, ABILITY_SWEET_VEIL);
BattleScriptExecute(BattleScript_ImmunityProtectedEnd2);
}
else
{
@ -1037,10 +1051,11 @@ static bool32 HandleEndTurnYawn(u32 battler)
else
gBattleMons[battler].status1 |= ((Random() % 4) + 3);
CancelMultiTurnMoves(battler, SKY_DROP_STATUS_YAWN);
TryActivateSleepClause(battler, gBattlerPartyIndexes[battler]);
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
BattleScriptExecute(BattleScript_YawnMakesAsleep);
BattleScriptExecute(BattleScript_YawnMakesAsleepEnd2);
}
effect = TRUE;
}
@ -1055,12 +1070,12 @@ static bool32 HandleEndTurnPerishSong(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (IsBattlerAlive(battler) && gStatuses3[battler] & STATUS3_PERISH_SONG)
if (IsBattlerAlive(battler) && gBattleMons[battler].volatiles.perishSong)
{
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[battler].perishSongTimer);
if (gDisableStructs[battler].perishSongTimer == 0)
{
gStatuses3[battler] &= ~STATUS3_PERISH_SONG;
gBattleMons[battler].volatiles.perishSong = FALSE;
gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp;
BattleScriptExecute(BattleScript_PerishSongTakesLife);
}
@ -1349,39 +1364,36 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
switch (gBattleStruct->eventBlockCounter)
{
case THIRD_EVENT_BLOCK_UPROAR:
if (gBattleMons[battler].status2 & STATUS2_UPROAR)
if (gBattleMons[battler].volatiles.uproarTurns)
{
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++)
for (gEffectBattler = 0; gEffectBattler < gBattlersCount; gEffectBattler++)
{
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF)
if ((gBattleMons[gEffectBattler].status1 & STATUS1_SLEEP)
&& GetBattlerAbility(gEffectBattler) != ABILITY_SOUNDPROOF)
{
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP;
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
gBattleMons[gEffectBattler].status1 &= ~STATUS1_SLEEP;
gBattleMons[gEffectBattler].volatiles.nightmare = FALSE;
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
BattleScriptExecute(BattleScript_MonWokeUpInUproar);
BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1);
MarkBattlerForControllerExec(gBattlerAttacker);
BtlController_EmitSetMonData(gEffectBattler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1);
MarkBattlerForControllerExec(gEffectBattler);
effect = TRUE;
break;
}
}
if (gBattlerAttacker != gBattlersCount)
{
break;
}
else
if (effect == FALSE)
{
gBattlerAttacker = battler;
gBattleMons[battler].status2 -= STATUS2_UPROAR_TURN(1); // uproar timer goes down
gBattleMons[battler].volatiles.uproarTurns--; // uproar timer goes down
if (WasUnableToUseMove(battler))
{
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS;
}
else if (gBattleMons[battler].status2 & STATUS2_UPROAR)
else if (gBattleMons[battler].volatiles.uproarTurns)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_CONTINUES;
gBattleMons[battler].status2 |= STATUS2_MULTIPLETURNS;
gBattleMons[battler].volatiles.multipleTurns = TRUE;
}
else
{
@ -1396,7 +1408,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
break;
case THIRD_EVENT_BLOCK_ABILITIES:
{
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
switch (ability)
{
case ABILITY_TRUANT: // Not fully accurate but it has to be handled somehow. TODO: Find a better way.
@ -1411,13 +1423,15 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE))
effect = TRUE;
break;
default:
break;
}
gBattleStruct->eventBlockCounter++;
break;
}
case THIRD_EVENT_BLOCK_ITEMS:
{
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler);
switch (holdEffect)
{
case HOLD_EFFECT_FLAME_ORB:
@ -1427,7 +1441,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
effect = TRUE;
break;
case HOLD_EFFECT_WHITE_HERB:
if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler))
if (ItemBattleEffects(ITEMEFFECT_WHITE_HERB_ENDTURN, battler))
effect = TRUE;
break;
default:
@ -1446,7 +1460,7 @@ static bool32 HandleEndTurnAbilities(u32 battler)
{
bool32 effect = FALSE;
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
gBattleStruct->turnEffectsBattlerId++;
@ -1458,6 +1472,8 @@ static bool32 HandleEndTurnAbilities(u32 battler)
case ABILITY_ZEN_MODE:
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE))
effect = TRUE;
default:
break;
}
return effect;
@ -1471,7 +1487,7 @@ static bool32 HandleEndTurnFourthEventBlock(u32 battler)
{
case FOURTH_EVENT_BLOCK_HUNGER_SWITCH:
{
u32 ability = GetBattlerAbility(battler);
enum Ability ability = GetBattlerAbility(battler);
if (ability == ABILITY_HUNGER_SWITCH)
{
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE))
@ -1482,7 +1498,7 @@ static bool32 HandleEndTurnFourthEventBlock(u32 battler)
}
case FOURTH_EVENT_BLOCK_EJECT_PACK:
{
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler);
if (holdEffect == HOLD_EFFECT_EJECT_PACK)
{
if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler))
@ -1514,6 +1530,19 @@ static bool32 HandleEndTurnDynamax(u32 battler)
return effect;
}
/*
* Various end turn effects that happen after all battlers moved.
* Each Case will apply the effects for each battler. Moving to the next case when all battlers are done.
* If an effect is going to be applied on a better, the bool effect will be set to TRUE and a script set.
* The script is set with `BattleScriptExecute` and should have the ending `end2`
Example:
BattleScriptExecute(BattleScript_X);
(in battle_scripts_1.s)
BattleScript_X:
some commands
end2
*/
static bool32 (*const sEndTurnEffectHandlers[])(u32 battler) =
{
[ENDTURN_ORDER] = HandleEndTurnOrder,

View File

@ -23,6 +23,7 @@
#include "data.h"
#include "palette.h"
// #include "contest.h"
#include "trainer_pokemon_sprites.h"
#include "constants/songs.h"
#include "constants/rgb.h"
// #include "constants/battle_palace.h"
@ -259,13 +260,15 @@ static void SpriteCB_TrainerSlideVertical(struct Sprite *sprite)
#undef sSpeedX
void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isStatus2, u32 status)
void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isVolatile, u32 status)
{
gBattleSpritesDataPtr->healthBoxesData[battler].statusAnimActive = 1;
if (!isStatus2)
if (!isVolatile)
{
if (status == STATUS1_FREEZE || status == STATUS1_FROSTBITE)
if (status == STATUS1_FREEZE)
LaunchStatusAnimation(battler, B_ANIM_STATUS_FRZ);
else if (status == STATUS1_FROSTBITE)
LaunchStatusAnimation(battler, B_ANIM_STATUS_FRB);
else if (status == STATUS1_POISON || status & STATUS1_TOXIC_POISON)
LaunchStatusAnimation(battler, B_ANIM_STATUS_PSN);
else if (status == STATUS1_BURN)
@ -279,13 +282,13 @@ void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isStatus2, u32 statu
}
else
{
if (status & STATUS2_INFATUATION)
if (status == VOLATILE_INFATUATION)
LaunchStatusAnimation(battler, B_ANIM_STATUS_INFATUATION);
else if (status & STATUS2_CONFUSION)
else if (status == VOLATILE_CONFUSION)
LaunchStatusAnimation(battler, B_ANIM_STATUS_CONFUSION);
else if (status & STATUS2_CURSED)
else if (status == VOLATILE_CURSED)
LaunchStatusAnimation(battler, B_ANIM_STATUS_CURSED);
else if (status & STATUS2_NIGHTMARE)
else if (status == VOLATILE_NIGHTMARE)
LaunchStatusAnimation(battler, B_ANIM_STATUS_NIGHTMARE);
else // no animation
gBattleSpritesDataPtr->healthBoxesData[battler].statusAnimActive = 0;
@ -483,17 +486,6 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
}
}
void DecompressGhostFrontPic(struct Pokemon *unused, u8 battlerId)
{
u16 palOffset;
u8 position = GetBattlerPosition(battlerId);
DecompressDataWithHeaderWram(gGhostFrontPic, gMonSpritesGfxPtr->spritesGfx[position]);
palOffset = OBJ_PLTT_ID(battlerId);
LoadPalette(gGhostPalette, palOffset, PLTT_SIZE_4BPP);
LoadPalette(gGhostPalette, BG_PLTT_ID(8) + BG_PLTT_ID(battlerId), PLTT_SIZE_4BPP);
}
void BattleGfxSfxDummy2(u16 species)
{
}
@ -509,17 +501,11 @@ void DecompressTrainerFrontPic(u16 frontPicId, u8 battler)
void DecompressTrainerBackPic(u16 backPicId, u8 battler)
{
u8 position = GetBattlerPosition(battler);
DecompressPicFromTable(&gTrainerBacksprites[backPicId].backPic,
gMonSpritesGfxPtr->spritesGfx[position]);
CopyTrainerBackspriteFramesToDest(backPicId, gMonSpritesGfxPtr->spritesGfx[position]);
LoadPalette(gTrainerBacksprites[backPicId].palette.data,
OBJ_PLTT_ID(battler), PLTT_SIZE_4BPP);
}
void DecompressTrainerBackPalette(u16 index, u8 palette)
{
LoadPalette(gTrainerBacksprites[index].palette.data, OBJ_PLTT_ID2(palette), PLTT_SIZE_4BPP);
}
void FreeTrainerFrontPicPalette(u16 frontPicId)
{
FreeSpritePaletteByTag(gTrainerSprites[frontPicId].palette.tag);
@ -683,15 +669,8 @@ bool8 BattleInitAllSprites(u8 *state1, u8 *battler)
}
break;
case 5:
if (IsOnPlayerSide(*battler))
{
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
UpdateHealthboxAttribute(gHealthboxSpriteIds[*battler], GetBattlerMon(*battler), HEALTHBOX_ALL);
}
else
{
if (!IsOnPlayerSide(*battler) || !(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
UpdateHealthboxAttribute(gHealthboxSpriteIds[*battler], GetBattlerMon(*battler), HEALTHBOX_ALL);
}
SetHealthboxSpriteInvisible(gHealthboxSpriteIds[*battler]);
(*battler)++;
if (*battler == gBattlersCount)
@ -764,7 +743,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
{
// Get base form if its currently Gigantamax
if (IsGigantamaxed(battlerDef))
targetSpecies = gBattleStruct->changedSpecies[GetBattlerSide(battlerDef)][gBattlerPartyIndexes[battlerDef]];
targetSpecies = GetBattlerPartyState(battlerDef)->changedSpecies;
else if (gBattleStruct->illusion[battlerDef].state == ILLUSION_ON)
targetSpecies = GetIllusionMonSpecies(battlerDef);
else
@ -826,13 +805,6 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16));
}
// Terastallization's tint
if (GetActiveGimmick(battlerAtk) == GIMMICK_TERA)
{
BlendPalette(paletteOffset, 16, 8, GetTeraTypeRGB(GetBattlerTeraType(battlerAtk)));
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16));
}
gSprites[gBattlerSpriteIds[battlerAtk]].y = GetBattlerSpriteDefault_Y(battlerAtk);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], 0);
}
@ -991,7 +963,7 @@ void CreateEnemyShadowSprite(u32 battler)
{
if (B_ENEMY_MON_SHADOW_STYLE >= GEN_4 && P_GBA_STYLE_SPECIES_GFX == FALSE)
{
u16 species = SanitizeSpeciesId(gBattleMons[battler].species);
u16 species = GetBattlerVisualSpecies(battler);
u8 size = gSpeciesInfo[species].enemyShadowSize;
gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteIdPrimary = CreateSprite(&gSpriteTemplate_EnemyShadow,
@ -1095,8 +1067,8 @@ void SpriteCB_EnemyShadow(struct Sprite *shadowSprite)
}
else if (transformSpecies != SPECIES_NONE)
{
xOffset = gSpeciesInfo[transformSpecies].enemyShadowXOffset;
yOffset = gSpeciesInfo[transformSpecies].enemyShadowYOffset;
xOffset = gSpeciesInfo[transformSpecies].enemyShadowXOffset + (shadowSprite->tSpriteSide == SPRITE_SIDE_LEFT ? -16 : 16);
yOffset = gSpeciesInfo[transformSpecies].enemyShadowYOffset + 16;
size = gSpeciesInfo[transformSpecies].enemyShadowSize;
invisible = (B_ENEMY_MON_SHADOW_STYLE >= GEN_4 && P_GBA_STYLE_SPECIES_GFX == FALSE)
@ -1105,7 +1077,7 @@ void SpriteCB_EnemyShadow(struct Sprite *shadowSprite)
}
else if (B_ENEMY_MON_SHADOW_STYLE >= GEN_4 && P_GBA_STYLE_SPECIES_GFX == FALSE)
{
u16 species = SanitizeSpeciesId(gBattleMons[battler].species);
u16 species = GetBattlerVisualSpecies(battler);
xOffset = gSpeciesInfo[species].enemyShadowXOffset + (shadowSprite->tSpriteSide == SPRITE_SIDE_LEFT ? -16 : 16);
yOffset = gSpeciesInfo[species].enemyShadowYOffset + 16;
size = gSpeciesInfo[species].enemyShadowSize;
@ -1297,3 +1269,14 @@ bool32 ShouldPlayNormalMonCry(struct Pokemon *mon)
return TRUE;
}
void DecompressGhostFrontPic(u32 battlerId)
{
u16 palOffset;
u8 position = GetBattlerPosition(battlerId);
DecompressDataWithHeaderWram(gGhostFrontPic, gMonSpritesGfxPtr->spritesGfx[position]);
palOffset = OBJ_PLTT_ID(battlerId);
LoadPalette(gGhostPalette, palOffset, PLTT_SIZE_4BPP);
LoadPalette(gGhostPalette, BG_PLTT_ID(8) + BG_PLTT_ID(battlerId), PLTT_SIZE_4BPP);
}

View File

@ -2197,30 +2197,71 @@ static void SafariTextIntoHealthboxObject(void *dest, u8 *windowTileData, u32 wi
CpuCopy32(windowTileData + 256, dest + 256, windowWidth * TILE_SIZE_4BPP);
}
#define ABILITY_POP_UP_TAG 0xD720
#undef sBattlerId
// for sprite
#define tOriginalX data[0]
#define tHide data[1]
#define tFrames data[2]
#define tRightToLeft data[3]
#define tBattlerId data[4]
#define tIsMain data[5]
#define ABILITY_POP_UP_POS_X_DIFF 64
#define ABILITY_POP_UP_POS_X_SLIDE 128
#define ABILITY_POP_UP_POS_X_SPEED 4
// for task
#define tSpriteId1 data[6]
#define tSpriteId2 data[7]
#define ABILITY_POP_UP_WIN_WIDTH 10
#define ABILITY_POP_UP_STR_WIDTH (ABILITY_POP_UP_WIN_WIDTH * 8)
static const u8 ALIGNED(4) sAbilityPopUpGfx[] = INCBIN_U8("graphics/battle_interface/ability_pop_up.4bpp");
#define ABILITY_POP_UP_PLAYER_LEFT_WIN_W 6
#define ABILITY_POP_UP_PLAYER_RIGHT_WIN_W 4
#define ABILITY_POP_UP_OPPONENT_LEFT_WIN_W 7
#define ABILITY_POP_UP_OPPONENT_RIGHT_WIN_W 3
#define ABILITY_POP_UP_WAIT_FRAMES 48
/*
* BG = BackGround
* FG = ForeGround
* SH = SHadow
*/
#define ABILITY_POP_UP_BATTLER_BG_TXTCLR 2
#define ABILITY_POP_UP_BATTLER_FG_TXTCLR 7
#define ABILITY_POP_UP_BATTLER_SH_TXTCLR 1
#define ABILITY_POP_UP_ABILITY_BG_TXTCLR 7
#define ABILITY_POP_UP_ABILITY_FG_TXTCLR 9
#define ABILITY_POP_UP_ABILITY_SH_TXTCLR 1
#define sState data[0]
#define sAutoDestroy data[1]
#define sTimer data[2]
#define sIsPlayerSide data[3]
#define sBattlerId data[4]
#define sIsMain data[5]
enum
{
APU_STATE_SLIDE_IN = 0,
APU_STATE_IDLE,
APU_STATE_SLIDE_OUT,
APU_STATE_END
};
enum
{
TAG_ABILITY_POP_UP = 0xD720, // Only used for the SpritePalette, the rest below is for the SpriteSheets.
TAG_ABILITY_POP_UP_PLAYER1 = TAG_ABILITY_POP_UP,
TAG_ABILITY_POP_UP_OPPONENT1,
TAG_ABILITY_POP_UP_PLAYER2,
TAG_ABILITY_POP_UP_OPPONENT2,
TAG_LAST_BALL_WINDOW,
};
static const u32 sAbilityPopUpGfx[] = INCBIN_U32("graphics/battle_interface/ability_pop_up.4bpp");
static const u16 sAbilityPopUpPalette[] = INCBIN_U16("graphics/battle_interface/ability_pop_up.gbapal");
static const struct SpriteSheet sSpriteSheet_AbilityPopUp =
{
sAbilityPopUpGfx, sizeof(sAbilityPopUpGfx), ABILITY_POP_UP_TAG
sAbilityPopUpGfx, sizeof(sAbilityPopUpGfx), TAG_ABILITY_POP_UP
};
static const struct SpritePalette sSpritePalette_AbilityPopUp =
{
sAbilityPopUpPalette, ABILITY_POP_UP_TAG
sAbilityPopUpPalette, TAG_ABILITY_POP_UP
};
static const struct OamData sOamData_AbilityPopUp =
@ -2234,8 +2275,8 @@ static const struct OamData sOamData_AbilityPopUp =
static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp =
{
.tileTag = ABILITY_POP_UP_TAG,
.paletteTag = ABILITY_POP_UP_TAG,
.tileTag = TAG_NONE, // Changed on the fly.
.paletteTag = TAG_ABILITY_POP_UP,
.oam = &sOamData_AbilityPopUp,
.anims = gDummySpriteAnimTable,
.images = NULL,
@ -2243,279 +2284,150 @@ static const struct SpriteTemplate sSpriteTemplate_AbilityPopUp =
.callback = SpriteCb_AbilityPopUp
};
#define ABILITY_POP_UP_POS_X_DIFF (64 - 7) // Hide second sprite underneath to gain proper letter spacing
#define ABILITY_POP_UP_POS_X_SLIDE 68
static const s16 sAbilityPopUpCoordsDoubles[MAX_BATTLERS_COUNT][2] =
{
{29, 80}, // player left
{186, 19}, // opponent left
{29, 97}, // player right
{186, 36}, // opponent right
{ 24, 80}, // Player left
{178, 19}, // Opponent left
{ 24, 97}, // Player right
{178, 36}, // Opponent right
};
static const s16 sAbilityPopUpCoordsSingles[MAX_BATTLERS_COUNT][2] =
{
{29, 97}, // player
{186, 57}, // opponent
{ 24, 97}, // Player
{178, 57}, // Opponent
};
#define POPUP_WINDOW_WIDTH 8
#define MAX_POPUP_STRING_WIDTH (POPUP_WINDOW_WIDTH * 8)
static u8* AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 color1, u32 color2, u32 color3, u32 *windowId)
static u8 *AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 bgColor, u32 fgColor, u32 shadowColor, u32 *windowId)
{
u32 fontId;
u8 color[3] = {color1, color2, color3};
u8 color[3] = {bgColor, fgColor, shadowColor};
struct WindowTemplate winTemplate = {0};
winTemplate.width = POPUP_WINDOW_WIDTH;
winTemplate.width = ABILITY_POP_UP_WIN_WIDTH;
winTemplate.height = 2;
*windowId = AddWindow(&winTemplate);
FillWindowPixelBuffer(*windowId, PIXEL_FILL(color1));
FillWindowPixelBuffer(*windowId, PIXEL_FILL(bgColor));
fontId = GetFontIdToFit(str, FONT_SMALL, 0, 76);
fontId = GetFontIdToFit(str, FONT_SMALL, 0, ABILITY_POP_UP_STR_WIDTH);
AddTextPrinterParameterized4(*windowId, fontId, x, y, 0, 0, color, TEXT_SKIP_DRAW, str);
return (u8 *)(GetWindowAttribute(*windowId, WINDOW_TILE_DATA));
}
static void TextIntoAbilityPopUp(void *dest, u8 *windowTileData, s32 xTileAmount, bool32 arg3)
static void TextIntoAbilityPopUp(void *dest, u8 *windowTileData, s32 windowWidth, bool32 printNickname)
{
CpuCopy32(windowTileData + 256, dest + 256, xTileAmount * 32);
if (xTileAmount > 0)
#define PIXELS(n) (n * 4)
if (windowWidth > 0)
{
do
{
if (arg3)
CpuCopy32(windowTileData + 16, dest + 16, 16);
if (printNickname)
{
CpuCopy32(windowTileData + PIXELS(3), dest + PIXELS(3), PIXELS(5));
CpuCopy32(windowTileData + TILE_OFFSET_4BPP(ABILITY_POP_UP_WIN_WIDTH), dest + TILE_OFFSET_4BPP(8), PIXELS(5));
}
else
CpuCopy32(windowTileData + 20, dest + 20, 12);
dest += 32, windowTileData += 32;
xTileAmount--;
} while (xTileAmount != 0);
{
CpuCopy32(windowTileData + PIXELS(7), dest + PIXELS(7), PIXELS(1));
CpuCopy32(windowTileData + TILE_OFFSET_4BPP(ABILITY_POP_UP_WIN_WIDTH), dest + TILE_OFFSET_4BPP(8), TILE_SIZE_4BPP);
}
dest += TILE_SIZE_4BPP, windowTileData += TILE_SIZE_4BPP;
windowWidth--;
} while (windowWidth != 0);
}
#undef PIXELS
}
static void PrintOnAbilityPopUp(const u8 *str, u8 *spriteTileData1, u8 *spriteTileData2, u32 x1, u32 x2, u32 y, u32 color1, u32 color2, u32 color3)
static void PrintOnAbilityPopUp(const u8 *str, u8 *spriteTileData1, u8 *spriteTileData2, u32 x, u32 y, u32 bgColor, u32 fgColor, u32 shadowColor, u32 printNickname, u32 battler)
{
u32 windowId;
u8 *windowTileData;
u16 width;
u32 windowId, fontId;
u8 *windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x, y, bgColor, fgColor, shadowColor, &windowId);
u32 size1 = ABILITY_POP_UP_OPPONENT_LEFT_WIN_W, size2 = ABILITY_POP_UP_OPPONENT_RIGHT_WIN_W;
windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x1, y, color1, color2, color3, &windowId);
TextIntoAbilityPopUp(spriteTileData1, windowTileData, 8, (y == 0));
RemoveWindow(windowId);
width = GetStringWidth(FONT_SMALL, str, 0);
if (width > MAX_POPUP_STRING_WIDTH - 5)
spriteTileData1 += TILE_OFFSET_4BPP(1);
if (IsOnPlayerSide(battler))
{
windowTileData = AddTextPrinterAndCreateWindowOnAbilityPopUp(str, x2 - MAX_POPUP_STRING_WIDTH, y, color1, color2, color3, &windowId);
TextIntoAbilityPopUp(spriteTileData2, windowTileData, 3, (y == 0));
RemoveWindow(windowId);
size1 = ABILITY_POP_UP_PLAYER_LEFT_WIN_W, size2 = ABILITY_POP_UP_PLAYER_RIGHT_WIN_W;
// Increment again as the *first* column of the sprite
// is not shown for player's pop up when sliding in.
spriteTileData1 += TILE_OFFSET_4BPP(1);
}
}
static const u8 sText_Spaces20[]= _(" ");
static void ClearAbilityName(u8 spriteId1, u8 spriteId2)
{
PrintOnAbilityPopUp(sText_Spaces20,
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256,
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256,
5, 12,
4,
7, 9, 1);
TextIntoAbilityPopUp(spriteTileData1, windowTileData, size1, printNickname);
fontId = GetFontIdToFit(str, FONT_SMALL, 0, ABILITY_POP_UP_STR_WIDTH);
if (GetStringWidth(fontId, str, 0) > (size1 * 8))
{
windowTileData += TILE_OFFSET_4BPP(size1);
TextIntoAbilityPopUp(spriteTileData2, windowTileData, size2, printNickname);
}
RemoveWindow(windowId);
}
static void PrintBattlerOnAbilityPopUp(u8 battler, u8 spriteId1, u8 spriteId2)
{
int i;
u8 lastChar;
u8* textPtr;
u8 monName[POKEMON_NAME_LENGTH + 3] = {0};
u32 totalChar = 0, lastChar;
struct Pokemon *illusionMon = GetIllusionMonPtr(battler);
u8 nick[POKEMON_NAME_LENGTH + 1] = {0};
if (illusionMon != NULL)
GetMonData(illusionMon, MON_DATA_NICKNAME, nick);
GetMonData(illusionMon, MON_DATA_NICKNAME, gStringVar1);
else
GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, nick);
GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, gStringVar1);
for (i = 0; i < POKEMON_NAME_LENGTH; ++i)
{
if (nick[i] == EOS) // End of string
break;
while (gStringVar1[totalChar] != EOS)
totalChar++;
monName[i] = nick[i];
}
textPtr = monName + i;
lastChar = *(textPtr - 1);
// Make the string say "[NAME]'s" instead of "[NAME]"
textPtr[0] = CHAR_SGL_QUOTE_RIGHT; // apostraphe
textPtr++;
lastChar = gStringVar1[totalChar - 1];
StringAppend(gStringVar1, COMPOUND_STRING("'"));
if (lastChar != CHAR_S && lastChar != CHAR_s)
{
textPtr[0] = CHAR_s;
textPtr++;
}
StringAppend(gStringVar1, COMPOUND_STRING("s"));
textPtr[0] = EOS;
PrintOnAbilityPopUp((const u8 *)monName,
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32),
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32),
5, 12,
0,
2, 7, 1);
PrintOnAbilityPopUp(gStringVar1,
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum),
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum),
0, 0,
ABILITY_POP_UP_BATTLER_BG_TXTCLR, ABILITY_POP_UP_BATTLER_FG_TXTCLR, ABILITY_POP_UP_BATTLER_SH_TXTCLR,
TRUE, gSprites[spriteId1].sBattlerId);
}
static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2)
static void PrintAbilityOnAbilityPopUp(enum Ability ability, u8 spriteId1, u8 spriteId2)
{
ClearAbilityName(spriteId1, spriteId2);
PrintOnAbilityPopUp(COMPOUND_STRING(" "),
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum) + TILE_OFFSET_4BPP(8),
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum) + TILE_OFFSET_4BPP(8),
0, 4,
ABILITY_POP_UP_ABILITY_BG_TXTCLR, ABILITY_POP_UP_ABILITY_FG_TXTCLR, ABILITY_POP_UP_ABILITY_SH_TXTCLR,
FALSE, gSprites[spriteId1].sBattlerId);
PrintOnAbilityPopUp(gAbilitiesInfo[ability].name,
(void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256,
(void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256,
5, 12,
4,
7, 9, 1);
}
#define PIXEL_COORDS_TO_OFFSET(x, y)( \
/*Add tiles by X*/ \
((y / 8) * 32 * 8) \
/*Add tiles by X*/ \
+ ((x / 8) * 32) \
/*Add pixels by Y*/ \
+ ((((y) - ((y / 8) * 8))) * 4) \
/*Add pixels by X*/ \
+ ((((x) - ((x / 8) * 8)) / 2)))
static const u16 sOverwrittenPixelsTable[][2] =
{
{PIXEL_COORDS_TO_OFFSET(0, 0), 5},
{PIXEL_COORDS_TO_OFFSET(0, 1), 5},
{PIXEL_COORDS_TO_OFFSET(0, 2), 5},
{PIXEL_COORDS_TO_OFFSET(0, 3), 5},
{PIXEL_COORDS_TO_OFFSET(0, 4), 5},
{PIXEL_COORDS_TO_OFFSET(0, 5), 5},
{PIXEL_COORDS_TO_OFFSET(0, 6), 5},
{PIXEL_COORDS_TO_OFFSET(0, 7), 3},
{PIXEL_COORDS_TO_OFFSET(0, 8), 3},
{PIXEL_COORDS_TO_OFFSET(0, 9), 3},
{PIXEL_COORDS_TO_OFFSET(0, 10), 3},
{PIXEL_COORDS_TO_OFFSET(0, 11), 3},
{PIXEL_COORDS_TO_OFFSET(0, 12), 3},
{PIXEL_COORDS_TO_OFFSET(0, 13), 8},
{PIXEL_COORDS_TO_OFFSET(8, 13), 8},
{PIXEL_COORDS_TO_OFFSET(16, 13), 8},
{PIXEL_COORDS_TO_OFFSET(24, 13), 8},
{PIXEL_COORDS_TO_OFFSET(32, 13), 8},
{PIXEL_COORDS_TO_OFFSET(40, 13), 8},
{PIXEL_COORDS_TO_OFFSET(48, 13), 8},
{PIXEL_COORDS_TO_OFFSET(56, 13), 8},
{PIXEL_COORDS_TO_OFFSET(0, 14), 8},
{PIXEL_COORDS_TO_OFFSET(8, 14), 8},
{PIXEL_COORDS_TO_OFFSET(16, 14), 8},
{PIXEL_COORDS_TO_OFFSET(24, 14), 8},
{PIXEL_COORDS_TO_OFFSET(32, 14), 8},
{PIXEL_COORDS_TO_OFFSET(40, 14), 8},
{PIXEL_COORDS_TO_OFFSET(48, 14), 8},
{PIXEL_COORDS_TO_OFFSET(56, 14), 8},
{PIXEL_COORDS_TO_OFFSET(0, 15), 3},
{PIXEL_COORDS_TO_OFFSET(0, 16), 3},
{PIXEL_COORDS_TO_OFFSET(0, 17), 3},
{PIXEL_COORDS_TO_OFFSET(0, 18), 3},
{PIXEL_COORDS_TO_OFFSET(0, 19), 3},
{PIXEL_COORDS_TO_OFFSET(0, 20), 3},
{PIXEL_COORDS_TO_OFFSET(0, 21), 3},
{PIXEL_COORDS_TO_OFFSET(0, 22), 3},
{PIXEL_COORDS_TO_OFFSET(0, 23), 3},
{PIXEL_COORDS_TO_OFFSET(0, 24), 3},
{PIXEL_COORDS_TO_OFFSET(0, 25), 3},
{PIXEL_COORDS_TO_OFFSET(0, 26), 3},
//Second Row Of Image
{PIXEL_COORDS_TO_OFFSET(0, 45), 8},
{PIXEL_COORDS_TO_OFFSET(0, 46), 8},
{PIXEL_COORDS_TO_OFFSET(0, 47), 8},
{PIXEL_COORDS_TO_OFFSET(8, 45), 8},
{PIXEL_COORDS_TO_OFFSET(8, 46), 8},
{PIXEL_COORDS_TO_OFFSET(8, 47), 8},
{PIXEL_COORDS_TO_OFFSET(16, 45), 8},
{PIXEL_COORDS_TO_OFFSET(16, 46), 8},
{PIXEL_COORDS_TO_OFFSET(16, 47), 8},
};
static inline void CopyPixels(u8 *dest, const u8 *src, u32 pixelCount)
{
u32 i = 0;
if (pixelCount & 1)
{
while (pixelCount != 0)
{
dest[i] &= ~(0xF);
dest[i] |= (src[i] & 0xF);
if (--pixelCount != 0)
{
dest[i] &= ~(0xF0);
dest[i] |= (src[i] & 0xF0);
pixelCount--;
}
i++;
}
}
else
{
for (i = 0; i < pixelCount / 2; i++)
dest[i] = src[i];
}
}
static void RestoreOverwrittenPixels(u8 *tiles)
{
u32 i;
u8 *buffer = Alloc(sizeof(sAbilityPopUpGfx) * 2);
CpuCopy32(tiles, buffer, sizeof(sAbilityPopUpGfx));
for (i = 0; i < ARRAY_COUNT(sOverwrittenPixelsTable); i++)
{
CopyPixels(buffer + sOverwrittenPixelsTable[i][0],
sAbilityPopUpGfx + sOverwrittenPixelsTable[i][0],
sOverwrittenPixelsTable[i][1]);
}
CpuCopy32(buffer, tiles, sizeof(sAbilityPopUpGfx));
Free(buffer);
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum) + TILE_OFFSET_4BPP(8),
(void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId2].oam.tileNum) + TILE_OFFSET_4BPP(8),
0, 4,
ABILITY_POP_UP_ABILITY_BG_TXTCLR, ABILITY_POP_UP_ABILITY_FG_TXTCLR, ABILITY_POP_UP_ABILITY_SH_TXTCLR,
FALSE, gSprites[spriteId1].sBattlerId);
}
static inline bool32 IsAnyAbilityPopUpActive(void)
{
u32 activeAbilityPopUps = 0;
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleStruct->battlerState[battler].activeAbilityPopUps)
return TRUE;
activeAbilityPopUps++;
}
return FALSE;
return activeAbilityPopUps;
}
void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle)
void CreateAbilityPopUp(u8 battler, enum Ability ability, bool32 isDoubleBattle)
{
u8 *spriteIds;
u32 xSlide, tileTag, battlerPosition = GetBattlerPosition(battler);
struct SpriteTemplate template;
const s16 (*coords)[2];
u8 spriteId1, spriteId2, battlerPosition, taskId;
if (B_ABILITY_POP_UP == FALSE)
return;
if (gBattleScripting.abilityPopupOverwrite != 0)
if (gBattleScripting.abilityPopupOverwrite)
ability = gBattleScripting.abilityPopupOverwrite;
if (gTestRunnerEnabled)
@ -2526,111 +2438,122 @@ void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle)
}
if (!IsAnyAbilityPopUpActive())
{
LoadSpriteSheet(&sSpriteSheet_AbilityPopUp);
LoadSpritePalette(&sSpritePalette_AbilityPopUp);
tileTag = (TAG_ABILITY_POP_UP_PLAYER1 + battler);
if (IndexOfSpriteTileTag(tileTag) == 0xFF)
{
struct SpriteSheet sheet = sSpriteSheet_AbilityPopUp;
sheet.tag = tileTag;
LoadSpriteSheet(&sheet);
}
coords = isDoubleBattle ? sAbilityPopUpCoordsDoubles : sAbilityPopUpCoordsSingles;
xSlide = IsOnPlayerSide(battler) ? -ABILITY_POP_UP_POS_X_SLIDE : ABILITY_POP_UP_POS_X_SLIDE;
template = sSpriteTemplate_AbilityPopUp;
template.tileTag = tileTag;
spriteIds = gBattleStruct->abilityPopUpSpriteIds[battler];
spriteIds[0] = CreateSprite(&template, coords[battlerPosition][0] + xSlide,
coords[battlerPosition][1], 0);
spriteIds[1] = CreateSprite(&template, coords[battlerPosition][0] + xSlide + ABILITY_POP_UP_POS_X_DIFF,
coords[battlerPosition][1], 0);
if (IsOnPlayerSide(battler))
{
gSprites[spriteIds[0]].sIsPlayerSide = TRUE;
gSprites[spriteIds[1]].sIsPlayerSide = TRUE;
}
gSprites[spriteIds[1]].oam.tileNum += 32; // Second half of the pop up tiles.
// Create only one instance, as it's only used for
// tracking the SpriteSheet(s) and SpritePalette.
if (!IsAnyAbilityPopUpActive())
CreateTask(Task_FreeAbilityPopUpGfx, 5);
gBattleStruct->battlerState[battler].activeAbilityPopUps = TRUE;
battlerPosition = GetBattlerPosition(battler);
if (isDoubleBattle)
coords = sAbilityPopUpCoordsDoubles;
else
coords = sAbilityPopUpCoordsSingles;
gSprites[spriteIds[0]].sIsMain = TRUE;
gSprites[spriteIds[0]].sBattlerId = battler;
gSprites[spriteIds[1]].sBattlerId = battler;
if ((battlerPosition & BIT_SIDE) == B_SIDE_PLAYER)
{
spriteId1 = CreateSprite(&sSpriteTemplate_AbilityPopUp,
coords[battlerPosition][0] - ABILITY_POP_UP_POS_X_SLIDE,
coords[battlerPosition][1], 0);
spriteId2 = CreateSprite(&sSpriteTemplate_AbilityPopUp,
coords[battlerPosition][0] - ABILITY_POP_UP_POS_X_SLIDE + ABILITY_POP_UP_POS_X_DIFF,
coords[battlerPosition][1], 1); //Appears below
gSprites[spriteId1].tRightToLeft = TRUE;
gSprites[spriteId2].tRightToLeft = TRUE;
}
else
{
spriteId1 = CreateSprite(&sSpriteTemplate_AbilityPopUp,
coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_SLIDE,
coords[battlerPosition][1], 0);
spriteId2 = CreateSprite(&sSpriteTemplate_AbilityPopUp,
coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_SLIDE + ABILITY_POP_UP_POS_X_DIFF,
coords[battlerPosition][1], 1); //Appears below
gSprites[spriteId1].tRightToLeft = FALSE;
gSprites[spriteId2].tRightToLeft = FALSE;
}
gSprites[spriteId1].tOriginalX = coords[battlerPosition][0];
gSprites[spriteId2].tOriginalX = coords[battlerPosition][0] + ABILITY_POP_UP_POS_X_DIFF;
gSprites[spriteId2].oam.tileNum += (8 * 4); //Second half of pop up
gBattleStruct->abilityPopUpSpriteIds[battler][0] = spriteId1;
gBattleStruct->abilityPopUpSpriteIds[battler][1] = spriteId2;
taskId = CreateTask(Task_FreeAbilityPopUpGfx, 5);
gTasks[taskId].tSpriteId1 = spriteId1;
gTasks[taskId].tSpriteId2 = spriteId2;
gSprites[spriteId1].tIsMain = TRUE;
gSprites[spriteId1].tBattlerId = battler;
gSprites[spriteId2].tBattlerId = battler;
StartSpriteAnim(&gSprites[spriteId1], 0);
StartSpriteAnim(&gSprites[spriteId2], 0);
PrintBattlerOnAbilityPopUp(battler, spriteId1, spriteId2);
PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2);
RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32));
PrintBattlerOnAbilityPopUp(battler, spriteIds[0], spriteIds[1]);
PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]);
}
void UpdateAbilityPopup(u8 battler)
{
u8 spriteId1 = gBattleStruct->abilityPopUpSpriteIds[battler][0];
u8 spriteId2 = gBattleStruct->abilityPopUpSpriteIds[battler][1];
u16 ability = (gBattleScripting.abilityPopupOverwrite != 0) ? gBattleScripting.abilityPopupOverwrite : gBattleMons[battler].ability;
PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2);
RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32));
u8 *spriteIds = gBattleStruct->abilityPopUpSpriteIds[battler];
enum Ability ability = (gBattleScripting.abilityPopupOverwrite) ? gBattleScripting.abilityPopupOverwrite
: gBattleMons[battler].ability;
PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]);
}
#define FRAMES_TO_WAIT 48
static void SpriteCb_AbilityPopUp(struct Sprite *sprite)
{
if (!sprite->tHide) // Show
s16 *data = sprite->data;
u32 battlerPosition = GetBattlerPosition(sBattlerId);
u32 fullX = sprite->x + sprite->x2;
u32 speed;
switch (sState)
{
if (sprite->tIsMain && ++sprite->tFrames == 4)
case APU_STATE_SLIDE_IN:
{
const s16 (*coords)[2] = IsDoubleBattle() ? sAbilityPopUpCoordsDoubles : sAbilityPopUpCoordsSingles;
u32 xCoord = coords[battlerPosition][0];
if (sIsMain && ++sTimer == 4)
PlaySE(SE_BALL_TRAY_ENTER);
if ((!sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX)
|| (sprite->tRightToLeft && (sprite->x += 4) >= sprite->tOriginalX)
)
{
sprite->x = sprite->tOriginalX;
sprite->tHide = TRUE;
sprite->tFrames = FRAMES_TO_WAIT;
}
if (!sIsMain)
xCoord += ABILITY_POP_UP_POS_X_DIFF;
if (fullX == xCoord)
{
sTimer = ABILITY_POP_UP_WAIT_FRAMES;
sState = APU_STATE_IDLE;
break;
}
speed = sIsPlayerSide ? ABILITY_POP_UP_POS_X_SPEED : -ABILITY_POP_UP_POS_X_SPEED;
sprite->x2 += speed;
break;
}
else // Hide
case APU_STATE_IDLE:
{
if (sprite->tFrames == 0)
if (!sTimer || sAutoDestroy)
{
if ((!sprite->tRightToLeft && (sprite->x += 4) >= sprite->tOriginalX + ABILITY_POP_UP_POS_X_SLIDE)
||(sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX - ABILITY_POP_UP_POS_X_SLIDE)
)
{
gBattleStruct->battlerState[sprite->tBattlerId].activeAbilityPopUps = FALSE;
DestroySprite(sprite);
}
}
else
{
if (!gBattleScripting.fixedPopup)
sprite->tFrames--;
sState = APU_STATE_SLIDE_OUT;
break;
}
if (!gBattleScripting.fixedPopup)
sTimer--;
break;
}
case APU_STATE_SLIDE_OUT:
{
if (fullX == sprite->x)
{
sState = APU_STATE_END;
break;
}
speed = sIsPlayerSide ? -ABILITY_POP_UP_POS_X_SPEED : ABILITY_POP_UP_POS_X_SPEED;
sprite->x2 += speed;
break;
}
case APU_STATE_END:
{
if (sIsMain)
gBattleStruct->battlerState[sBattlerId].activeAbilityPopUps = FALSE;
DestroySprite(sprite);
break;
}
}
}
@ -2638,26 +2561,33 @@ void DestroyAbilityPopUp(u8 battler)
{
if (gBattleStruct->battlerState[battler].activeAbilityPopUps)
{
gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][0]].tFrames = 0;
gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][1]].tFrames = 0;
gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][0]].sAutoDestroy = TRUE;
gSprites[gBattleStruct->abilityPopUpSpriteIds[battler][1]].sAutoDestroy = TRUE;
}
gBattleScripting.fixedPopup = FALSE;
}
static void Task_FreeAbilityPopUpGfx(u8 taskId)
{
if (!gSprites[gTasks[taskId].tSpriteId1].inUse
&& !gSprites[gTasks[taskId].tSpriteId2].inUse
&& !IsAnyAbilityPopUpActive())
if (!IsAnyAbilityPopUpActive())
{
FreeSpriteTilesByTag(ABILITY_POP_UP_TAG);
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG);
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (IndexOfSpriteTileTag(TAG_ABILITY_POP_UP_PLAYER1 + battler) != 0xFF)
FreeSpriteTilesByTag(TAG_ABILITY_POP_UP_PLAYER1 + battler);
}
FreeSpritePaletteByTag(TAG_ABILITY_POP_UP);
DestroyTask(taskId);
}
}
#undef sState
#undef sAutoDestroy
#undef sTimer
#undef sIsPlayerSide
#undef sBattlerId
#undef sIsMain
// last used ball
#define LAST_BALL_WINDOW_TAG 0xD721
static const struct OamData sOamData_LastUsedBall =
{
@ -2678,8 +2608,8 @@ static const struct OamData sOamData_LastUsedBall =
static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow =
{
.tileTag = LAST_BALL_WINDOW_TAG,
.paletteTag = ABILITY_POP_UP_TAG,
.tileTag = TAG_LAST_BALL_WINDOW,
.paletteTag = TAG_ABILITY_POP_UP,
.oam = &sOamData_LastUsedBall,
.anims = gDummySpriteAnimTable,
.images = NULL,
@ -2709,7 +2639,7 @@ static const struct OamData sOamData_MoveInfoWindow =
static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow =
{
.tileTag = MOVE_INFO_WINDOW_TAG,
.paletteTag = ABILITY_POP_UP_TAG,
.paletteTag = TAG_ABILITY_POP_UP,
.oam = &sOamData_MoveInfoWindow,
.anims = gDummySpriteAnimTable,
.images = NULL,
@ -2728,7 +2658,7 @@ static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow =
#endif
static const struct SpriteSheet sSpriteSheet_LastUsedBallWindow =
{
sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), LAST_BALL_WINDOW_TAG
sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), TAG_LAST_BALL_WINDOW
};
#if B_MOVE_DESCRIPTION_BUTTON == R_BUTTON
@ -2786,7 +2716,7 @@ void TryAddLastUsedBallItemSprites(void)
// we have to compact the bag first bc it is typically only compacted when you open it
CompactItemsInBagPocket(POCKET_POKE_BALLS);
firstBall = gBagPockets[POCKET_POKE_BALLS].itemSlots[0].itemId;
firstBall = GetBagItemId(POCKET_POKE_BALLS, 0);
if (firstBall > ITEM_NONE)
gBallToDisplay = firstBall;
}
@ -2807,7 +2737,7 @@ void TryAddLastUsedBallItemSprites(void)
// window
LoadSpritePalette(&sSpritePalette_AbilityPopUp);
if (GetSpriteTileStartByTag(LAST_BALL_WINDOW_TAG) == 0xFFFF)
if (GetSpriteTileStartByTag(TAG_LAST_BALL_WINDOW) == 0xFFFF)
LoadSpriteSheet(&sSpriteSheet_LastUsedBallWindow);
if (gBattleStruct->ballSpriteIds[1] == MAX_SPRITES)
@ -2825,8 +2755,8 @@ void TryAddLastUsedBallItemSprites(void)
static void DestroyLastUsedBallWinGfx(struct Sprite *sprite)
{
FreeSpriteTilesByTag(LAST_BALL_WINDOW_TAG);
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG);
FreeSpriteTilesByTag(TAG_LAST_BALL_WINDOW);
FreeSpritePaletteByTag(TAG_ABILITY_POP_UP);
DestroySprite(sprite);
gBattleStruct->ballSpriteIds[1] = MAX_SPRITES;
}
@ -2863,7 +2793,7 @@ void TryToHideMoveInfoWindow(void)
static void DestroyMoveInfoWinGfx(struct Sprite *sprite)
{
FreeSpriteTilesByTag(MOVE_INFO_WINDOW_TAG);
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG);
FreeSpritePaletteByTag(TAG_ABILITY_POP_UP);
DestroySprite(sprite);
gBattleStruct->moveInfoSpriteId = MAX_SPRITES;
}

View File

@ -67,9 +67,9 @@
#include "constants/abilities.h"
#include "constants/battle_ai.h"
#include "constants/battle_move_effects.h"
#include "constants/battle_setup.h"
#include "constants/battle_string_ids.h"
#include "constants/battle_partner.h"
#include "constants/battle_setup.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
#include "constants/moves.h"
@ -95,6 +95,9 @@ static void BattleMainCB1(void);
static void CB2_QuitPokedudeBattle(void);
static void CB2_EndLinkBattle(void);
static void EndLinkBattleInSteps(void);
// static void CB2_InitAskRecordBattle(void);
// static void CB2_AskRecordBattle(void);
// static void AskRecordBattle(void);
static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite);
static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite);
static void SpriteCB_WildMonAnimate(struct Sprite *sprite);
@ -168,7 +171,7 @@ EWRAM_DATA u16 gChosenMove = 0;
EWRAM_DATA u16 gCalledMove = 0;
EWRAM_DATA s32 gBideDmg[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastUsedItem = 0;
EWRAM_DATA u16 gLastUsedAbility = 0;
EWRAM_DATA enum Ability gLastUsedAbility = 0;
EWRAM_DATA u8 gBattlerAttacker = 0;
EWRAM_DATA u8 gBattlerTarget = 0;
EWRAM_DATA u8 gBattlerFainted = 0;
@ -194,8 +197,6 @@ EWRAM_DATA u32 gHitMarker = 0;
EWRAM_DATA u8 gBideTarget[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u32 gSideStatuses[NUM_BATTLE_SIDES] = {0};
EWRAM_DATA struct SideTimer gSideTimers[NUM_BATTLE_SIDES] = {0};
EWRAM_DATA u32 gStatuses3[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u32 gStatuses4[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gPauseCounterBattle = 0;
EWRAM_DATA u16 gPaydayMoney = 0;
@ -239,7 +240,7 @@ EWRAM_DATA u16 gBattleTurnCounter = 0;
EWRAM_DATA u8 gBattlerAbility = 0;
EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA bool8 gHasFetchedBall = FALSE;
EWRAM_DATA u8 gLastUsedBall = 0;
EWRAM_DATA u16 gLastUsedBall = 0;
EWRAM_DATA u16 gLastThrownBall = 0;
EWRAM_DATA u16 gBallToDisplay = 0;
EWRAM_DATA bool8 gLastUsedBallMenuPresent = FALSE;
@ -541,10 +542,9 @@ static void CB2_InitBattleInternal(void)
else
{
gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1);
ScanlineEffect_Clear();
if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless)
{
ScanlineEffect_Clear();
for (i = 0; i < DISPLAY_HEIGHT / 2; i++)
{
gScanlineEffectRegBuffers[0][i] = 0xF0;
@ -1481,7 +1481,7 @@ static void CB2_PreInitIngamePlayerPartnerBattle(void)
*savedBattleTypeFlags = gBattleTypeFlags;
gMain.savedCallback = CB2_PreInitIngamePlayerPartnerBattle;
// if (!PlayerHasFollowerNPC() || !FollowerNPCIsBattlePartner() || (FNPC_NPC_FOLLOWER_PARTY_PREVIEW && FollowerNPCIsBattlePartner()))
ShowPartyMenuToShowcaseMultiBattleParty();
ShowPartyMenuToShowcaseMultiBattleParty();
break;
case 1:
@ -2106,7 +2106,24 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
u8 retVal;
if (trainerNum == TRAINER_SECRET_BASE)
return 0;
retVal = CreateNPCTrainerPartyFromTrainer(party, GetTrainerStructFromId(trainerNum), firstTrainer, gBattleTypeFlags);
if (GetTrainerStructFromId(trainerNum)->overrideTrainer)
{
struct Trainer tempTrainer;
memcpy(&tempTrainer, GetTrainerStructFromId(trainerNum), sizeof(struct Trainer));
const struct Trainer *origTrainer = GetTrainerStructFromId(tempTrainer.overrideTrainer);
tempTrainer.party = origTrainer->party;
tempTrainer.poolSize = origTrainer->poolSize;
if (tempTrainer.partySize == 0)
tempTrainer.partySize = origTrainer->partySize;
retVal = CreateNPCTrainerPartyFromTrainer(party, (const struct Trainer *)(&tempTrainer), firstTrainer, gBattleTypeFlags);
}
else
{
retVal = CreateNPCTrainerPartyFromTrainer(party, GetTrainerStructFromId(trainerNum), firstTrainer, gBattleTypeFlags);
}
return retVal;
}
@ -2767,8 +2784,6 @@ static void BattleStartClearSetData(void)
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
gStatuses3[i] = 0;
gStatuses4[i] = 0;
gDisableStructs[i].isFirstTurn = 2;
gLastMoves[i] = MOVE_NONE;
gLastLandedMoves[i] = MOVE_NONE;
@ -2874,14 +2889,13 @@ static void BattleStartClearSetData(void)
}
}
#define UNPACK_VOLATILE_BATON_PASSABLES(_enum, _fieldName, _typeBitSize, ...) __VA_OPT__(if ((FIRST(__VA_ARGS__)) & V_BATON_PASSABLE) gBattleMons[battler].volatiles._fieldName = volatilesCopy._fieldName;)
#define UNPACK_VOLATILE_BATON_PASSABLES(_enum, _fieldName, _typeMaxValue, ...) __VA_OPT__(if ((FIRST(__VA_ARGS__)) & V_BATON_PASSABLE) gBattleMons[battler].volatiles._fieldName = volatilesCopy->_fieldName;)
void SwitchInClearSetData(u32 battler)
void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
{
s32 i;
enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove);
struct DisableStruct disableStructCopy = gDisableStructs[battler];
struct Volatiles volatilesCopy = gBattleMons[battler].volatiles;
ClearIllusionMon(battler);
if (effect != EFFECT_BATON_PASS)
@ -2890,58 +2904,52 @@ void SwitchInClearSetData(u32 battler)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
for (i = 0; i < gBattlersCount; i++)
{
if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == battler)
gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION;
if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].battlerWithSureHit == battler)
if (gBattleMons[i].volatiles.escapePrevention && gDisableStructs[i].battlerPreventingEscape == battler)
gBattleMons[i].volatiles.escapePrevention = FALSE;
if (gBattleMons[i].volatiles.lockOn && gDisableStructs[i].battlerWithSureHit == battler)
{
gStatuses3[i] &= ~STATUS3_ALWAYS_HITS;
gBattleMons[i].volatiles.lockOn = 0;
gDisableStructs[i].battlerWithSureHit = 0;
}
}
}
// Clear volatiles - reapply some if Baton Pass was used
memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles));
if (effect == EFFECT_BATON_PASS)
{
// Transfer Baton Passable volatile statuses
memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles));
VOLATILE_DEFINITIONS(UNPACK_VOLATILE_BATON_PASSABLES)
/* Expands to the following (compiler removes `if` statements):
* gBattleMons[battler].volatiles.confusionTurns = volatilesCopy.confusionTurns;
* gBattleMons[battler].volatiles.substitute = volatilesCopy.substitute;
* gBattleMons[battler].volatiles.escapePrevention = volatilesCopy.escapePrevention;
* gBattleMons[battler].volatiles.confusionTurns = volatilesCopy->confusionTurns;
* gBattleMons[battler].volatiles.substitute = volatilesCopy->substitute;
* gBattleMons[battler].volatiles.escapePrevention = volatilesCopy->escapePrevention;
* ...etc
*/
gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED
| STATUS3_GASTRO_ACID | STATUS3_EMBARGO | STATUS3_TELEKINESIS | STATUS3_MAGNET_RISE | STATUS3_HEAL_BLOCK
| STATUS3_AQUA_RING | STATUS3_POWER_TRICK);
gStatuses4[battler] &= (STATUS4_MUD_SPORT | STATUS4_WATER_SPORT | STATUS4_INFINITE_CONFUSION);
for (i = 0; i < gBattlersCount; i++)
{
if (!IsBattlerAlly(battler, i)
&& (gStatuses3[i] & STATUS3_ALWAYS_HITS) != 0
&& gBattleMons[i].volatiles.lockOn != 0
&& (gDisableStructs[i].battlerWithSureHit == battler))
{
gStatuses3[i] &= ~STATUS3_ALWAYS_HITS;
gStatuses3[i] |= STATUS3_ALWAYS_HITS_TURN(2);
gBattleMons[i].volatiles.lockOn = 0;
}
}
if (gStatuses3[battler] & STATUS3_POWER_TRICK)
if (gBattleMons[battler].volatiles.powerTrick)
SWAP(gBattleMons[battler].attack, gBattleMons[battler].defense, i);
}
else
{
gBattleMons[battler].status2 = 0;
gStatuses3[battler] = 0;
gStatuses4[battler] = 0;
}
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(battler))
gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(battler);
if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && gBattleStruct->wrappedBy[i] == battler)
gBattleMons[i].status2 &= ~STATUS2_WRAPPED;
if ((gStatuses4[i] & STATUS4_SYRUP_BOMB) && gBattleStruct->stickySyrupdBy[i] == battler)
gStatuses4[i] &= ~STATUS4_SYRUP_BOMB;
if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler))
gBattleMons[i].volatiles.infatuation = 0;
if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler)
gBattleMons[i].volatiles.wrapped = FALSE;
if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler)
gBattleMons[i].volatiles.syrupBomb = FALSE;
if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler)
gDisableStructs[i].octolock = FALSE;
}
gActionSelectionCursor[battler] = 0;
@ -2949,6 +2957,9 @@ void SwitchInClearSetData(u32 battler)
memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct));
if (GetProtectType(gProtectStructs[battler].protected) == PROTECT_TYPE_SINGLE) // Side type protects expire at the end of the turn
gProtectStructs[battler].protected = PROTECT_NONE;
if (effect == EFFECT_BATON_PASS)
{
gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP;
@ -2956,10 +2967,11 @@ void SwitchInClearSetData(u32 battler)
gDisableStructs[battler].perishSongTimer = disableStructCopy.perishSongTimer;
gDisableStructs[battler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape;
gDisableStructs[battler].embargoTimer = disableStructCopy.embargoTimer;
gDisableStructs[battler].healBlockTimer = disableStructCopy.healBlockTimer;
}
else if (effect == EFFECT_SHED_TAIL)
{
gBattleMons[battler].status2 |= STATUS2_SUBSTITUTE;
gBattleMons[battler].volatiles.substitute = TRUE;
gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP;
}
@ -3030,7 +3042,7 @@ void SwitchInClearSetData(u32 battler)
u32 side = GetBattlerSide(battler);
u32 partyIndex = gBattlerPartyIndexes[battler];
if (TestRunner_Battle_GetForcedAbility(side, partyIndex))
gBattleMons[i].ability = gDisableStructs[i].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex);
gBattleMons[i].ability = TestRunner_Battle_GetForcedAbility(side, partyIndex);
}
#endif // TESTING
@ -3045,20 +3057,22 @@ const u8* FaintClearSetData(u32 battler)
for (i = 0; i < NUM_BATTLE_STATS; i++)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
gBattleMons[battler].status2 = 0;
gStatuses3[battler] &= STATUS3_GASTRO_ACID; // Edge case: Keep Gastro Acid if pokemon's ability can have effect after fainting, for example Innards Out.
gStatuses4[battler] = 0;
bool32 keepGastroAcid = gBattleMons[battler].volatiles.gastroAcid;
memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles));
gBattleMons[battler].volatiles.gastroAcid = keepGastroAcid; // Edge case: Keep Gastro Acid if pokemon's ability can have effect after fainting, for example Innards Out.
for (i = 0; i < gBattlersCount; i++)
{
if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == battler)
gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION;
if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(battler))
gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(battler);
if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && gBattleStruct->wrappedBy[i] == battler)
gBattleMons[i].status2 &= ~STATUS2_WRAPPED;
if ((gStatuses4[i] & STATUS4_SYRUP_BOMB) && gBattleStruct->stickySyrupdBy[i] == battler)
gStatuses4[i] &= ~STATUS4_SYRUP_BOMB;
if (gBattleMons[i].volatiles.escapePrevention && gDisableStructs[i].battlerPreventingEscape == battler)
gBattleMons[i].volatiles.escapePrevention = FALSE;
if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler))
gBattleMons[i].volatiles.infatuation = 0;
if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler)
gBattleMons[i].volatiles.wrapped = FALSE;
if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler)
gBattleMons[i].volatiles.syrupBomb = FALSE;
if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler)
gDisableStructs[i].octolock = FALSE;
}
gActionSelectionCursor[battler] = 0;
@ -3070,9 +3084,8 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].protected = PROTECT_NONE;
gProtectStructs[battler].quash = FALSE;
gProtectStructs[battler].endured = FALSE;
gProtectStructs[battler].noValidMoves = FALSE;
gProtectStructs[battler].helpingHand = FALSE;
gProtectStructs[battler].helpingHand = 0;
gProtectStructs[battler].bounceMove = FALSE;
gProtectStructs[battler].stealMove = FALSE;
gProtectStructs[battler].nonVolatileStatusImmobility = FALSE;
@ -3080,9 +3093,7 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].confusionSelfDmg = FALSE;
gProtectStructs[battler].chargingTurn = FALSE;
gProtectStructs[battler].fleeType = 0;
gProtectStructs[battler].notFirstStrike = FALSE;
gProtectStructs[battler].statRaised = FALSE;
gProtectStructs[battler].tryEjectPack = FALSE;
gProtectStructs[battler].pranksterElevated = FALSE;
gDisableStructs[battler].isFirstTurn = 2;
@ -3106,7 +3117,7 @@ const u8* FaintClearSetData(u32 battler)
ClearPursuitValuesIfSet(battler);
if (gBattleStruct->commanderActive[battler] != SPECIES_NONE)
if (gBattleStruct->battlerState[battler].commanderSpecies != SPECIES_NONE)
{
u32 partner = BATTLE_PARTNER(battler);
if (IsBattlerAlive(partner))
@ -3149,27 +3160,28 @@ const u8* FaintClearSetData(u32 battler)
gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET;
// If the other Pokemon involved in this Sky Drop was the target, not the attacker
if (gStatuses3[otherSkyDropper] & STATUS3_SKY_DROPPED)
if (gBattleMons[otherSkyDropper].volatiles.semiInvulnerable == STATE_SKY_DROP)
{
// Release the target and take them out of the semi-invulnerable state
gStatuses3[otherSkyDropper] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
gBattleMons[otherSkyDropper].volatiles.semiInvulnerable = STATE_NONE;
// Make the target's sprite visible
gSprites[gBattlerSpriteIds[otherSkyDropper]].invisible = FALSE;
// If the target was sky dropped in the middle of using Outrage/Petal Dance/Thrash,
// confuse them upon release and print "confused via fatigue" message and animation.
if (gBattleMons[otherSkyDropper].status2 & STATUS2_LOCK_CONFUSE)
if (gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns)
{
gBattleMons[otherSkyDropper].status2 &= ~(STATUS2_LOCK_CONFUSE);
gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns = 0;
// If the released mon can be confused, do so.
// Don't use CanBeConfused here, since it can cause issues in edge cases.
if (!(GetBattlerAbility(otherSkyDropper) == ABILITY_OWN_TEMPO
|| gBattleMons[otherSkyDropper].status2 & STATUS2_CONFUSION
|| IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN)))
enum Ability ability = GetBattlerAbility(otherSkyDropper);
if (!(ability == ABILITY_OWN_TEMPO
|| gBattleMons[otherSkyDropper].volatiles.confusionTurns
|| IsBattlerTerrainAffected(otherSkyDropper, ability, GetBattlerHoldEffect(otherSkyDropper), STATUS_FIELD_MISTY_TERRAIN)))
{
gBattleMons[otherSkyDropper].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2);
gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2;
gBattlerAttacker = otherSkyDropper;
result = BattleScript_ThrashConfuses;
}
@ -3232,7 +3244,7 @@ static void DoBattleIntro(void)
gBattleMons[battler].types[2] = TYPE_MYSTERY;
gBattleMons[battler].ability = GetAbilityBySpecies(gBattleMons[battler].species, gBattleMons[battler].abilityNum);
gBattleStruct->hpOnSwitchout[GetBattlerSide(battler)] = gBattleMons[battler].hp;
gBattleMons[battler].status2 = 0;
memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles));
for (i = 0; i < NUM_BATTLE_STATS; i++)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
#if TESTING
@ -3241,7 +3253,7 @@ static void DoBattleIntro(void)
u32 side = GetBattlerSide(battler);
u32 partyIndex = gBattlerPartyIndexes[battler];
if (TestRunner_Battle_GetForcedAbility(side, partyIndex))
gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex);
gBattleMons[battler].ability = TestRunner_Battle_GetForcedAbility(side, partyIndex);
}
#endif
}
@ -3418,7 +3430,7 @@ static void DoBattleIntro(void)
case BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT:
if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)))
{
if (IS_BATTLE_TYPE_GHOST_WITH_SCOPE(gBattleTypeFlags))
if (gBattleTypeFlags & BATTLE_TYPE_GHOST && CheckBagHasItem(ITEM_SILPH_SCOPE, 1))
{
gBattleScripting.battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
BattleScriptExecute(BattleScript_SilphScopeUnveiled);
@ -3495,7 +3507,7 @@ static void DoBattleIntro(void)
| BATTLE_TYPE_GHOST
| BATTLE_TYPE_OLD_MAN_TUTORIAL
| BATTLE_TYPE_LEGENDARY))
|| ((gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_GHOST_UNVEILED)) && !IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags))))
|| ((gBattleTypeFlags & (BATTLE_TYPE_GHOST | BATTLE_TYPE_GHOST_UNVEILED)) && !IsGhostBattleWithoutScope())))
{
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality);
}
@ -3560,7 +3572,7 @@ static void TryDoEventsBeforeFirstTurn(void)
u32 side = GetBattlerSide(i);
u32 partyIndex = gBattlerPartyIndexes[i];
if (TestRunner_Battle_GetForcedAbility(side, partyIndex))
gBattleMons[i].ability = gDisableStructs[i].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex);
gBattleMons[i].ability = TestRunner_Battle_GetForcedAbility(side, partyIndex);
}
}
#endif // TESTING
@ -3622,28 +3634,28 @@ static void TryDoEventsBeforeFirstTurn(void)
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_NEUTRALIZING_GAS:
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0)
return;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
if (TryPrimalReversion(i))
return;
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0) != 0)
return;
if (TryClearIllusion(i, ABILITYEFFECT_ON_SWITCHIN))
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN, i, gBattleMons[i].ability, 0, 0) != 0)
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_OPPORTUNIST_1:
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;
case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
if (TryPrimalReversion(battler))
return;
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battler, 0, 0, 0))
return;
if (TryClearIllusion(battler, ABILITYEFFECT_ON_SWITCHIN))
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_ITEM_EFFECTS:
@ -3655,9 +3667,32 @@ static void TryDoEventsBeforeFirstTurn(void)
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_OPPORTUNIST_2:
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;
case FIRST_TURN_EVENTS_WHITE_HERB:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
if (ItemBattleEffects(ITEMEFFECT_WHITE_HERB_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]))
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_OPPORTUNIST:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST_FIRST_TURN, battler, GetBattlerAbility(battler), 0, 0))
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_MIRROR_HERB:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
if (ItemBattleEffects(ITEMEFFECT_MIRROR_HERB_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]))
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_EJECT_PACK:
@ -3684,14 +3719,14 @@ static void TryDoEventsBeforeFirstTurn(void)
for (i = 0; i < gBattlersCount; i++)
{
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
gBattleMons[i].volatiles.flinched = FALSE;
// Record party slots of player's mons that appeared in battle
if (!BattlerHasAi(i))
gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[i];
}
*(&gBattleStruct->eventBlockCounter) = 0;
*(&gBattleStruct->turnEffectsBattlerId) = 0;
gBattleStruct->eventBlockCounter = 0;
gBattleStruct->turnEffectsBattlerId = 0;
gBattleScripting.moveendState = 0;
gBattleStruct->faintedActionsState = 0;
gBattleStruct->endTurnEventsCounter = 0;
@ -3724,8 +3759,8 @@ static void HandleEndTurn_ContinueBattle(void)
gBattleCommunication[i] = 0;
for (i = 0; i < gBattlersCount; i++)
{
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS))
gBattleMons[i].volatiles.flinched = FALSE;
if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].volatiles.multipleTurns))
CancelMultiTurnMoves(i, SKY_DROP_IGNORE);
}
gBattleStruct->eventBlockCounter = 0;
@ -3752,10 +3787,10 @@ void BattleTurnPassed(void)
gBattleStruct->faintedActionsState = 0;
TurnValuesCleanUp(FALSE);
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE;
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
gHitMarker &= ~HITMARKER_PLAYER_FAINTED;
gHitMarker &= ~HITMARKER_PASSIVE_DAMAGE;
gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE;
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
gBattleScripting.moveendState = 0;
@ -3781,9 +3816,9 @@ void BattleTurnPassed(void)
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
gBattleStruct->monToSwitchIntoId[i] = PARTY_SIZE;
gStatuses4[i] &= ~STATUS4_ELECTRIFIED;
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
gBattleMons[i].status2 &= ~STATUS2_POWDER;
gBattleMons[i].volatiles.electrified = FALSE;
gBattleMons[i].volatiles.flinched = FALSE;
gBattleMons[i].volatiles.powder = FALSE;
if (gBattleStruct->battlerState[i].stompingTantrumTimer > 0)
gBattleStruct->battlerState[i].stompingTantrumTimer--;
@ -3967,8 +4002,8 @@ static void HandleTurnActionSelectionState(void)
}
else
{
if (gBattleMons[battler].status2 & STATUS2_MULTIPLETURNS
|| gBattleMons[battler].status2 & STATUS2_RECHARGE)
if (gBattleMons[battler].volatiles.multipleTurns
|| gBattleMons[battler].volatiles.recharge)
{
gChosenActionByBattler[battler] = B_ACTION_USE_MOVE;
gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
@ -4050,7 +4085,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case B_ACTION_USE_ITEM:
if (FlagGet(B_FLAG_NO_BAG_USE))
if (ShouldBattleRestrictionsApply(battler) && !IsAllowedToUseBag())
{
RecordedBattle_ClearBattlerAction(battler, 1);
gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed;
@ -4066,7 +4101,7 @@ static void HandleTurnActionSelectionState(void)
| BATTLE_TYPE_RECORDED_LINK))
&& !gTestRunnerEnabled)
// Or if currently held by Sky Drop
|| gStatuses3[battler] & STATUS3_SKY_DROPPED)
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
{
RecordedBattle_ClearBattlerAction(battler, 1);
gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed;
@ -4118,8 +4153,8 @@ static void HandleTurnActionSelectionState(void)
gBattleCommunication[battler] = STATE_WAIT_SET_BEFORE_ACTION;
gBattleCommunication[GetPartnerBattler(battler)] = STATE_BEFORE_ACTION_CHOSEN;
RecordedBattle_ClearBattlerAction(battler, 1);
if (gBattleMons[GetPartnerBattler(battler)].status2 & STATUS2_MULTIPLETURNS
|| gBattleMons[GetPartnerBattler(battler)].status2 & STATUS2_RECHARGE)
if (gBattleMons[GetPartnerBattler(battler)].volatiles.multipleTurns
|| gBattleMons[GetPartnerBattler(battler)].volatiles.recharge)
{
BtlController_EmitEndBounceEffect(battler, B_COMM_TO_CONTROLLER);
MarkBattlerForControllerExec(battler);
@ -4248,8 +4283,12 @@ static void HandleTurnActionSelectionState(void)
// Get the chosen move position (and thus the chosen move) and target from the returned buffer.
gBattleStruct->chosenMovePositions[battler] = gBattleResources->bufferB[battler][2] & ~RET_GIMMICK;
gChosenMoveByBattler[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
gChosenMoveByBattler[battler] = GetChosenMoveFromPosition(battler);
gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3];
if (IsBattleMoveStatus(gChosenMoveByBattler[battler]) && GetBattlerAbility(battler) == ABILITY_MYCELIUM_MIGHT)
gProtectStructs[battler].myceliumMight = TRUE;
if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_LAGGING_TAIL)
gProtectStructs[battler].laggingTail = TRUE;
// Check to see if any gimmicks need to be prepared.
if (gBattleResources->bufferB[battler][2] & RET_GIMMICK)
@ -4258,13 +4297,16 @@ static void HandleTurnActionSelectionState(void)
// Max Move check
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX))
{
gBattleStruct->dynamax.baseMoves[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
gBattleStruct->dynamax.baseMoves[battler] = GetChosenMoveFromPosition(battler);
}
gBattleCommunication[battler]++;
if (gTestRunnerEnabled)
{
TestRunner_Battle_CheckChosenMove(battler, gChosenMoveByBattler[battler], gBattleStruct->moveTarget[battler]);
UNUSED enum Gimmick gimmick = GIMMICK_NONE;
if (gBattleResources->bufferB[battler][2] & RET_GIMMICK)
gimmick = gBattleStruct->gimmick.usableGimmick[battler];
TestRunner_Battle_CheckChosenMove(battler, gChosenMoveByBattler[battler], gBattleStruct->moveTarget[battler], gimmick);
}
}
break;
@ -4478,7 +4520,7 @@ void SwapTurnOrder(u8 id1, u8 id2)
}
// For AI, so it doesn't 'cheat' by knowing player's ability
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect holdEffect)
u32 GetBattlerTotalSpeedStatArgs(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect)
{
u32 speed = gBattleMons[battler].speed;
@ -4506,9 +4548,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect h
speed *= 2;
else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0)
speed /= 2;
else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battler].boosterEnergyActivated))
else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].volatiles.transformed) && ((gBattleWeather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battler].boosterEnergyActivated))
speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivated))
else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].volatiles.transformed) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivated))
speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
else if (ability == ABILITY_UNBURDEN && gDisableStructs[battler].unburdenActive)
speed *= 2;
@ -4528,7 +4570,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect h
speed /= 2;
else if (holdEffect == HOLD_EFFECT_CHOICE_SCARF && GetActiveGimmick(battler) != GIMMICK_DYNAMAX)
speed = (speed * 150) / 100;
else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battler].species == SPECIES_DITTO && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED))
else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battler].species == SPECIES_DITTO && !(gBattleMons[battler].volatiles.transformed))
speed *= 2;
// various effects
@ -4547,12 +4589,12 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect h
u32 GetBattlerTotalSpeedStat(u32 battler)
{
u32 ability = GetBattlerAbility(battler);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
enum Ability ability = GetBattlerAbility(battler);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler);
return GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect);
}
s32 GetChosenMovePriority(u32 battler, u32 ability)
s32 GetChosenMovePriority(u32 battler, enum Ability ability)
{
u16 move;
@ -4560,12 +4602,12 @@ s32 GetChosenMovePriority(u32 battler, u32 ability)
if (gProtectStructs[battler].noValidMoves)
move = MOVE_STRUGGLE;
else
move = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
move = GetChosenMoveFromPosition(battler);
return GetBattleMovePriority(battler, ability, move);
}
s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move)
s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move)
{
s32 priority = 0;
@ -4578,9 +4620,13 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move)
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS)
return GetMovePriority(MOVE_MAX_GUARD);
if (ability == ABILITY_GALE_WINGS
&& (GetGenConfig(GEN_CONFIG_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler))
&& GetMoveType(move) == TYPE_FLYING)
if (gProtectStructs[battler].quash)
{
priority = -8;
}
else if (ability == ABILITY_GALE_WINGS
&& (GetGenConfig(GEN_CONFIG_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler))
&& GetMoveType(move) == TYPE_FLYING)
{
priority++;
}
@ -4589,20 +4635,19 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move)
gProtectStructs[battler].pranksterElevated = 1;
priority++;
}
else if (GetMoveEffect(move) == EFFECT_GRASSY_GLIDE && IsBattlerTerrainAffected(battler, STATUS_FIELD_GRASSY_TERRAIN) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_DYNAMAX && !IsGimmickSelected(battler, GIMMICK_DYNAMAX))
else if (GetMoveEffect(move) == EFFECT_GRASSY_GLIDE && IsBattlerTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), STATUS_FIELD_GRASSY_TERRAIN) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_DYNAMAX && !IsGimmickSelected(battler, GIMMICK_DYNAMAX))
{
priority++;
}
else if (ability == ABILITY_TRIAGE && IsHealingMove(move))
{
priority += 3;
if (gProtectStructs[battler].quash)
priority = -8;
}
return priority;
}
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, enum Ability ability1, enum Ability ability2,
enum ItemHoldEffect holdEffectBattler1, enum ItemHoldEffect holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2)
{
u32 strikesFirst = 0;
@ -4614,16 +4659,16 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov
// Lagging Tail - always last
bool32 battler1HasQuickEffect = gProtectStructs[battler1].quickDraw || gProtectStructs[battler1].usedCustapBerry;
bool32 battler2HasQuickEffect = gProtectStructs[battler2].quickDraw || gProtectStructs[battler2].usedCustapBerry;
bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || (ability1 == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gChosenMoveByBattler[battler1]));
bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || (ability2 == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gChosenMoveByBattler[battler2]));
bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || gProtectStructs[battler1].myceliumMight;
bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || gProtectStructs[battler2].myceliumMight;
if (battler1HasQuickEffect && !battler2HasQuickEffect)
strikesFirst = 1;
else if (battler2HasQuickEffect && !battler1HasQuickEffect)
strikesFirst = -1;
else if (holdEffectBattler1 == HOLD_EFFECT_LAGGING_TAIL && holdEffectBattler2 != HOLD_EFFECT_LAGGING_TAIL)
else if (gProtectStructs[battler1].laggingTail && !gProtectStructs[battler2].laggingTail)
strikesFirst = -1;
else if (holdEffectBattler2 == HOLD_EFFECT_LAGGING_TAIL && holdEffectBattler1 != HOLD_EFFECT_LAGGING_TAIL)
else if (gProtectStructs[battler2].laggingTail && !gProtectStructs[battler1].laggingTail)
strikesFirst = 1;
else if (battler1HasStallingAbility && !battler2HasStallingAbility)
strikesFirst = -1;
@ -4668,12 +4713,12 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov
s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves)
{
s32 priority1 = 0, priority2 = 0;
u32 ability1 = GetBattlerAbility(battler1);
enum Ability ability1 = GetBattlerAbility(battler1);
u32 speedBattler1 = GetBattlerTotalSpeedStat(battler1);
enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE);
enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1);
u32 speedBattler2 = GetBattlerTotalSpeedStat(battler2);
enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE);
u32 ability2 = GetBattlerAbility(battler2);
enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2);
enum Ability ability2 = GetBattlerAbility(battler2);
if (!ignoreChosenMoves)
{
@ -4874,15 +4919,15 @@ static void TurnValuesCleanUp(bool8 var0)
{
gDisableStructs[i].rechargeTimer--;
if (gDisableStructs[i].rechargeTimer == 0)
gBattleMons[i].status2 &= ~STATUS2_RECHARGE;
gBattleMons[i].volatiles.recharge = FALSE;
}
gBattleStruct->battlerState[i].canPickupItem = FALSE;
}
if (gDisableStructs[i].substituteHP == 0)
gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE;
gBattleMons[i].volatiles.substitute = FALSE;
if (!(gStatuses3[i] & STATUS3_COMMANDER))
if (gBattleMons[i].volatiles.semiInvulnerable != STATE_COMMANDER)
gBattleStruct->battlerState[i].commandingDondozo = FALSE;
gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF;
@ -4942,7 +4987,7 @@ static bool32 TryDoGimmicksBeforeMoves(void)
}
}
if (B_MEGA_EVO_TURN_ORDER >= GEN_7)
if (GetGenConfig(GEN_CONFIG_MEGA_EVO_TURN_ORDER) >= GEN_7)
TryChangeTurnOrder(); // This will just do nothing if no mon has mega evolved.
return FALSE;
}
@ -5009,10 +5054,10 @@ static void TryChangeTurnOrder(void)
static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickClawRandom, u32 *quickDrawRandom)
{
u32 ability1 = GetBattlerAbility(battler1);
enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE);
enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE);
u32 ability2 = GetBattlerAbility(battler2);
enum Ability ability1 = GetBattlerAbility(battler1);
enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1);
enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2);
enum Ability ability2 = GetBattlerAbility(battler2);
// Battler 1
// Quick Draw
@ -5056,14 +5101,14 @@ static void CheckChangingTurnOrderEffects(void)
{
gLastUsedItem = gBattleMons[battler].item;
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem);
if (GetBattlerHoldEffect(battler, FALSE) == HOLD_EFFECT_CUSTAP_BERRY)
if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_CUSTAP_BERRY)
{
// don't record berry since its gone now
BattleScriptExecute(BattleScript_CustapBerryActivation);
}
else
{
RecordItemEffectBattle(battler, GetBattlerHoldEffect(battler, FALSE));
RecordItemEffectBattle(battler, GetBattlerHoldEffect(battler));
BattleScriptExecute(BattleScript_QuickClawActivation);
}
}
@ -5089,14 +5134,13 @@ static void CheckChangingTurnOrderEffects(void)
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
gBattleStruct->battlerState[i].focusPunchBattlers = FALSE;
gBattleStruct->ateBoost[i] = FALSE;
gBattleStruct->battlerState[i].ateBoost = FALSE;
gSpecialStatuses[i].gemBoost = FALSE;
}
gBattleMainFunc = RunTurnActionsFunctions;
gBattleCommunication[3] = 0;
gBattleCommunication[4] = 0;
gBattleScripting.multihitMoveEffect = 0;
gBattleResources->battleScriptsStack->size = 0;
}
@ -5128,14 +5172,14 @@ static void RunTurnActionsFunctions(void)
if (gCurrentTurnActionNumber >= gBattlersCount) // everyone did their actions, turn finished
{
gHitMarker &= ~HITMARKER_PASSIVE_DAMAGE;
gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE;
gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F];
}
else
{
if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battler
{
gHitMarker &= ~HITMARKER_NO_ATTACKSTRING;
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE;
}
}
@ -5261,7 +5305,8 @@ static void HandleEndTurn_FinishBattle(void)
| BATTLE_TYPE_BATTLE_TOWER
| BATTLE_TYPE_SAFARI
| BATTLE_TYPE_FIRST_BATTLE
| BATTLE_TYPE_LINK)))
| BATTLE_TYPE_LINK))
&& !(gBattleTypeFlags & BATTLE_TYPE_GHOST && IsGhostBattleWithoutScope()))
{
for (battler = 0; battler < gBattlersCount; battler++)
{
@ -5278,11 +5323,16 @@ static void HandleEndTurn_FinishBattle(void)
GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, gBattleResults.playerMon2Name);
}
}
else if (!IsOnPlayerSide(battler))
{
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality);
}
}
}
TrySetQuestLogBattleEvent();
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
ClearRematchStateByTrainerId();
RecordedBattle_SetPlaybackFinished();
if (gTestRunnerEnabled)
TestRunner_Battle_AfterLastTurn();
@ -5310,8 +5360,8 @@ static void HandleEndTurn_FinishBattle(void)
changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE);
// Clear original species field
gBattleStruct->changedSpecies[B_SIDE_PLAYER][i] = SPECIES_NONE;
gBattleStruct->changedSpecies[B_SIDE_OPPONENT][i] = SPECIES_NONE;
gBattleStruct->partyState[B_SIDE_PLAYER][i].changedSpecies = SPECIES_NONE;
gBattleStruct->partyState[B_SIDE_OPPONENT][i].changedSpecies = SPECIES_NONE;
// Recalculate the stats of every party member before the end
if (!changedForm && B_RECALCULATE_STATS >= GEN_5)
@ -5482,7 +5532,7 @@ void RunBattleScriptCommands(void)
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
u32 TrySetAteType(u32 move, u32 battlerAtk, u32 attackerAbility)
u32 TrySetAteType(u32 move, u32 battlerAtk, enum Ability attackerAbility)
{
u32 ateType = TYPE_NONE;
@ -5534,7 +5584,8 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState
{
u32 moveType = GetMoveType(move);
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
u32 species, heldItem, ability, type1, type2, type3;
u32 species, heldItem, type1, type2, type3;
enum Ability ability;
enum ItemHoldEffect holdEffect;
enum Gimmick gimmick = GetActiveGimmick(battler);
@ -5545,7 +5596,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState
{
species = gBattleMons[battler].species;
heldItem = gBattleMons[battler].item;
holdEffect = GetBattlerHoldEffect(battler, TRUE);
holdEffect = GetBattlerHoldEffect(battler);
ability = GetBattlerAbility(battler);
type1 = gBattleMons[battler].types[0];
type2 = gBattleMons[battler].types[1];
@ -5687,7 +5738,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState
case EFFECT_TERRAIN_PULSE:
if (state == MON_IN_BATTLE)
{
if (IsBattlerTerrainAffected(battler, STATUS_FIELD_TERRAIN_ANY))
if (IsBattlerTerrainAffected(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler), STATUS_FIELD_TERRAIN_ANY))
{
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
return TYPE_ELECTRIC;
@ -5747,7 +5798,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState
{
u32 ateType = TrySetAteType(move, battler, ability);
if (ateType != TYPE_NONE && state == MON_IN_BATTLE)
gBattleStruct->ateBoost[battler] = TRUE;
gBattleStruct->battlerState[battler].ateBoost = TRUE;
return ateType;
}
else if (moveEffect != EFFECT_CHANGE_TYPE_ON_ITEM
@ -5759,7 +5810,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState
&& gimmick != GIMMICK_Z_MOVE)
{
if (state == MON_IN_BATTLE && gimmick != GIMMICK_DYNAMAX)
gBattleStruct->ateBoost[battler] = TRUE;
gBattleStruct->battlerState[battler].ateBoost = TRUE;
return TYPE_NORMAL;
}
@ -5770,10 +5821,10 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler)
{
u32 moveType;
u32 heldItem = gBattleMons[battler].item;
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler);
gBattleStruct->dynamicMoveType = 0;
gBattleStruct->ateBoost[battler] = FALSE;
gBattleStruct->battlerState[battler].ateBoost = FALSE;
gSpecialStatuses[battler].gemBoost = FALSE;
moveType = GetDynamicMoveType(GetBattlerMon(battler),
@ -5785,7 +5836,8 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler)
gBattleStruct->dynamicMoveType = moveType | F_DYNAMIC_TYPE_SET;
moveType = GetBattleMoveType(move);
if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL) || gStatuses4[battler] & STATUS4_ELECTRIFIED)
if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL)
|| gBattleMons[battler].volatiles.electrified)
gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | F_DYNAMIC_TYPE_SET;
// Check if a gem should activate.
@ -5861,3 +5913,10 @@ static s32 Factorial(s32 n)
// return (gBattleOutcome == B_OUTCOME_FORFEITED);
// }
// Wins the battle instantly. Used in the battle debug with LIST_ITEM_INSTANT_WIN
void BattleDebug_WonBattle(void)
{
gBattleOutcome |= B_OUTCOME_WON;
gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F];
}

View File

@ -301,13 +301,12 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PLAYERWHITEOUT2_WILD] = COMPOUND_STRING("You panicked and dropped ¥{B_BUFF1}…"),
[STRINGID_PLAYERWHITEOUT2_TRAINER] = COMPOUND_STRING("You gave ¥{B_BUFF1} to the winner…"),
[STRINGID_PLAYERWHITEOUT3] = COMPOUND_STRING("You were overwhelmed by your defeat!"),
[STRINGID_PREVENTSESCAPE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} prevents escape with {B_SCR_ACTIVE_ABILITY}!\p"),
[STRINGID_PREVENTSESCAPE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} prevents escape with {B_SCR_ABILITY}!\p"),
[STRINGID_HITXTIMES] = COMPOUND_STRING("The Pokémon was hit {B_BUFF1} time(s)!"), //SV has dynamic plural here
[STRINGID_PKMNFELLASLEEP] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} fell asleep!"),
[STRINGID_PKMNMADESLEEP] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_BUFF1} made {B_EFF_NAME_WITH_PREFIX2} sleep!"), //not in gen 5+, ability popup
[STRINGID_PKMNALREADYASLEEP] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is already asleep!"),
[STRINGID_PKMNALREADYASLEEP2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is already asleep!"),
[STRINGID_PKMNWASNTAFFECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} wasn't affected!"), //not in gen 5+, ability popup
[STRINGID_PKMNWASPOISONED] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} was poisoned!"),
[STRINGID_PKMNPOISONEDBY] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} was poisoned by {B_SCR_NAME_WITH_PREFIX2}'s {B_BUFF1}!"), //not in gen 5+, ability popup
[STRINGID_PKMNHURTBYPOISON] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} was hurt by its poisoning!"),
@ -328,11 +327,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNISPARALYZED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} couldn't move because it's paralyzed!"),
[STRINGID_PKMNISALREADYPARALYZED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is already paralyzed!"),
[STRINGID_PKMNHEALEDPARALYSIS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was cured of paralysis!"),
[STRINGID_PKMNDREAMEATEN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s dream was eaten!"), //not in gen 5+, expansion doesn't use anymore
[STRINGID_STATSWONTINCREASE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} won't go any higher!"),
[STRINGID_STATSWONTDECREASE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} won't go any lower!"),
[STRINGID_TEAMSTOPPEDWORKING] = COMPOUND_STRING("Your team's {B_BUFF1} stopped working!"), //unused
[STRINGID_FOESTOPPEDWORKING] = COMPOUND_STRING("The foe's {B_BUFF1} stopped working!"), //unused
[STRINGID_PKMNISCONFUSED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is confused!"),
[STRINGID_PKMNHEALEDCONFUSION] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} snapped out of its confusion!"),
[STRINGID_PKMNWASCONFUSED] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} became confused!"),
@ -340,7 +336,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNFELLINLOVE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fell in love!"),
[STRINGID_PKMNINLOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is in love with {B_SCR_NAME_WITH_PREFIX2}!"),
[STRINGID_PKMNIMMOBILIZEDBYLOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is immobilized by love!"),
[STRINGID_PKMNBLOWNAWAY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was blown away!"), //unused
[STRINGID_PKMNCHANGEDTYPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} transformed into the {B_BUFF1} type!"),
[STRINGID_PKMNFLINCHED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} flinched and couldn't move!"),
[STRINGID_PKMNREGAINEDHEALTH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s HP was restored."),
@ -378,13 +373,12 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNFASTASLEEP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is fast asleep."),
[STRINGID_PKMNWOKEUP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} woke up!"),
[STRINGID_PKMNUPROARKEPTAWAKE] = COMPOUND_STRING("But the uproar kept {B_SCR_NAME_WITH_PREFIX2} awake!"),
[STRINGID_PKMNWOKEUPINUPROAR] = COMPOUND_STRING("The uproar woke {B_ATK_NAME_WITH_PREFIX2}!"),
[STRINGID_PKMNWOKEUPINUPROAR] = COMPOUND_STRING("The uproar woke {B_EFF_NAME_WITH_PREFIX2}!"),
[STRINGID_PKMNCAUSEDUPROAR] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} caused an uproar!"),
[STRINGID_PKMNMAKINGUPROAR] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is making an uproar!"),
[STRINGID_PKMNCALMEDDOWN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} calmed down."),
[STRINGID_PKMNCANTSLEEPINUPROAR] = COMPOUND_STRING("But {B_DEF_NAME_WITH_PREFIX2} can't sleep in an uproar!"),
[STRINGID_PKMNSTOCKPILED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stockpiled {B_BUFF1}!"),
[STRINGID_PKMNCANTSTOCKPILE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can't stockpile any more!"), //I think this was replaced with just "But it failed!"
[STRINGID_PKMNCANTSLEEPINUPROAR2] = COMPOUND_STRING("But {B_DEF_NAME_WITH_PREFIX2} can't sleep in an uproar!"),
[STRINGID_UPROARKEPTPKMNAWAKE] = COMPOUND_STRING("But the uproar kept {B_DEF_NAME_WITH_PREFIX2} awake!"),
[STRINGID_PKMNSTAYEDAWAKEUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} stayed awake using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
@ -425,14 +419,14 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNENDUREDHIT] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} endured the hit!"),
[STRINGID_MAGNITUDESTRENGTH] = COMPOUND_STRING("Magnitude {B_BUFF1}!"),
[STRINGID_PKMNCUTHPMAXEDATTACK] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} cut its own HP and maximized its Attack!"),
[STRINGID_PKMNCOPIEDSTATCHANGES] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} copied {B_DEF_NAME_WITH_PREFIX2}'s stat changes!"),
[STRINGID_PKMNCOPIEDSTATCHANGES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} copied {B_EFF_NAME_WITH_PREFIX2}'s stat changes!"),
[STRINGID_PKMNGOTFREE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} got free of {B_DEF_NAME_WITH_PREFIX2}'s {B_BUFF1}!"), //not in gen 5+, generic rapid spin?
[STRINGID_PKMNSHEDLEECHSEED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} shed Leech Seed!"), //not in gen 5+, generic rapid spin?
[STRINGID_PKMNBLEWAWAYSPIKES] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} blew away Spikes!"), //not in gen 5+, generic rapid spin?
[STRINGID_PKMNFLEDFROMBATTLE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} fled from battle!"),
[STRINGID_PKMNFORESAWATTACK] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} foresaw an attack!"),
[STRINGID_PKMNTOOKATTACK] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} took the {B_BUFF1} attack!"),
[STRINGID_PKMNATTACK] = COMPOUND_STRING("{B_BUFF1}'s attack!"), //not in gen 5+, expansion doesn't use anymore
[STRINGID_PKMNATTACK] = COMPOUND_STRING("{B_BUFF1}'s attack!"), //not in gen 5+
[STRINGID_PKMNCENTERATTENTION] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} became the center of attention!"),
[STRINGID_PKMNCHARGINGPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} began charging power!"),
[STRINGID_NATUREPOWERTURNEDINTO] = COMPOUND_STRING("Nature Power turned into {B_CURRENT_MOVE}!"),
@ -446,7 +440,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNREADYTOHELP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is ready to help {B_DEF_NAME_WITH_PREFIX2}!"),
[STRINGID_PKMNSWITCHEDITEMS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} switched items with its target!"),
[STRINGID_PKMNCOPIEDFOE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} copied {B_DEF_NAME_WITH_PREFIX2}'s Ability!"),
[STRINGID_PKMNMADEWISH] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} made a wish!"), //unused
[STRINGID_PKMNWISHCAMETRUE] = COMPOUND_STRING("{B_BUFF1}'s wish came true!"),
[STRINGID_PKMNPLANTEDROOTS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} planted its roots!"),
[STRINGID_PKMNABSORBEDNUTRIENTS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} absorbed nutrients with its roots!"),
@ -462,30 +455,27 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNMOVEBOUNCED] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} bounced the {B_CURRENT_MOVE} back!"),
[STRINGID_PKMNWAITSFORTARGET] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} waits for a target to make a move!"),
[STRINGID_PKMNSNATCHEDMOVE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} snatched {B_SCR_NAME_WITH_PREFIX2}'s move!"),
[STRINGID_PKMNMADEITRAIN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} made it rain!"), //not in gen 5+, ability popup
[STRINGID_PKMNRAISEDSPEED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} raised its Speed!"), //not in gen 5+, ability popup
[STRINGID_PKMNMADEITRAIN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} made it rain!"), //not in gen 5+, ability popup
[STRINGID_PKMNPROTECTEDBY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was protected by {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSUSAGE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents {B_ATK_NAME_WITH_PREFIX2} from using {B_CURRENT_MOVE}!"), //I don't see this in SV text
[STRINGID_PKMNRESTOREDHPUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} restored HP using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
[STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSPARALYSISWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} prevents paralysis!"), //not in gen 5+, ability popup
[STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSROMANCEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents romance!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSPOISONINGWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} prevents poisoning!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSCONFUSIONWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents confusion!"), //not in gen 5+, ability popup
[STRINGID_PKMNRAISEDFIREPOWERWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} raised the power of Fire-type moves!"), //not in gen 5+, ability popup
[STRINGID_PKMNANCHORSITSELFWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} anchors itself with {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
[STRINGID_PKMNCUTSATTACKWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} cuts {B_DEF_NAME_WITH_PREFIX2}'s Attack!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSSTATLOSSWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} prevents stat loss!"), //not in gen 5+, ability popup
[STRINGID_PKMNCUTSATTACKWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} cuts {B_DEF_NAME_WITH_PREFIX2}'s Attack!"), //not in gen 5+, ability popup
[STRINGID_PKMNPREVENTSSTATLOSSWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} prevents stat loss!"), //not in gen 5+, ability popup
[STRINGID_PKMNHURTSWITH] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} was hurt by {B_DEF_NAME_WITH_PREFIX2}'s {B_BUFF1}!"),
[STRINGID_PKMNTRACED] = COMPOUND_STRING("It traced {B_BUFF1}'s {B_BUFF2}!"),
[STRINGID_STATSHARPLY] = gText_StatSharply,
[STRINGID_STATROSE] = gText_StatRose,
[STRINGID_STATHARSHLY] = COMPOUND_STRING("harshly "),
[STRINGID_STATFELL] = gText_StatFell,
[STRINGID_ATTACKERSSTATROSE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"),
[STRINGID_ATTACKERSSTATROSE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}rose!"),
[STRINGID_DEFENDERSSTATROSE] = gText_DefendersStatRose,
[STRINGID_ATTACKERSSTATFELL] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"),
[STRINGID_DEFENDERSSTATFELL] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"),
[STRINGID_ATTACKERSSTATFELL] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}fell!"),
[STRINGID_DEFENDERSSTATFELL] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}fell!"),
[STRINGID_CRITICALHIT] = COMPOUND_STRING("A critical hit!"),
[STRINGID_ONEHITKO] = COMPOUND_STRING("It's a one-hit KO!"),
[STRINGID_123POOF] = COMPOUND_STRING("One…{PAUSE 10}two…{PAUSE 10}and…{PAUSE 10}{PAUSE 20}{PLAY_SE SE_BALL_BOUNCE_1}ta-da!\p"),
@ -500,7 +490,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_BUTNOTHINGHAPPENED] = COMPOUND_STRING("But nothing happened!"),
[STRINGID_BUTITFAILED] = COMPOUND_STRING("But it failed!"),
[STRINGID_ITHURTCONFUSION] = COMPOUND_STRING("It hurt itself in its confusion!"),
[STRINGID_MIRRORMOVEFAILED] = COMPOUND_STRING("The Mirror Move failed!"), //not in gen 5+, uses "but it failed"
[STRINGID_STARTEDTORAIN] = COMPOUND_STRING("It started to rain!"),
[STRINGID_DOWNPOURSTARTED] = COMPOUND_STRING("A downpour started!"), // corresponds to DownpourText in pokegold and pokecrystal and is used by Rain Dance in GSC
[STRINGID_RAINCONTINUES] = COMPOUND_STRING("Rain continues to fall."), //not in gen 5+
@ -515,9 +504,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_STARTEDHAIL] = COMPOUND_STRING("It started to hail!"),
[STRINGID_HAILCONTINUES] = COMPOUND_STRING("The hail is crashing down."),
[STRINGID_HAILSTOPPED] = COMPOUND_STRING("The hail stopped."),
[STRINGID_FAILEDTOSPITUP] = COMPOUND_STRING("But it failed to spit up a thing!"), //not in gen 5+, uses "but it failed"
[STRINGID_FAILEDTOSWALLOW] = COMPOUND_STRING("But it failed to swallow a thing!"), //not in gen 5+, uses "but it failed"
[STRINGID_WINDBECAMEHEATWAVE] = COMPOUND_STRING("The wind turned into a Heat Wave!"), //unused
[STRINGID_STATCHANGESGONE] = COMPOUND_STRING("All stat changes were eliminated!"),
[STRINGID_COINSSCATTERED] = COMPOUND_STRING("Coins were scattered everywhere!"),
[STRINGID_TOOWEAKFORSUBSTITUTE] = COMPOUND_STRING("But it does not have enough HP left to make a substitute!"),
@ -574,14 +560,13 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_ITEMALLOWSONLYYMOVE] = COMPOUND_STRING("{B_LAST_ITEM} only allows the use of {B_CURRENT_MOVE}!\p"),
[STRINGID_PKMNHUNGONWITHX] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} hung on using its {B_LAST_ITEM}!"),
[STRINGID_EMPTYSTRING3] = gText_EmptyString3,
[STRINGID_PKMNSXPREVENTSBURNS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} prevents burns!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXBLOCKSY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXRESTOREDHPALITTLE2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} restored its HP a little!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXWHIPPEDUPSANDSTORM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} whipped up a sandstorm!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXPREVENTSYLOSS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} prevents {B_BUFF1} loss!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXWHIPPEDUPSANDSTORM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} whipped up a sandstorm!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXPREVENTSYLOSS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} prevents {B_BUFF1} loss!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXINFATUATEDY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} infatuated {B_ATK_NAME_WITH_PREFIX2}!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXMADEYINEFFECTIVE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} made {B_CURRENT_MOVE} ineffective!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXCUREDYPROBLEM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} cured its {B_BUFF1} problem!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXCUREDYPROBLEM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} cured its {B_BUFF1} problem!"), //not in gen 5+, ability popup
[STRINGID_ITSUCKEDLIQUIDOOZE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} sucked up the liquid ooze!"),
[STRINGID_PKMNTRANSFORMED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} transformed!"),
[STRINGID_ELECTRICITYWEAKENED] = COMPOUND_STRING("Electricity's power was weakened!"),
@ -593,14 +578,14 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PLAYERDEFEATEDTRAINER1] = sText_PlayerDefeatedLinkTrainerTrainer1,
[STRINGID_SOOTHINGAROMA] = COMPOUND_STRING("A soothing aroma wafted through the area!"),
[STRINGID_ITEMSCANTBEUSEDNOW] = COMPOUND_STRING("Items can't be used now.{PAUSE 64}"), //not in gen 5+, i think
[STRINGID_FORXCOMMAYZ] = COMPOUND_STRING("For {B_SCR_NAME_WITH_PREFIX2}, {B_LAST_ITEM} {B_BUFF1}"), //not in gen 5+, expansion doesn't use anymore
[STRINGID_USINGITEMSTATOFPKMNROSE] = COMPOUND_STRING("Using {B_LAST_ITEM}, the {B_BUFF1} of {B_SCR_NAME_WITH_PREFIX2} {B_BUFF2}"), //todo: update this, will require code changes
[STRINGID_USINGITEMSTATOFPKMNROSE] = COMPOUND_STRING("Using {B_LAST_ITEM}, the {B_BUFF1} of {B_SCR_NAME_WITH_PREFIX2} {B_BUFF2}rose!"), //todo: update this, will require code changes
[STRINGID_USINGITEMSTATOFPKMNFELL] = COMPOUND_STRING("Using {B_LAST_ITEM}, the {B_BUFF1} of {B_SCR_NAME_WITH_PREFIX2} {B_BUFF2}fell!"),
[STRINGID_PKMNUSEDXTOGETPUMPED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} used the {B_LAST_ITEM} to get pumped!"),
[STRINGID_PKMNSXMADEYUSELESS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} made {B_CURRENT_MOVE} useless!"), //not in gen 5+, ability popup
[STRINGID_PKMNTRAPPEDBYSANDTOMB] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} became trapped by the quicksand!"),
[STRINGID_EMPTYSTRING4] = COMPOUND_STRING(""),
[STRINGID_ABOOSTED] = COMPOUND_STRING(" a boosted"),
[STRINGID_PKMNSXINTENSIFIEDSUN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} intensified the sun's rays!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXINTENSIFIEDSUN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} intensified the sun's rays!"), //not in gen 5+, ability popup
[STRINGID_PKMNMAKESGROUNDMISS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} makes Ground-type moves miss with {B_DEF_ABILITY}!"), //not in gen 5+, ability popup
[STRINGID_YOUTHROWABALLNOWRIGHT] = COMPOUND_STRING("You throw a Ball now, right? I… I'll do my best!"),
[STRINGID_PKMNSXTOOKATTACK] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} took the attack!"), //In gen 5+ but without naming the ability
@ -610,28 +595,23 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNFLEDUSINGITS] = COMPOUND_STRING("{PLAY_SE SE_FLEE}{B_ATK_NAME_WITH_PREFIX} fled using its {B_LAST_ITEM}!\p"),
[STRINGID_PKMNFLEDUSING] = COMPOUND_STRING("{PLAY_SE SE_FLEE}{B_ATK_NAME_WITH_PREFIX} fled using {B_ATK_ABILITY}!\p"), //not in gen 5+
[STRINGID_PKMNWASDRAGGEDOUT] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was dragged out!\p"),
[STRINGID_PREVENTEDFROMWORKING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevented {B_SCR_NAME_WITH_PREFIX2}'s {B_BUFF1} from working!"), //unused
[STRINGID_PKMNSITEMNORMALIZEDSTATUS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_LAST_ITEM} normalized its status!"),
[STRINGID_TRAINER1USEDITEM] = COMPOUND_STRING("{B_ATK_TRAINER_NAME_WITH_CLASS} used {B_LAST_ITEM}!"),
[STRINGID_BOXISFULL] = COMPOUND_STRING("The Box is full! You can't catch any more!\p"),
[STRINGID_PKMNAVOIDEDATTACK] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} avoided the attack!"),
[STRINGID_PKMNSXMADEITINEFFECTIVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} made it ineffective!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXMADEITINEFFECTIVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} made it ineffective!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXPREVENTSFLINCHING] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} prevents flinching!"), //not in gen 5+, ability popup
[STRINGID_PKMNALREADYHASBURN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is already burned!"),
[STRINGID_STATSWONTDECREASE2] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s stats won't go any lower!"),
[STRINGID_PKMNSXBLOCKSY2] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXBLOCKSY2] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXWOREOFF] = COMPOUND_STRING("{B_ATK_TEAM1} team's {B_BUFF1} wore off!"),
[STRINGID_PKMNRAISEDDEFALITTLE] = COMPOUND_STRING("{B_ATK_PREFIX1}'s {B_CURRENT_MOVE} raised DEFENSE a little!"), //expansion doesn't use anymore
[STRINGID_PKMNRAISEDSPDEFALITTLE] = COMPOUND_STRING("{B_ATK_PREFIX1}'s {B_CURRENT_MOVE} raised SP. DEF a little!"), //expansion doesn't use anymore
[STRINGID_THEWALLSHATTERED] = COMPOUND_STRING("The wall shattered!"), //not in gen5+, uses "your teams light screen wore off!" etc instead
[STRINGID_PKMNSXPREVENTSYSZ] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} prevents {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY} from working!"),
[STRINGID_PKMNSXCUREDITSYPROBLEM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} cured its {B_BUFF1} problem!"), //not in gen 5+, ability popup
[STRINGID_PKMNSXCUREDITSYPROBLEM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} cured its {B_BUFF1} problem!"), //not in gen 5+, ability popup
[STRINGID_ATTACKERCANTESCAPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can't escape!"),
[STRINGID_PKMNOBTAINEDX] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} obtained {B_BUFF1}."),
[STRINGID_PKMNOBTAINEDX2] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} obtained {B_BUFF2}."),
[STRINGID_PKMNOBTAINEDXYOBTAINEDZ] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} obtained {B_BUFF1}.\p{B_DEF_NAME_WITH_PREFIX} obtained {B_BUFF2}."),
[STRINGID_BUTNOEFFECT] = COMPOUND_STRING("But it had no effect!"),
[STRINGID_PKMNSXHADNOEFFECTONY] = COMPOUND_STRING("Target protected by {B_LAST_ABILITY}!"), //not in gen 5+, ability popup
[STRINGID_TWOENEMIESDEFEATED] = sText_TwoInGameTrainersDefeated,
[STRINGID_TRAINER2LOSETEXT] = COMPOUND_STRING("{B_TRAINER2_LOSE_TEXT}"),
[STRINGID_PKMNINCAPABLEOFPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} appears incapable of using its power!"),
@ -690,10 +670,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_FELLSTRAIGHTDOWN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fell straight down!"),
[STRINGID_TARGETCHANGEDTYPE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} transformed into the {B_BUFF1} type!"),
[STRINGID_PKMNACQUIREDSIMPLE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} acquired Simple!"), //shouldn't directly use the name
[STRINGID_EMPTYSTRING5] = sText_EmptyString4,
[STRINGID_KINDOFFER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} took the kind offer!"),
[STRINGID_RESETSTARGETSSTATLEVELS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s stat changes were removed!"),
[STRINGID_EMPTYSTRING6] = sText_EmptyString4,
[STRINGID_ALLYSWITCHPOSITION] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} and {B_SCR_NAME_WITH_PREFIX2} switched places!"),
[STRINGID_RESTORETARGETSHEALTH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s HP was restored!"),
[STRINGID_TOOKPJMNINTOTHESKY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} took {B_DEF_NAME_WITH_PREFIX2} into the sky!"),
@ -718,9 +696,9 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_MISTYTERRAINENDS] = COMPOUND_STRING("The mist disappeared from the battlefield."),
[STRINGID_PSYCHICTERRAINENDS] = COMPOUND_STRING("The weirdness disappeared from the battlefield!"),
[STRINGID_GRASSYTERRAINENDS] = COMPOUND_STRING("The grass disappeared from the battlefield."),
[STRINGID_TARGETABILITYSTATRAISE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} raised its {B_BUFF1}!"),
[STRINGID_TARGETABILITYSTATRAISE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} {B_BUFF2}raised its {B_BUFF1}!"),
[STRINGID_TARGETSSTATWASMAXEDOUT] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} maxed its {B_BUFF1}!"),
[STRINGID_ATTACKERABILITYSTATRAISE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} raised its {B_BUFF1}!"),
[STRINGID_ATTACKERABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} {B_BUFF2}raised its {B_BUFF1}!"),
[STRINGID_POISONHEALHPUP] = COMPOUND_STRING("The poisoning healed {B_ATK_NAME_WITH_PREFIX2} a little bit!"), //don't think this message is displayed anymore
[STRINGID_BADDREAMSDMG] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is tormented!"),
[STRINGID_MOLDBREAKERENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} breaks the mold!"),
@ -731,26 +709,26 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_SOLARPOWERHPDROP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} takes its toll!"), //don't think this message is displayed anymore
[STRINGID_AFTERMATHDMG] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} was hurt!"),
[STRINGID_ANTICIPATIONACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} shuddered!"),
[STRINGID_FOREWARNACTIVATES] = COMPOUND_STRING("{B_SCR_ACTIVE_ABILITY} alerted {B_SCR_NAME_WITH_PREFIX2} to {B_DEF_NAME_WITH_PREFIX2}'s {B_BUFF1}!"),
[STRINGID_FOREWARNACTIVATES] = COMPOUND_STRING("{B_SCR_ABILITY} alerted {B_SCR_NAME_WITH_PREFIX2} to {B_EFF_NAME_WITH_PREFIX2}'s {B_BUFF1}!"),
[STRINGID_ICEBODYHPGAIN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} healed it a little bit!"), //don't think this message is displayed anymore
[STRINGID_SNOWWARNINGHAIL] = COMPOUND_STRING("It started to hail!"),
[STRINGID_FRISKACTIVATES] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} frisked {B_DEF_NAME_WITH_PREFIX2} and found its {B_LAST_ITEM}!"),
[STRINGID_UNNERVEENTERS] = COMPOUND_STRING("{B_DEF_TEAM1} team is too nervous to eat Berries!"),
[STRINGID_UNNERVEENTERS] = COMPOUND_STRING("{B_EFF_TEAM1} team is too nervous to eat Berries!"),
[STRINGID_HARVESTBERRY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} harvested its {B_LAST_ITEM}!"),
[STRINGID_MAGICBOUNCEACTIVATES] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} bounced the {B_ATK_NAME_WITH_PREFIX2} back!"),
[STRINGID_PROTEANTYPECHANGE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} transformed it into the {B_BUFF1} type!"),
[STRINGID_SYMBIOSISITEMPASS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} passed its {B_LAST_ITEM} to {B_EFF_NAME_WITH_PREFIX2} through {B_LAST_ABILITY}!"),
[STRINGID_STEALTHROCKDMG] = COMPOUND_STRING("Pointed stones dug into {B_SCR_NAME_WITH_PREFIX2}!"),
[STRINGID_TOXICSPIKESABSORBED] = COMPOUND_STRING("The poison spikes disappeared from the ground around {B_SCR_TEAM2} team!"),
[STRINGID_TOXICSPIKESABSORBED] = COMPOUND_STRING("The poison spikes disappeared from the ground around {B_EFF_TEAM2} team!"),
[STRINGID_TOXICSPIKESPOISONED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} was poisoned!"),
[STRINGID_TOXICSPIKESBADLYPOISONED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} was badly poisoned!"),
[STRINGID_STICKYWEBSWITCHIN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} was caught in a sticky web!"),
[STRINGID_HEALINGWISHCAMETRUE] = COMPOUND_STRING("The healing wish came true for {B_ATK_NAME_WITH_PREFIX2}!"),
[STRINGID_HEALINGWISHHEALED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} regained health!"),
[STRINGID_LUNARDANCECAMETRUE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became cloaked in mystical moonlight!"),
[STRINGID_CUSEDBODYDISABLED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} was disabled by {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY}!"),
[STRINGID_CURSEDBODYDISABLED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} was disabled by {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY}!"),
[STRINGID_ATTACKERACQUIREDABILITY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} acquired {B_ATK_ABILITY}!"),
[STRINGID_TARGETABILITYSTATLOWER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} lowered its {B_BUFF1}!"),
[STRINGID_TARGETABILITYSTATLOWER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} {B_BUFF2}lowered its {B_BUFF1}!"),
[STRINGID_TARGETSTATWONTGOHIGHER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} won't go any higher!"),
[STRINGID_PKMNMOVEBOUNCEDABILITY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} was bounced back by {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY}!"),
[STRINGID_IMPOSTERTRANSFORM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} transformed into {B_DEF_NAME_WITH_PREFIX2} using {B_LAST_ABILITY}!"),
@ -789,7 +767,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_MISTYTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with a protective mist!"),
[STRINGID_GRASSYTERRAINHEALS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is healed by the grassy terrain!"),
[STRINGID_ELECTRICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with electrified terrain!"),
[STRINGID_PSYCHICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with psychic terrain!"),
[STRINGID_PSYCHICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is protected by the Psychic Terrain!"),
[STRINGID_SAFETYGOGGLESPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is not affected thanks to its {B_LAST_ITEM}!"),
[STRINGID_FLOWERVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounded itself with a veil of petals!"),
[STRINGID_SWEETVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} can't fall asleep due to a veil of sweetness!"),
@ -809,8 +787,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_ATTACKERCUREDTARGETSTATUS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} cured {B_DEF_NAME_WITH_PREFIX2}'s problem!"),
[STRINGID_ATTACKERLOSTFIRETYPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} burned itself out!"),
[STRINGID_HEALERCURE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} cured {B_SCR_NAME_WITH_PREFIX2}'s problem!"),
[STRINGID_SCRIPTINGABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} raised its {B_BUFF1}!"),
[STRINGID_RECEIVERABILITYTAKEOVER] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} was taken over!"),
[STRINGID_SCRIPTINGABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} {B_BUFF2}raised its {B_BUFF1}!"),
[STRINGID_RECEIVERABILITYTAKEOVER] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} was taken over!"),
[STRINGID_PKNMABSORBINGPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is absorbing power!"),
[STRINGID_NOONEWILLBEABLETORUNAWAY] = COMPOUND_STRING("No one will be able to run away during the next turn!"),
[STRINGID_DESTINYKNOTACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} fell in love because of the {B_LAST_ITEM}!"),
@ -825,10 +803,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_COMATOSEENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is drowsing!"),
[STRINGID_SCREENCLEANERENTERS] = COMPOUND_STRING("All screens on the field were cleansed!"),
[STRINGID_FETCHEDPOKEBALL] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} found a {B_LAST_ITEM}!"),
[STRINGID_BATTLERABILITYRAISEDSTAT] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} raised its {B_BUFF1}!"),
[STRINGID_ASANDSTORMKICKEDUP] = COMPOUND_STRING("A sandstorm kicked up!"),
[STRINGID_PKMNSWILLPERISHIN3TURNS] = COMPOUND_STRING("Both Pokémon will perish in three turns!"), //don't think this message is displayed anymore
[STRINGID_ABILITYRAISEDSTATDRASTICALLY] = COMPOUND_STRING("{B_DEF_ABILITY} raised {B_DEF_NAME_WITH_PREFIX2}'s {B_BUFF1} drastically!"),
[STRINGID_AURAFLAREDTOLIFE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s aura flared to life!"),
[STRINGID_ASONEENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} has two Abilities!"),
[STRINGID_CURIOUSMEDICINEENTERS] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s stat changes were removed!"),
@ -865,7 +841,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_BROKETHROUGHPROTECTION] = COMPOUND_STRING("It broke through {B_DEF_NAME_WITH_PREFIX2}'s protection!"),
[STRINGID_ABILITYALLOWSONLYMOVE] = COMPOUND_STRING("{B_ATK_ABILITY} only allows the use of {B_CURRENT_MOVE}!\p"),
[STRINGID_SWAPPEDABILITIES] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} swapped Abilities with its target!"),
[STRINGID_PASTELVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is protected by a pastel veil!"),
[STRINGID_PASTELVEILENTERS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was cured of its poisoning!"),
[STRINGID_BATTLERTYPECHANGEDTO] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s type changed to {B_BUFF1}!"),
[STRINGID_BOTHCANNOLONGERESCAPE] = COMPOUND_STRING("Neither Pokémon can run away!"),
@ -901,9 +876,9 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_SUNLIGHTACTIVATEDABILITY] = COMPOUND_STRING("The harsh sunlight activated {B_SCR_NAME_WITH_PREFIX2}'s Protosynthesis!"),
[STRINGID_STATWASHEIGHTENED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_BUFF1} was heightened!"),
[STRINGID_ELECTRICTERRAINACTIVATEDABILITY] = COMPOUND_STRING("The Electric Terrain activated {B_SCR_NAME_WITH_PREFIX2}'s Quark Drive!"),
[STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} weakened the {B_BUFF1} of all surrounding Pokémon!\p"),
[STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} weakened the {B_BUFF1} of all surrounding Pokémon!\p"),
[STRINGID_ATTACKERGAINEDSTRENGTHFROMTHEFALLEN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} gained strength from the fallen!"),
[STRINGID_PKMNSABILITYPREVENTSABILITY] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY} prevents {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY} from working!"), //not in gen 5+, ability popup
[STRINGID_PKMNSABILITYPREVENTSABILITY] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} prevents {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY} from working!"), //not in gen 5+, ability popup
[STRINGID_PREPARESHELLTRAP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} set a shell trap!"),
[STRINGID_SHELLTRAPDIDNTWORK] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s shell trap didn't work!"),
[STRINGID_SPIKESDISAPPEAREDFROMTEAM] = COMPOUND_STRING("The spikes disappeared from the ground around {B_ATK_TEAM2} team!"),
@ -935,7 +910,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_TEAMGAINEDEXP] = COMPOUND_STRING("The rest of your team gained Exp. Points thanks to the Exp. Share!\p"),
[STRINGID_CURRENTMOVECANTSELECT] = COMPOUND_STRING("{B_BUFF1} cannot be used!\p"),
[STRINGID_TARGETISBEINGSALTCURED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is being salt cured!"),
[STRINGID_TARGETISHURTBYSALTCURE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"),
[STRINGID_TARGETISHURTBYSALTCURE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"),
[STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} got covered in sticky candy syrup!"),
[STRINGID_SHARPSTEELFLOATS] = COMPOUND_STRING("Sharp-pointed pieces of steel started floating around {B_DEF_TEAM2} Pokémon!"),
[STRINGID_SHARPSTEELDMG] = COMPOUND_STRING("The sharp steel bit into {B_DEF_NAME_WITH_PREFIX2}!"),
@ -961,7 +936,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_SWAMPENVELOPEDSIDE] = COMPOUND_STRING("A swamp enveloped {B_DEF_TEAM2} team!"),
[STRINGID_THESWAMPDISAPPEARED] = COMPOUND_STRING("The swamp around {B_ATK_TEAM2} team disappeared!"),
[STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is preparing to tell a chillingly bad joke!"),
[STRINGID_HOSPITALITYRESTORATION] = COMPOUND_STRING("{B_ATK_PARTNER_NAME} drank down all the matcha that {B_ATK_NAME_WITH_PREFIX2} made!"),
[STRINGID_HOSPITALITYRESTORATION] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} drank down all the matcha that {B_SCR_NAME_WITH_PREFIX2} made!"),
[STRINGID_ELECTROSHOTCHARGING] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} absorbed electricity!"),
[STRINGID_ITEMWASUSEDUP] = COMPOUND_STRING("The {B_LAST_ITEM} was used up…"),
[STRINGID_ATTACKERLOSTITSTYPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} lost its {B_BUFF1} type!"),
@ -973,7 +948,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_BIZARREAREACREATED] = COMPOUND_STRING("A bizarre area was created in which Defense and Sp. Def stats are swapped!"),
[STRINGID_TIDYINGUPCOMPLETE] = COMPOUND_STRING("Tidying up complete!"),
[STRINGID_PKMNTERASTALLIZEDINTO] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} terastallized into the {B_BUFF1} type!"),
[STRINGID_BOOSTERENERGYACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} used its {B_LAST_ITEM} to activate {B_SCR_ACTIVE_ABILITY}!"),
[STRINGID_BOOSTERENERGYACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} used its {B_LAST_ITEM} to activate {B_SCR_ABILITY}!"),
[STRINGID_FOGCREPTUP] = COMPOUND_STRING("Fog crept up as thick as soup!"),
[STRINGID_FOGISDEEP] = COMPOUND_STRING("The fog is deep…"),
[STRINGID_FOGLIFTED] = COMPOUND_STRING("The fog lifted."),
@ -1197,10 +1172,10 @@ const u16 gReflectLightScreenSafeguardStringIds[] =
{
[B_MSG_SIDE_STATUS_FAILED] = STRINGID_BUTITFAILED,
[B_MSG_SET_REFLECT_SINGLE] = STRINGID_PKMNRAISEDDEF,
[B_MSG_SET_REFLECT_DOUBLE] = STRINGID_PKMNRAISEDDEFALITTLE,
[B_MSG_SET_REFLECT_DOUBLE] = STRINGID_PKMNRAISEDDEF,
[B_MSG_SET_LIGHTSCREEN_SINGLE] = STRINGID_PKMNRAISEDSPDEF,
[B_MSG_SET_LIGHTSCREEN_DOUBLE] = STRINGID_PKMNRAISEDSPDEFALITTLE,
[B_MSG_SET_SAFEGUARD] = STRINGID_PKMNCOVEREDBYVEIL
[B_MSG_SET_LIGHTSCREEN_DOUBLE] = STRINGID_PKMNRAISEDSPDEF,
[B_MSG_SET_SAFEGUARD] = STRINGID_PKMNCOVEREDBYVEIL,
};
const u16 gLeechSeedStringIds[] =
@ -1224,24 +1199,12 @@ const u16 gUproarOverTurnStringIds[] =
[B_MSG_UPROAR_ENDS] = STRINGID_PKMNCALMEDDOWN
};
const u16 gStockpileUsedStringIds[] =
{
[B_MSG_STOCKPILED] = STRINGID_PKMNSTOCKPILED,
[B_MSG_CANT_STOCKPILE] = STRINGID_PKMNCANTSTOCKPILE
};
const u16 gWokeUpStringIds[] =
{
[B_MSG_WOKE_UP] = STRINGID_PKMNWOKEUP,
[B_MSG_WOKE_UP_UPROAR] = STRINGID_PKMNWOKEUPINUPROAR
};
const u16 gSwallowFailStringIds[] =
{
[B_MSG_SWALLOW_FAILED] = STRINGID_FAILEDTOSWALLOW,
[B_MSG_SWALLOW_FULL_HP] = STRINGID_PKMNHPFULL
};
const u16 gUproarAwakeStringIds[] =
{
[B_MSG_CANT_SLEEP_UPROAR] = STRINGID_PKMNCANTSLEEPINUPROAR2,
@ -1250,20 +1213,21 @@ const u16 gUproarAwakeStringIds[] =
const u16 gStatUpStringIds[] =
{
[B_MSG_ATTACKER_STAT_ROSE] = STRINGID_ATTACKERSSTATROSE,
[B_MSG_DEFENDER_STAT_ROSE] = STRINGID_DEFENDERSSTATROSE,
[B_MSG_STAT_WONT_INCREASE] = STRINGID_STATSWONTINCREASE,
[B_MSG_STAT_ROSE_EMPTY] = STRINGID_EMPTYSTRING3,
[B_MSG_STAT_ROSE_ITEM] = STRINGID_USINGITEMSTATOFPKMNROSE,
[B_MSG_USED_DIRE_HIT] = STRINGID_PKMNUSEDXTOGETPUMPED,
[B_MSG_ATTACKER_STAT_CHANGED] = STRINGID_ATTACKERSSTATROSE,
[B_MSG_DEFENDER_STAT_CHANGED] = STRINGID_DEFENDERSSTATROSE,
[B_MSG_STAT_WONT_CHANGE] = STRINGID_STATSWONTINCREASE,
[B_MSG_STAT_CHANGE_EMPTY] = STRINGID_EMPTYSTRING3,
[B_MSG_STAT_CHANGED_ITEM] = STRINGID_USINGITEMSTATOFPKMNROSE,
[B_MSG_USED_DIRE_HIT] = STRINGID_PKMNUSEDXTOGETPUMPED,
};
const u16 gStatDownStringIds[] =
{
[B_MSG_ATTACKER_STAT_FELL] = STRINGID_ATTACKERSSTATFELL,
[B_MSG_DEFENDER_STAT_FELL] = STRINGID_DEFENDERSSTATFELL,
[B_MSG_STAT_WONT_DECREASE] = STRINGID_STATSWONTDECREASE,
[B_MSG_STAT_FELL_EMPTY] = STRINGID_EMPTYSTRING3
[B_MSG_ATTACKER_STAT_CHANGED] = STRINGID_ATTACKERSSTATFELL,
[B_MSG_DEFENDER_STAT_CHANGED] = STRINGID_DEFENDERSSTATFELL,
[B_MSG_STAT_WONT_CHANGE] = STRINGID_STATSWONTDECREASE,
[B_MSG_STAT_CHANGE_EMPTY] = STRINGID_EMPTYSTRING3,
[B_MSG_STAT_CHANGED_ITEM] = STRINGID_USINGITEMSTATOFPKMNFELL,
};
// Index copied from move's index in sTrappingMoves
@ -1463,16 +1427,6 @@ const u16 gBerryEffectStringIds[] =
[B_MSG_NORMALIZED_STATUS] = STRINGID_PKMNSITEMNORMALIZEDSTATUS
};
const u16 gStatusPreventionStringIds[] =
{
[B_MSG_ABILITY_PREVENTS_MOVE_BURN] = STRINGID_PKMNSXPREVENTSBURNS,
[B_MSG_ABILITY_PREVENTS_MOVE_PARALYSIS] = STRINGID_PKMNPREVENTSPARALYSISWITH,
[B_MSG_ABILITY_PREVENTS_MOVE_POISON] = STRINGID_PKMNPREVENTSPOISONINGWITH,
[B_MSG_ABILITY_PREVENTS_ABILITY_STATUS] = STRINGID_PKMNSXPREVENTSYSZ,
[B_MSG_STATUS_HAD_NO_EFFECT] = STRINGID_PKMNSXHADNOEFFECTONY,
[B_MSG_ABILITY_PASTEL_VEIL] = STRINGID_PASTELVEILPROTECTED
};
const u16 gItemSwapStringIds[] =
{
[B_MSG_ITEM_SWAP_TAKEN] = STRINGID_PKMNOBTAINEDX,
@ -1529,6 +1483,24 @@ const u16 gDamageNonTypesDmgStringIds[] =
[B_MSG_HURT_BY_ROCKS_THROWN] = STRINGID_PKMNHURTBYROCKSTHROWN,
};
const u16 gDefogHazardsStringIds[] =
{
[HAZARDS_SPIKES] = STRINGID_SPIKESDISAPPEAREDFROMTEAM,
[HAZARDS_STICKY_WEB] = STRINGID_STICKYWEBDISAPPEAREDFROMTEAM,
[HAZARDS_TOXIC_SPIKES] = STRINGID_TOXICSPIKESDISAPPEAREDFROMTEAM,
[HAZARDS_STEALTH_ROCK] = STRINGID_STEALTHROCKDISAPPEAREDFROMTEAM,
[HAZARDS_STEELSURGE] = STRINGID_SHARPSTEELDISAPPEAREDFROMTEAM,
};
const u16 gSpinHazardsStringIds[] =
{
[HAZARDS_SPIKES] = STRINGID_PKMNBLEWAWAYSPIKES,
[HAZARDS_STICKY_WEB] = STRINGID_PKMNBLEWAWAYSTICKYWEB,
[HAZARDS_TOXIC_SPIKES] = STRINGID_PKMNBLEWAWAYTOXICSPIKES,
[HAZARDS_STEALTH_ROCK] = STRINGID_PKMNBLEWAWAYSTEALTHROCK,
[HAZARDS_STEELSURGE] = STRINGID_PKMNBLEWAWAYSHARPSTEEL,
};
// Index is determined in VARIOUS_GET_BATTLERS_FOR_RECALL by ORing flags for each present battler on the losing side.
// No battlers (0) is skipped.
const u16 gDoubleBattleRecallStrings[1 << (MAX_BATTLERS_COUNT / 2)] =
@ -1674,7 +1646,7 @@ static const u16 sGrammarMoveUsedTable[] =
static const u8 sRecordedBattleTextSpeeds[] = {8, 4, 1, 0};
void BufferStringBattle(u16 stringId, u32 battler)
void BufferStringBattle(enum StringID stringID, u32 battler)
{
s32 i;
const u8 *stringPtr = NULL;
@ -1699,7 +1671,7 @@ void BufferStringBattle(u16 stringId, u32 battler)
gBattleTextBuff3[i] = gBattleMsgDataPtr->textBuffs[2][i];
}
switch (stringId)
switch (stringID)
{
case STRINGID_INTROMSG: // first battle msg
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
@ -1737,16 +1709,13 @@ void BufferStringBattle(u16 stringId, u32 battler)
}
else
{
if (gBattleTypeFlags & BATTLE_TYPE_GHOST)
{
if (gBattleTypeFlags & BATTLE_TYPE_GHOST_UNVEILED)
stringPtr = sText_TheGhostAppeared;
else
stringPtr = sText_GhostAppearedCantId;
}
if (gBattleTypeFlags & BATTLE_TYPE_GHOST && IsGhostBattleWithoutScope())
stringPtr = sText_GhostAppearedCantId;
else if (gBattleTypeFlags & BATTLE_TYPE_GHOST)
stringPtr = sText_TheGhostAppeared;
else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
stringPtr = sText_WildPkmnAppeared2;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]])) // interesting, looks like they had something planned for wild double battles
else if (IsDoubleBattle() && IsValidForBattle(GetBattlerMon(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT))))
stringPtr = sText_TwoWildPkmnAppeared;
else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL)
stringPtr = sText_WildPkmnAppearedPause;
@ -1755,9 +1724,9 @@ void BufferStringBattle(u16 stringId, u32 battler)
}
break;
case STRINGID_INTROSENDOUT: // poke first send-out
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
if (IsOnPlayerSide(battler))
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]))
if (IsDoubleBattle() && IsValidForBattle(GetBattlerMon(BATTLE_PARTNER(battler))))
{
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
stringPtr = sText_InGamePartnerSentOutZGoN;
@ -1775,7 +1744,7 @@ void BufferStringBattle(u16 stringId, u32 battler)
}
else
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]))
if (IsDoubleBattle() && IsValidForBattle(GetBattlerMon(BATTLE_PARTNER(battler))))
{
if (BATTLE_TWO_VS_ONE_OPPONENT)
stringPtr = sText_Trainer1SentOutTwoPkmn;
@ -1802,11 +1771,11 @@ void BufferStringBattle(u16 stringId, u32 battler)
}
break;
case STRINGID_RETURNMON: // sending poke to ball msg
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
if (IsOnPlayerSide(battler))
{
if (*(&gBattleStruct->hpScale) == 0)
stringPtr = sText_PkmnThatsEnough;
else if (*(&gBattleStruct->hpScale) == 1 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
else if (*(&gBattleStruct->hpScale) == 1 || IsDoubleBattle())
stringPtr = sText_PkmnComeBack;
else if (*(&gBattleStruct->hpScale) == 2)
stringPtr = sText_PkmnOkComeBack;
@ -1829,9 +1798,9 @@ void BufferStringBattle(u16 stringId, u32 battler)
}
break;
case STRINGID_SWITCHINMON: // switch-in msg
if (GetBattlerSide(gBattleScripting.battler) == B_SIDE_PLAYER)
if (IsOnPlayerSide(gBattleScripting.battler))
{
if (*(&gBattleStruct->hpScale) == 0 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
if (*(&gBattleStruct->hpScale) == 0 || IsDoubleBattle())
stringPtr = sText_GoPkmn2;
else if (*(&gBattleStruct->hpScale) == 1)
stringPtr = sText_DoItPkmn;
@ -1844,20 +1813,40 @@ void BufferStringBattle(u16 stringId, u32 battler)
{
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
stringPtr = sText_LinkTrainerMultiSentOutPkmn;
else if (TRAINER_BATTLE_PARAM.opponentA == TRAINER_UNION_ROOM)
stringPtr = sText_Trainer1SentOutPkmn2;
if (gBattleTypeFlags & BATTLE_TYPE_TOWER_LINK_MULTI)
{
if (gBattleScripting.battler == 1)
stringPtr = sText_Trainer1SentOutPkmn2;
else
stringPtr = sText_Trainer2SentOutPkmn;
}
else
stringPtr = sText_LinkTrainerSentOutPkmn2;
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
stringPtr = sText_LinkTrainerMultiSentOutPkmn;
else if (TRAINER_BATTLE_PARAM.opponentA == TRAINER_UNION_ROOM)
stringPtr = sText_Trainer1SentOutPkmn2;
else
stringPtr = sText_LinkTrainerSentOutPkmn2;
}
}
else
{
stringPtr = sText_Trainer1SentOutPkmn2;
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
if (gBattleScripting.battler == 1)
stringPtr = sText_Trainer1SentOutPkmn2;
else
stringPtr = sText_Trainer2SentOutPkmn;
}
else
{
stringPtr = sText_Trainer1SentOutPkmn2;
}
}
}
break;
case STRINGID_USEDMOVE: // pokemon used a move msg
case STRINGID_USEDMOVE: // Pokémon used a move msg
if (gBattleMsgDataPtr->currentMove >= MOVES_COUNT
&& !IsZMove(gBattleMsgDataPtr->currentMove)
&& !IsMaxMove(gBattleMsgDataPtr->currentMove))
@ -1870,21 +1859,19 @@ void BufferStringBattle(u16 stringId, u32 battler)
if (gBattleTextBuff1[0] & B_OUTCOME_LINK_BATTLE_RAN)
{
gBattleTextBuff1[0] &= ~(B_OUTCOME_LINK_BATTLE_RAN);
if (GetBattlerSide(battler) == B_SIDE_OPPONENT && gBattleTextBuff1[0] != B_OUTCOME_DREW)
if (!IsOnPlayerSide(battler) && gBattleTextBuff1[0] != B_OUTCOME_DREW)
gBattleTextBuff1[0] ^= (B_OUTCOME_LOST | B_OUTCOME_WON);
if (gBattleTextBuff1[0] == B_OUTCOME_LOST || gBattleTextBuff1[0] == B_OUTCOME_DREW)
stringPtr = sText_GotAwaySafely;
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
stringPtr = sText_TwoWildFled;
else if (TRAINER_BATTLE_PARAM.opponentA == TRAINER_UNION_ROOM)
stringPtr = sText_Trainer1Fled;
else
stringPtr = sText_WildFled;
}
else
{
if (GetBattlerSide(battler) == B_SIDE_OPPONENT && gBattleTextBuff1[0] != B_OUTCOME_DREW)
if (!IsOnPlayerSide(battler) && gBattleTextBuff1[0] != B_OUTCOME_DREW)
gBattleTextBuff1[0] ^= (B_OUTCOME_LOST | B_OUTCOME_WON);
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
@ -1938,14 +1925,14 @@ void BufferStringBattle(u16 stringId, u32 battler)
stringPtr = gBattleStruct->trainerSlideMsg;
break;
default: // load a string from the table
if (stringId >= STRINGID_COUNT)
if (stringID >= STRINGID_COUNT)
{
gDisplayedStringBattle[0] = EOS;
return;
}
else
{
stringPtr = gBattleStringsTable[stringId];
stringPtr = gBattleStringsTable[stringID];
}
break;
}
@ -2700,13 +2687,13 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst, u32 dstSize)
else
toCpy = sText_Opposing2;
break;
case B_TXT_SCR_TEAM1:
case B_TXT_EFF_TEAM1:
if (GetBattlerSide(gBattleScripting.battler) == B_SIDE_PLAYER)
toCpy = sText_Your1;
else
toCpy = sText_Opposing1;
break;
case B_TXT_SCR_TEAM2:
case B_TXT_EFF_TEAM2:
if (GetBattlerSide(gBattleScripting.battler) == B_SIDE_PLAYER)
toCpy = sText_Your2;
else

File diff suppressed because it is too large Load Diff

View File

@ -62,9 +62,9 @@ void ApplyBattlerVisualsForTeraAnim(u32 battler)
// Returns whether a battler can Terastallize.
bool32 CanTerastallize(u32 battler)
{
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler);
if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS)
if (gBattleMons[battler].volatiles.transformed && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS)
return FALSE;
// Prevents Zigzagoon from terastalizing in vanilla.
@ -132,20 +132,19 @@ bool32 IsTypeStellarBoosted(u32 battler, u32 type)
// Returns the STAB power multiplier to use when Terastallized.
// Power multipliers from Smogon Research thread.
uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
uq4_12_t GetTeraMultiplier(struct DamageContext *ctx)
{
u32 teraType = GetBattlerTeraType(battler);
bool32 hasAdaptability = (GetBattlerAbility(battler) == ABILITY_ADAPTABILITY);
u32 teraType = GetBattlerTeraType(ctx->battlerAtk);
// Safety check.
if (GetActiveGimmick(battler) != GIMMICK_TERA)
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_TERA)
return UQ_4_12(1.0);
// Stellar-type checks.
if (teraType == TYPE_STELLAR)
{
bool32 shouldBoost = IsTypeStellarBoosted(battler, type);
if (IS_BATTLER_OF_BASE_TYPE(battler, type))
bool32 shouldBoost = IsTypeStellarBoosted(ctx->battlerAtk, ctx->moveType);
if (IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
{
if (shouldBoost)
return UQ_4_12(2.0);
@ -158,18 +157,18 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
return UQ_4_12(1.0);
}
// Base and Tera type.
if (type == teraType && IS_BATTLER_OF_BASE_TYPE(battler, type))
if (ctx->moveType == teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
{
if (hasAdaptability)
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
return UQ_4_12(2.25);
else
return UQ_4_12(2.0);
}
// Base or Tera type only.
else if ((type == teraType && !IS_BATTLER_OF_BASE_TYPE(battler, type))
|| (type != teraType && IS_BATTLER_OF_BASE_TYPE(battler, type)))
else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
|| (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)))
{
if (hasAdaptability)
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
return UQ_4_12(2.0);
else
return UQ_4_12(1.5);

File diff suppressed because it is too large Load Diff

View File

@ -113,7 +113,7 @@ bool32 IsZMove(u32 move)
bool32 CanUseZMove(u32 battler)
{
u32 holdEffect = GetBattlerHoldEffect(battler, FALSE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler);
// Check if Player has Z-Power Ring.
if (!TESTING && (battler == B_POSITION_PLAYER_LEFT
@ -122,7 +122,7 @@ bool32 CanUseZMove(u32 battler)
return FALSE;
// Add '| BATTLE_TYPE_FRONTIER' to below if issues occur
if (gBattleTypeFlags & (BATTLE_TYPE_SAFARI | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
if (gBattleTypeFlags & (BATTLE_TYPE_SAFARI | BATTLE_TYPE_OLD_MAN_TUTORIAL))
return FALSE;
// Check if Trainer has already used a Z-Move.
@ -144,7 +144,7 @@ bool32 CanUseZMove(u32 battler)
u32 GetUsableZMove(u32 battler, u32 move)
{
u32 item = gBattleMons[battler].item;
u32 holdEffect = GetBattlerHoldEffect(battler, FALSE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler);
if (holdEffect == HOLD_EFFECT_Z_CRYSTAL)
{
@ -161,14 +161,13 @@ u32 GetUsableZMove(u32 battler, u32 move)
void ActivateZMove(u32 battler)
{
gBattleStruct->zmove.baseMoves[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]];
SetActiveGimmick(battler, GIMMICK_Z_MOVE);
}
bool32 IsViableZMove(u32 battler, u32 move)
{
u32 item;
u32 holdEffect = GetBattlerHoldEffect(battler, FALSE);
enum ItemHoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler);
int moveSlotIndex;
item = gBattleMons[battler].item;
@ -364,7 +363,7 @@ bool32 MoveSelectionDisplayZMove(u16 zmove, u32 battler)
gDisplayedStringBattle[1] = CHAR_HYPHEN;
StringCopy(gDisplayedStringBattle + 2, GetMoveName(move));
}
else if (zmove == MOVE_EXTREME_EVOBOOST)
else if (GetMoveEffect(zmove) == EFFECT_EXTREME_EVOBOOST)
{
// Damaging move -> status z move
StringCopy(gDisplayedStringBattle, sText_StatsPlus2);
@ -438,7 +437,7 @@ static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler)
void SetZEffect(void)
{
u32 i;
u32 effect = GetMoveZEffect(gBattleStruct->zmove.baseMoves[gBattlerAttacker]);
u32 effect = GetMoveZEffect(gChosenMove);
if (effect == Z_EFFECT_CURSE)
{
@ -486,9 +485,9 @@ void SetZEffect(void)
break;
}
case Z_EFFECT_BOOST_CRITS:
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY_ANY))
if (!(gBattleMons[gBattlerAttacker].volatiles.dragonCheer || gBattleMons[gBattlerAttacker].volatiles.focusEnergy))
{
gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY;
gBattleMons[gBattlerAttacker].volatiles.focusEnergy = TRUE;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_BOOST_CRITS;
BattleScriptPush(gBattlescriptCurrInstr + Z_EFFECT_BS_LENGTH);
gBattlescriptCurrInstr = BattleScript_ZEffectPrintString;
@ -549,7 +548,8 @@ u32 GetZMovePower(u32 move)
{
if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS)
return 0;
if (GetMoveEffect(move) == EFFECT_OHKO)
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
if (moveEffect == EFFECT_OHKO || moveEffect == EFFECT_SHEER_COLD)
return 180;
u32 power = GetMoveZPowerOverride(move);
@ -568,4 +568,3 @@ u32 GetZMovePower(u32 move)
else if (power >= 60) return 120;
else return 100;
}

View File

@ -1,4 +1,4 @@
const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
const struct AbilityInfo gAbilitiesInfo[ABILITIES_COUNT] =
{
[ABILITY_NONE] =
{

View File

@ -49,7 +49,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_MIRROR_MOVE] =
{
.battleScript = BattleScript_EffectMirrorMove,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 1,
},
@ -398,7 +398,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_METRONOME] =
{
.battleScript = BattleScript_EffectMetronome,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 1,
},
@ -502,7 +502,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_SLEEP_TALK] =
{
.battleScript = BattleScript_EffectSleepTalk,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 3,
.encourageEncore = TRUE,
},
@ -791,7 +791,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_BEAT_UP] =
{
.battleScript = BattleScript_EffectBeatUp,
.battleScript = (B_BEAT_UP >= GEN_5) ? BattleScript_EffectHit : BattleScript_EffectBeatUp,
.battleTvScore = 2,
},
@ -819,14 +819,14 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_FIRST_TURN_ONLY] =
{
.battleScript = BattleScript_EffectFirstTurnOnly,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 4,
.encourageEncore = TRUE,
},
[EFFECT_UPROAR] =
{
.battleScript = BattleScript_EffectUproar,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 4,
},
@ -911,7 +911,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_NATURE_POWER] =
{
.battleScript = BattleScript_EffectNaturePower,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -956,7 +956,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_ASSIST] =
{
.battleScript = BattleScript_EffectAssist,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 2,
},
@ -1004,6 +1004,12 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleTvScore = 2,
},
[EFFECT_STEAL_ITEM] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 3,
},
[EFFECT_ENDEAVOR] =
{
.battleScript = BattleScript_EffectEndeavor,
@ -1386,7 +1392,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_SUCKER_PUNCH] =
{
.battleScript = BattleScript_EffectSuckerPunch,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -1480,7 +1486,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_ME_FIRST] =
{
.battleScript = BattleScript_EffectMeFirst,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -1525,7 +1531,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_LAST_RESORT] =
{
.battleScript = BattleScript_EffectLastResort,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -1595,7 +1601,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_COPYCAT] =
{
.battleScript = BattleScript_EffectCopycat,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -1715,7 +1721,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_MAT_BLOCK] =
{
.battleScript = BattleScript_EffectMatBlock,
.battleScript = BattleScript_EffectProtect,
.battleTvScore = 0, // TODO: Assign points
.encourageEncore = TRUE,
},
@ -1768,7 +1774,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_FAIL_IF_NOT_ARG_TYPE] =
{
.battleScript = BattleScript_FailIfNotArgType,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -1875,7 +1881,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
[EFFECT_AURA_WHEEL] =
{
.battleScript = BattleScript_EffectAuraWheel,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
@ -1978,9 +1984,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_HIT_SET_REMOVE_TERRAIN] =
[EFFECT_HIT_SET_TERRAIN] =
{
.battleScript = BattleScript_EffectHitSetRemoveTerrain,
.battleScript = BattleScript_EffectHitSetTerrain,
.battleTvScore = 0, // TODO: Assign points
},
@ -2212,4 +2218,34 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_LIFE_DEW] =
{
.battleScript = BattleScript_EffectLifeDew,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_ICE_SPINNER] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_STEEL_ROLLER] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_STONE_AXE] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_CEASELESS_EDGE] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
};

View File

@ -1,9 +1,7 @@
//
// DO NOT MODIFY THIS FILE! It is auto-generated from src/data/battle_partners.party
//
// If you want to modify this file set COMPETITIVE_PARTY_SYNTAX to FALSE
// in include/config/general.h and remove this notice.
// Use sed -i '/^#line/d' 'src/data/battle_partners.h' to remove #line markers.
// If you want to modify this file see expansion PR #7154
//
#line 1 "src/data/battle_partners.party"
@ -14,45 +12,51 @@
#line 3
.trainerClass = TRAINER_CLASS_PKMN_TRAINER_1,
#line 4
.trainerPic = TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN,
.trainerPic = TRAINER_PIC_RS_BRENDAN_1,
.encounterMusic_gender =
#line 6
TRAINER_ENCOUNTER_MUSIC_MALE,
#line 7
.trainerBackPic = TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN,
.partySize = 0,
.party = (const struct TrainerMon[])
{
},
},
#line 8
#line 9
[DIFFICULTY_NORMAL][PARTNER_STEVEN] =
{
#line 9
.trainerName = _("STEVEN"),
#line 10
.trainerClass = TRAINER_CLASS_RIVAL_LATE,
.trainerName = _("STEVEN"),
#line 11
.trainerPic = TRAINER_BACK_PIC_STEVEN,
.trainerClass = TRAINER_CLASS_RIVAL_LATE,
#line 12
.trainerPic = TRAINER_PIC_RS_BRENDAN_1,
.encounterMusic_gender =
#line 13
#line 14
TRAINER_ENCOUNTER_MUSIC_MALE,
#line 16
.aiFlags = AI_FLAG_BASIC_TRAINER,
#line 15
.trainerBackPic = TRAINER_BACK_PIC_STEVEN,
.partySize = 3,
.party = (const struct TrainerMon[])
{
{
#line 15
#line 18
.species = SPECIES_METANG,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 19
#line 22
.ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0),
#line 18
#line 21
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 17
#line 20
.lvl = 42,
#line 16
#line 19
.nature = NATURE_BRAVE,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 20
#line 23
MOVE_LIGHT_SCREEN,
MOVE_PSYCHIC,
MOVE_REFLECT,
@ -60,20 +64,20 @@
},
},
{
#line 25
#line 28
.species = SPECIES_SKARMORY,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 29
#line 32
.ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252),
#line 28
#line 31
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 27
#line 30
.lvl = 43,
#line 26
#line 29
.nature = NATURE_IMPISH,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 30
#line 33
MOVE_TOXIC,
MOVE_AERIAL_ACE,
MOVE_PROTECT,
@ -81,20 +85,20 @@
},
},
{
#line 35
#line 38
.species = SPECIES_AGGRON,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 39
#line 42
.ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6),
#line 38
#line 41
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 37
#line 40
.lvl = 44,
#line 36
#line 39
.nature = NATURE_ADAMANT,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 40
#line 43
MOVE_THUNDER,
MOVE_PROTECT,
MOVE_SOLAR_BEAM,

View File

@ -1,16 +1,19 @@
=== PARTNER_NONE ===
Name:
Class: Pkmn Trainer 1
Pic: Ruby Sapphire Brendan
Pic: RS Brendan 1
Gender: Male
Music: Male
Back Pic: Ruby Sapphire Brendan
=== PARTNER_STEVEN ===
Name: STEVEN
Class: Rival Late
Pic: Steven
Pic: RS Brendan 1
Gender: Male
Music: Male
Back Pic: Steven
AI: Basic Trainer
Metang
Brave Nature

136
src/data/debug_trainers.h Normal file
View File

@ -0,0 +1,136 @@
//
// DO NOT MODIFY THIS FILE! It is auto-generated from src/data/debug_trainers.party
//
// If you want to modify this file see expansion PR #7154
//
#line 1 "src/data/debug_trainers.party"
#line 14
[DIFFICULTY_NORMAL][DEBUG_TRAINER_PLAYER] =
{
#line 15
.trainerName = _("Player"),
#line 16
.trainerClass = TRAINER_CLASS_PKMN_TRAINER_1,
#line 17
.trainerPic = TRAINER_PIC_RED,
.encounterMusic_gender =
#line 19
TRAINER_ENCOUNTER_MUSIC_MALE,
#line 0
.trainerBackPic = TRAINER_PIC_RED,
.partySize = 1,
.party = (const struct TrainerMon[])
{
{
#line 21
.nickname = COMPOUND_STRING("Buffie"),
#line 21
.species = SPECIES_WOBBUFFET,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 25
.ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0),
#line 24
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 23
.lvl = 100,
#line 22
.nature = NATURE_BRAVE,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 26
MOVE_EARTHQUAKE,
MOVE_FLAMETHROWER,
MOVE_CELEBRATE,
MOVE_CELEBRATE,
},
},
},
},
#line 31
[DIFFICULTY_NORMAL][DEBUG_TRAINER_AI] =
{
#line 32
.trainerName = _("Debugger"),
#line 34
.trainerClass = TRAINER_CLASS_CHAMPION,
#line 36
.trainerPic = TRAINER_PIC_CHAMPION_STEVEN,
.encounterMusic_gender =
#line 38
TRAINER_ENCOUNTER_MUSIC_MALE,
#line 35
.battleType = TRAINER_BATTLE_TYPE_SINGLES,
#line 33
.aiFlags = AI_FLAG_BASIC_TRAINER,
#line 0
.trainerBackPic = TRAINER_PIC_CHAMPION_STEVEN,
.partySize = 3,
.party = (const struct TrainerMon[])
{
{
#line 40
.species = SPECIES_METANG,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 44
.ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0),
#line 43
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 42
.lvl = 42,
#line 41
.nature = NATURE_BRAVE,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 45
MOVE_LIGHT_SCREEN,
MOVE_PSYCHIC,
MOVE_REFLECT,
MOVE_METAL_CLAW,
},
},
{
#line 50
.species = SPECIES_SKARMORY,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 54
.ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252),
#line 53
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 52
.lvl = 43,
#line 51
.nature = NATURE_IMPISH,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 55
MOVE_TOXIC,
MOVE_AERIAL_ACE,
MOVE_PROTECT,
MOVE_STEEL_WING,
},
},
{
#line 60
.species = SPECIES_AGGRON,
.gender = TRAINER_MON_RANDOM_GENDER,
#line 64
.ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6),
#line 63
.iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31),
#line 62
.lvl = 44,
#line 61
.nature = NATURE_ADAMANT,
.dynamaxLevel = MAX_DYNAMAX_LEVEL,
.moves = {
#line 65
MOVE_THUNDER,
MOVE_PROTECT,
MOVE_SOLAR_BEAM,
MOVE_DRAGON_CLAW,
},
},
},
},

View File

@ -0,0 +1,68 @@
/*
Parties for the debug menu.
The trainer description for DEBUG_TRAINER_PLAYER is not used,
its party is given to the player whenever the Set Party action is selected,
or the Start Debug Battle action is selected.
The debug menu will start a battle against DEBUG_TRAINER_AI when the
Start Debug Battle action is selected.
*/
=== DEBUG_TRAINER_PLAYER ===
Name: Player
Class: Pkmn Trainer 1
Pic: Red
Gender: Male
Music: Male
Buffie (Wobbuffet)
Brave Nature
Level: 100
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 Def / 6 SpA
- Earthquake
- Flamethrower
- Celebrate
- Celebrate
=== DEBUG_TRAINER_AI ===
Name: Debugger
AI: Basic Trainer
Class: Champion
Battle Type: Singles
Pic: Champion Steven
Gender: Male
Music: Male
Metang
Brave Nature
Level: 42
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 Def / 6 SpA
- Light Screen
- Psychic
- Reflect
- Metal Claw
Skarmory
Impish Nature
Level: 43
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 HP / 6 SpA / 252 SpD
- Toxic
- Aerial Ace
- Protect
- Steel Wing
Aggron
Adamant Nature
Level: 44
IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
EVs: 252 Atk / 252 SpA / 6 SpD
- Thunder
- Protect
- Solar Beam
- Dragon Claw

View File

@ -689,84 +689,22 @@ static const union AnimCmd *const sBackAnims_Hoenn[] =
sAnimCmd_Point_HGSS,
};
#define BACK_PIC_TABLE_ENTRY(backPicData, entryId) \
{.data = backPicData + TRAINER_PIC_SIZE * entryId, .size = TRAINER_PIC_SIZE}
const struct SpriteFrameImage gTrainerBackPicTable_Red[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Red, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Red, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Red, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Red, 3),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Red, 4),
};
const struct SpriteFrameImage gTrainerBackPicTable_Leaf[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Leaf, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Leaf, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Leaf, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Leaf, 3),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Leaf, 4),
};
const struct SpriteFrameImage gTrainerBackPicTable_Pokedude[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Pokedude, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Pokedude, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Pokedude, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Pokedude, 3),
};
const struct SpriteFrameImage gTrainerBackPicTable_OldMan[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_OldMan, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_OldMan, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_OldMan, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_OldMan, 3),
};
const struct SpriteFrameImage gTrainerBackPicTable_RSBrendan[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSBrendan, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSBrendan, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSBrendan, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSBrendan, 3),
};
const struct SpriteFrameImage gTrainerBackPicTable_RSMay[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSMay, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSMay, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSMay, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_RSMay, 3),
};
const struct SpriteFrameImage gTrainerBackPicTable_Steven[] =
{
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Steven, 0),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Steven, 1),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Steven, 2),
BACK_PIC_TABLE_ENTRY(gTrainerBackPic_Steven, 3),
};
#define TRAINER_BACK_SPRITE(trainerId, yOffset, backPicData, backPicTable, paletteData, anim) \
[trainerId] = \
{ \
.coordinates = {.size = 8, .y_offset = yOffset}, \
.backPic = {.data = (const u32 *)backPicData, .size = TRAINER_PIC_SIZE * ARRAY_COUNT(backPicTable), .tag = trainerId}, \
.palette = {.data = paletteData, .tag = trainerId}, \
.animation = anim, \
#define TRAINER_BACK_SPRITE(trainerPic, yOffset, sprite, pal, anim) \
[trainerPic] = \
{ \
.coordinates = {.size = 8, .y_offset = yOffset}, \
.backPic = {.data = sprite, .size = TRAINER_PIC_SIZE, .relativeFrames = TRUE}, \
.palette = {.data = pal, .tag = trainerPic}, \
.animation = anim, \
}
const struct TrainerBacksprite gTrainerBacksprites[] =
{
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_RED, 5, gTrainerBackPic_Red, gTrainerBackPicTable_Red, gTrainerPalette_RedBackPic, sBackAnims_Kanto),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_LEAF, 5, gTrainerBackPic_Leaf, gTrainerBackPicTable_Leaf, gTrainerPalette_LeafBackPic, sBackAnims_Kanto),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN, 4, gTrainerBackPic_RSBrendan, gTrainerBackPicTable_RSBrendan, gTrainerPalette_RSBrendan1, sBackAnims_Hoenn),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_RUBY_SAPPHIRE_MAY, 4, gTrainerBackPic_RSMay, gTrainerBackPicTable_RSMay, gTrainerPalette_RSMay1, sBackAnims_Hoenn),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_POKEDUDE, 4, gTrainerBackPic_Pokedude, gTrainerBackPicTable_Pokedude, gTrainerPalette_PokedudeBackPic, sBackAnims_OldManPokedude),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_OLD_MAN, 4, gTrainerBackPic_OldMan, gTrainerBackPicTable_OldMan, gTrainerPalette_OldManBackPic, sBackAnims_OldManPokedude),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_STEVEN, 4, gTrainerBackPic_Steven, gTrainerBackPicTable_Steven, gTrainerPalette_Steven, sBackAnims_Hoenn),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_RED, 5, gTrainerBackPic_Red, gTrainerPalette_RedBackPic, sBackAnims_Kanto),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_LEAF, 5, gTrainerBackPic_Leaf, gTrainerPalette_LeafBackPic, sBackAnims_Kanto),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN, 4, gTrainerBackPic_RSBrendan, gTrainerPalette_RSBrendan1, sBackAnims_Hoenn),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_RUBY_SAPPHIRE_MAY, 4, gTrainerBackPic_RSMay, gTrainerPalette_RSMay1, sBackAnims_Hoenn),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_POKEDUDE, 4, gTrainerBackPic_Pokedude, gTrainerPalette_PokedudeBackPic, sBackAnims_OldManPokedude),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_OLD_MAN, 4, gTrainerBackPic_OldMan, gTrainerPalette_OldManBackPic, sBackAnims_OldManPokedude),
TRAINER_BACK_SPRITE(TRAINER_BACK_PIC_STEVEN, 4, gTrainerBackPic_Steven, gTrainerPalette_Steven, sBackAnims_Hoenn),
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2143,6 +2143,13 @@ void RunMassageCooldownStepCounter(void)
VarSet(VAR_MASSAGE_COOLDOWN_STEP_COUNTER, count + 1);
}
void SetHiddenNature(void)
{
u32 hiddenNature = gSpecialVar_Result;
SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HIDDEN_NATURE, &hiddenNature);
CalculateMonStats(&gPlayerParty[gSpecialVar_0x8004]);
}
void DaisyMassageServices(void)
{
AdjustFriendship(&gPlayerParty[gSpecialVar_0x8004], FRIENDSHIP_EVENT_MASSAGE);

View File

@ -1139,3 +1139,33 @@ bool32 IsWeatherAlphaBlend(void)
|| gWeatherPtr->currWeather == WEATHER_UNDERWATER_BUBBLES
|| gWeatherPtr->currWeather == WEATHER_UNDERWATER);
}
static const u8 sWeatherNames[WEATHER_COUNT][24] = {
[WEATHER_NONE] = _("NONE"),
[WEATHER_SUNNY_CLOUDS] = _("SUNNY CLOUDS"),
[WEATHER_SUNNY] = _("SUNNY"),
[WEATHER_RAIN] = _("RAIN"),
[WEATHER_SNOW] = _("SNOW"),
[WEATHER_RAIN_THUNDERSTORM] = _("RAIN THUNDERSTORM"),
[WEATHER_FOG_HORIZONTAL] = _("FOG HORIZONTAL"),
[WEATHER_VOLCANIC_ASH] = _("VOLCANIC ASH"),
[WEATHER_SANDSTORM] = _("SANDSTORM"),
[WEATHER_FOG_DIAGONAL] = _("FOG DIAGONAL"),
[WEATHER_UNDERWATER] = _("UNDERWATER"),
[WEATHER_SHADE] = _("SHADE"),
[WEATHER_DROUGHT] = _("DROUGHT"),
[WEATHER_DOWNPOUR] = _("DOWNPOUR"),
[WEATHER_UNDERWATER_BUBBLES] = _("UNDERWATER BUBBLES"),
[WEATHER_ABNORMAL] = _("ABNORMAL(NOT WORKING)"),
[WEATHER_ROUTE119_CYCLE] = _("ROUTE119 CYCLE"),
[WEATHER_ROUTE123_CYCLE] = _("ROUTE123 CYCLE"),
[WEATHER_FOG] = _("FOG"),
};
static const u8 sDebugText_WeatherNotDefined[] = _("NOT DEFINED!!!");
const u8 *GetWeatherName(u32 weatherId)
{
if (sWeatherNames[weatherId][0] != 0)
return sWeatherNames[weatherId];
return sDebugText_WeatherNotDefined;
}

View File

@ -17,6 +17,13 @@
#include "constants/items.h"
#include "constants/maps.h"
#define DUMMY_PC_BAG_POCKET \
{ \
.id = POCKET_DUMMY, \
.capacity = PC_ITEMS_COUNT, \
.itemSlots = gSaveBlock1Ptr->pcItems, \
}
EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {};
static const u8 *ItemId_GetPluralName(u16);
@ -28,6 +35,27 @@ static bool32 DoesItemHavePluralName(u16);
#include "data/pokemon/item_effects.h"
#include "data/items.h"
#define UNPACK_TM_ITEM_ID(_tm) [CAT(ENUM_TM_HM_, _tm) + 1] = { CAT(ITEM_TM_, _tm), CAT(MOVE_, _tm) },
#define UNPACK_HM_ITEM_ID(_hm) [CAT(ENUM_TM_HM_, _hm) + 1] = { CAT(ITEM_HM_, _hm), CAT(MOVE_, _hm) },
const struct TmHmIndexKey gTMHMItemMoveIds[NUM_ALL_MACHINES + 1] =
{
[0] = { ITEM_NONE, MOVE_NONE }, // Failsafe
FOREACH_TM(UNPACK_TM_ITEM_ID)
FOREACH_HM(UNPACK_HM_ITEM_ID)
/*
* Expands to the following:
*
* [1] = { ITEM_TM_FOCUS_PUNCH, MOVE_FOCUS_PUNCH },
* [2] = { ITEM_TM_DRAGON_CLAW, MOVE_DRAGON_CLAW },
* [3] = { ITEM_TM_WATER_PULSE, MOVE_WATER_PULSE },
* etc etc
*/
};
#undef UNPACK_TM_ITEM_ID
#undef UNPACK_HM_ITEM_ID
static inline u16 GetBagItemIdPocket(struct BagPocket *pocket, u32 pocketPos)
{
return pocket->itemSlots[pocketPos].itemId;
@ -726,9 +754,11 @@ ItemUseFunc GetItemFieldFunc(u16 itemId)
return gItemsInfo[SanitizeItemId(itemId)].fieldUseFunc;
}
bool8 GetItemBattleUsage(u16 itemId)
// Returns an item's battle effect script ID.
u8 GetItemBattleUsage(u16 itemId)
{
u16 item = SanitizeItemId(itemId);
u16 item = SanitizeItemId(itemId);
// Handle E-Reader berries.
if (item == ITEM_ENIGMA_BERRY_E_READER)
{
switch (GetItemEffectType(gSpecialVar_ItemId))
@ -740,7 +770,7 @@ bool8 GetItemBattleUsage(u16 itemId)
case ITEM_EFFECT_CURE_POISON:
case ITEM_EFFECT_CURE_SLEEP:
case ITEM_EFFECT_CURE_BURN:
case ITEM_EFFECT_CURE_FREEZE:
case ITEM_EFFECT_CURE_FREEZE_FROSTBITE:
case ITEM_EFFECT_CURE_PARALYSIS:
case ITEM_EFFECT_CURE_ALL_STATUS:
case ITEM_EFFECT_CURE_CONFUSION:
@ -800,17 +830,18 @@ u32 GetItemStatus1Mask(u16 itemId)
return 0;
}
u32 GetItemStatus2Mask(u16 itemId)
bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile _volatile)
{
const u8 *effect = GetItemEffect(itemId);
if (effect[3] & ITEM3_STATUS_ALL)
return STATUS2_INFATUATION | STATUS2_CONFUSION;
else if (effect[0] & ITEM0_INFATUATION)
return STATUS2_INFATUATION;
else if (effect[3] & ITEM3_CONFUSION)
return STATUS2_CONFUSION;
else
return 0;
switch (_volatile)
{
case VOLATILE_CONFUSION:
return (effect[3] & ITEM3_STATUS_ALL) || (effect[3] & ITEM3_CONFUSION);
case VOLATILE_INFATUATION:
return (effect[3] & ITEM3_STATUS_ALL) || (effect[0] & ITEM0_INFATUATION);
default:
return FALSE;
}
}
u32 GetItemSellPrice(u32 itemId)
@ -818,6 +849,13 @@ u32 GetItemSellPrice(u32 itemId)
return GetItemPrice(itemId) / ITEM_SELL_FACTOR;
}
bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect)
{
return holdEffect == HOLD_EFFECT_CHOICE_BAND
|| holdEffect == HOLD_EFFECT_CHOICE_SCARF
|| holdEffect == HOLD_EFFECT_CHOICE_SPECS;
}
bool8 IsItemTM(u16 itemId)
{
itemId = SanitizeItemId(itemId);

View File

@ -1,4 +1,5 @@
#include "global.h"
#include "battle_main.h"
#include "gflib.h"
#include "decompress.h"
#include "graphics.h"
@ -7,7 +8,6 @@
#include "move.h"
#include "constants/item.h"
#include "constants/items.h"
#include "battle_main.h"
EWRAM_DATA u8 *gItemIconDecompressionBuffer = NULL;
EWRAM_DATA u8 *gItemIcon4x4Buffer = NULL;

View File

@ -89,11 +89,12 @@ static void (*const sExitCallbackByItemType[])(void) = {
[ITEM_USE_PARTY_MENU_MOVES - 1] = CB2_ShowPartyMenuForItemUse
};
#define tEnigmaBerryType data[4]
static void SetUpItemUseCallback(u8 taskId)
{
u8 itemType;
if (gSpecialVar_ItemId == ITEM_ENIGMA_BERRY_E_READER)
itemType = gTasks[taskId].data[4] - 1;
itemType = gTasks[taskId].tEnigmaBerryType - 1;
else
itemType = GetItemType(gSpecialVar_ItemId) - 1;
if (GetPocketByItemId(gSpecialVar_ItemId) == POCKET_BERRIES)
@ -976,9 +977,9 @@ static u32 GetBallThrowableState(void)
return BALL_THROW_UNABLE_TWO_MONS;
else if (IsPlayerPartyAndPokemonStorageFull() == TRUE)
return BALL_THROW_UNABLE_NO_ROOM;
else if (B_SEMI_INVULNERABLE_CATCH >= GEN_4 && (gStatuses3[GetCatchingBattler()] & STATUS3_SEMI_INVULNERABLE))
else if (B_SEMI_INVULNERABLE_CATCH >= GEN_4 && IsSemiInvulnerable(GetCatchingBattler(), CHECK_ALL))
return BALL_THROW_UNABLE_SEMI_INVULNERABLE;
else if (FlagGet(B_FLAG_NO_CATCHING))
else if (FlagGet(B_FLAG_NO_CATCHING) || !IsAllowedToUseBag())
return BALL_THROW_UNABLE_DISABLED_FLAG;
return BALL_THROW_ABLE;
@ -992,6 +993,29 @@ bool32 CanThrowBall(void)
static const u8 sText_CantThrowPokeBall_TwoMons[] = _("Cannot throw a ball!\nThere are two Pokémon out there!\p");
static const u8 sText_CantThrowPokeBall_SemiInvulnerable[] = _("Cannot throw a ball!\nThere's no Pokémon in sight!\p");
static const u8 sText_CantThrowPokeBall_Disabled[] = _("POKé BALLS cannot be used\nright now!\p");
static bool32 IteamHealsMonVolatile(u32 battler, u16 itemId)
{
const u8 *effect = GetItemEffect(itemId);
if (effect[3] & ITEM3_STATUS_ALL)
return (gBattleMons[battler].volatiles.infatuation || gBattleMons[battler].volatiles.confusionTurns > 0);
else if (effect[0] & ITEM0_INFATUATION)
return gBattleMons[battler].volatiles.infatuation;
else if (effect[3] & ITEM3_CONFUSION)
return gBattleMons[battler].volatiles.confusionTurns > 0;
return FALSE;
}
static bool32 SelectedMonHasVolatile(u16 itemId)
{
if (gPartyMenu.slotId == 0)
return IteamHealsMonVolatile(0, itemId);
else if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI) && gPartyMenu.slotId == 1)
return IteamHealsMonVolatile(2, itemId);
return FALSE;
}
// Returns whether an item can be used in battle and sets the fail text.
bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
{
@ -1002,8 +1026,8 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
u16 hp = GetMonData(mon, MON_DATA_HP);
// Embargo Check
if ((gPartyMenu.slotId == 0 && gStatuses3[B_POSITION_PLAYER_LEFT] & STATUS3_EMBARGO)
|| (gPartyMenu.slotId == 1 && gStatuses3[B_POSITION_PLAYER_RIGHT] & STATUS3_EMBARGO))
if ((gPartyMenu.slotId == 0 && gBattleMons[B_POSITION_PLAYER_LEFT].volatiles.embargo)
|| (gPartyMenu.slotId == 1 && gBattleMons[B_POSITION_PLAYER_RIGHT].volatiles.embargo))
{
return TRUE;
}
@ -1016,7 +1040,7 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
cannotUse = TRUE;
break;
case EFFECT_ITEM_SET_FOCUS_ENERGY:
if (gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY)
if (gBattleMons[gBattlerInMenuId].volatiles.dragonCheer || gBattleMons[gBattlerInMenuId].volatiles.focusEnergy)
cannotUse = TRUE;
break;
case EFFECT_ITEM_SET_MIST:
@ -1064,13 +1088,13 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
break;
case EFFECT_ITEM_CURE_STATUS:
if (!((GetMonData(mon, MON_DATA_STATUS) & GetItemStatus1Mask(itemId))
|| (gPartyMenu.slotId == 0 && gBattleMons[gBattlerInMenuId].status2 & GetItemStatus2Mask(itemId))))
|| SelectedMonHasVolatile(itemId)))
cannotUse = TRUE;
break;
case EFFECT_ITEM_HEAL_AND_CURE_STATUS:
if ((hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP))
&& !((GetMonData(mon, MON_DATA_STATUS) & GetItemStatus1Mask(itemId))
|| (gPartyMenu.slotId == 0 && gBattleMons[gBattlerInMenuId].status2 & GetItemStatus2Mask(itemId))))
|| SelectedMonHasVolatile(itemId)))
cannotUse = TRUE;
break;
case EFFECT_ITEM_REVIVE:
@ -1078,11 +1102,11 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
cannotUse = TRUE;
break;
case EFFECT_ITEM_RESTORE_PP:
if (GetItemEffect(itemId)[6] == ITEM4_HEAL_PP)
if (GetItemEffect(itemId)[4] == ITEM4_HEAL_PP)
{
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (GetMonData(mon, MON_DATA_PP1 + i) < CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + i), GetMonData(mon, MON_DATA_PP_BONUSES), i));
if (GetMonData(mon, MON_DATA_PP1 + i) < CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + i), GetMonData(mon, MON_DATA_PP_BONUSES), i))
break;
}
if (i == MAX_MON_MOVES)
@ -1111,7 +1135,7 @@ void ItemUseOutOfBattle_EnigmaBerry(u8 taskId)
case ITEM_EFFECT_CURE_POISON:
case ITEM_EFFECT_CURE_SLEEP:
case ITEM_EFFECT_CURE_BURN:
case ITEM_EFFECT_CURE_FREEZE:
case ITEM_EFFECT_CURE_FREEZE_FROSTBITE:
case ITEM_EFFECT_CURE_PARALYSIS:
case ITEM_EFFECT_CURE_ALL_STATUS:
case ITEM_EFFECT_ATK_EV:
@ -1120,29 +1144,30 @@ void ItemUseOutOfBattle_EnigmaBerry(u8 taskId)
case ITEM_EFFECT_SPDEF_EV:
case ITEM_EFFECT_SPEED_EV:
case ITEM_EFFECT_DEF_EV:
gTasks[taskId].data[4] = 1;
gTasks[taskId].tEnigmaBerryType = ITEM_USE_PARTY_MENU;
ItemUseOutOfBattle_Medicine(taskId);
break;
case ITEM_EFFECT_SACRED_ASH:
gTasks[taskId].data[4] = 1;
gTasks[taskId].tEnigmaBerryType = ITEM_USE_PARTY_MENU;
ItemUseOutOfBattle_SacredAsh(taskId);
break;
case ITEM_EFFECT_RAISE_LEVEL:
gTasks[taskId].data[4] = 1;
gTasks[taskId].tEnigmaBerryType = ITEM_USE_PARTY_MENU;
ItemUseOutOfBattle_RareCandy(taskId);
break;
case ITEM_EFFECT_PP_UP:
case ITEM_EFFECT_PP_MAX:
gTasks[taskId].data[4] = 1;
gTasks[taskId].tEnigmaBerryType = ITEM_USE_PARTY_MENU;
ItemUseOutOfBattle_PPUp(taskId);
break;
case ITEM_EFFECT_HEAL_PP:
gTasks[taskId].data[4] = 1;
gTasks[taskId].tEnigmaBerryType = ITEM_USE_PARTY_MENU;
ItemUseOutOfBattle_PPRecovery(taskId);
break;
default:
gTasks[taskId].data[4] = 4;
gTasks[taskId].tEnigmaBerryType = ITEM_USE_BAG_MENU;
ItemUseOutOfBattle_CannotUse(taskId);
break;
}
}

View File

@ -171,3 +171,11 @@ s32 MathUtil_Inv32(s32 y)
return x / y;
}
u32 MathUtil_Exponent(u32 x, u32 y)
{
u32 result = 1;
for (u32 index = 0; index < y; index++)
result *= x;
return result;
}

View File

@ -352,10 +352,11 @@ void Overworld_ResetBattleFlagsAndVars(void)
FlagClear(B_FLAG_INVERSE_BATTLE);
FlagClear(B_FLAG_FORCE_DOUBLE_WILD);
FlagClear(B_SMART_WILD_AI_FLAG);
FlagClear(B_FLAG_NO_BAG_USE);
FlagClear(B_FLAG_NO_CATCHING);
FlagClear(B_FLAG_NO_RUNNING);
FlagClear(B_FLAG_DYNAMAX_BATTLE);
FlagClear(B_FLAG_SKY_BATTLE);
FlagClear(B_FLAG_NO_WHITEOUT);
}
#endif

View File

@ -4545,7 +4545,7 @@ static bool8 IsHPRecoveryItem(u16 item)
return FALSE;
}
static void GetMedicineItemEffectMessage(u16 item)
static void GetMedicineItemEffectMessage(u16 item, u32 statusCured)
{
switch (GetItemEffectType(item))
{
@ -4558,8 +4558,11 @@ static void GetMedicineItemEffectMessage(u16 item)
case ITEM_EFFECT_CURE_BURN:
StringExpandPlaceholders(gStringVar4, gText_PkmnBurnHealed);
break;
case ITEM_EFFECT_CURE_FREEZE:
StringExpandPlaceholders(gStringVar4, gText_PkmnThawedOut);
case ITEM_EFFECT_CURE_FREEZE_FROSTBITE:
if (statusCured & STATUS1_FREEZE)
StringExpandPlaceholders(gStringVar4, gText_PkmnThawedOut);
if (statusCured & STATUS1_FROSTBITE)
StringExpandPlaceholders(gStringVar4, gText_PkmnFrostbiteHealed);
break;
case ITEM_EFFECT_CURE_PARALYSIS:
StringExpandPlaceholders(gStringVar4, gText_PkmnCuredOfParalysis);
@ -5013,6 +5016,7 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc func)
struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId];
u16 item = gSpecialVar_ItemId;
bool8 canHeal, cannotUse;
u32 oldStatus = GetMonData(mon, MON_DATA_STATUS);
if (NotUsingHPEVItemOnShedinja(mon, item) == FALSE) {
cannotUse = TRUE;
@ -5062,7 +5066,7 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc func)
else
{
GetMonNickname(mon, gStringVar1);
GetMedicineItemEffectMessage(item);
GetMedicineItemEffectMessage(item, oldStatus);
DisplayPartyMenuMessage(gStringVar4, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = func;
@ -5353,7 +5357,7 @@ static void ItemUseCB_RestorePP(u8 taskId, TaskFunc func)
RemoveBagItem(gSpecialVar_ItemId, 1);
move = GetMonData(mon, gPartyMenu.ppMoveSlot + MON_DATA_MOVE1);
StringCopy(gStringVar1, gMovesInfo[move].name);
GetMedicineItemEffectMessage(gSpecialVar_ItemId);
GetMedicineItemEffectMessage(gSpecialVar_ItemId, 0);
DisplayPartyMenuMessage(gStringVar4, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_ClosePartyMenuAfterText;
@ -6127,16 +6131,16 @@ u8 GetItemEffectType(u16 item)
u32 statusCure;
const u8 *itemEffect = GetItemEffect(item);
// Read the item's effect properties.
if (itemEffect == NULL)
return ITEM_EFFECT_NONE;
if ((itemEffect[0] & ITEM0_DIRE_HIT) || itemEffect[1] || itemEffect[2] || (itemEffect[3] & ITEM3_GUARD_SPEC))
if ((itemEffect[0] & ITEM0_DIRE_HIT) || itemEffect[1] || (itemEffect[3] & ITEM3_GUARD_SPEC))
return ITEM_EFFECT_X_ITEM;
else if (itemEffect[0] & ITEM0_SACRED_ASH)
return ITEM_EFFECT_SACRED_ASH;
else if (itemEffect[3] & ITEM3_LEVEL_UP)
return ITEM_EFFECT_RAISE_LEVEL;
statusCure = itemEffect[3] & ITEM3_STATUS_ALL;
if (statusCure || (itemEffect[0] >> 7))
{
@ -6147,7 +6151,7 @@ u8 GetItemEffectType(u16 item)
else if (statusCure == ITEM3_BURN)
return ITEM_EFFECT_CURE_BURN;
else if (statusCure == ITEM3_FREEZE)
return ITEM_EFFECT_CURE_FREEZE;
return ITEM_EFFECT_CURE_FREEZE_FROSTBITE;
else if (statusCure == ITEM3_PARALYSIS)
return ITEM_EFFECT_CURE_PARALYSIS;
else if (statusCure == ITEM3_CONFUSION)
@ -6157,6 +6161,7 @@ u8 GetItemEffectType(u16 item)
else
return ITEM_EFFECT_CURE_ALL_STATUS;
}
if (itemEffect[4] & (ITEM4_REVIVE | ITEM4_HEAL_HP))
return ITEM_EFFECT_HEAL_HP;
else if (itemEffect[4] & ITEM4_EV_ATK)

File diff suppressed because it is too large Load Diff

View File

@ -523,6 +523,11 @@ static void Task_HandleMonAnimation(u8 taskId)
sprite->data[2] = gTasks[taskId].tSpeciesId;
sprite->data[1] = 0;
// Task_HandleMonAnimation handles more than just KO animations,
// but if the counter is non-zero then only KO animations are running.
// This assumption is not checked.
if (gBattleStruct->battlerKOAnimsRunning > 0)
gBattleStruct->battlerKOAnimsRunning--;
DestroyTask(taskId);
}
}

View File

@ -346,35 +346,35 @@ void RecordedBattle_CopyBattlerMoves(u32 battler)
void RecordedBattle_CheckMovesetChanges(u8 mode)
{
s32 battlerId, j, k;
s32 battler, j, k;
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
return;
for (battlerId = 0; battlerId < gBattlersCount; battlerId++)
for (battler = 0; battler < gBattlersCount; battler++)
{
// Player's side only
if (GetBattlerSide(battlerId) != B_SIDE_OPPONENT)
if (IsOnPlayerSide(battler))
{
if (mode == B_RECORD_MODE_RECORDING)
{
// Check if any of the battler's moves have changed.
for (j = 0; j < MAX_MON_MOVES; j++)
{
if (gBattleMons[battlerId].moves[j] != sPlayerMonMoves[battlerId / 2][j])
if (gBattleMons[battler].moves[j] != sPlayerMonMoves[battler / 2][j])
break;
}
if (j != MAX_MON_MOVES)
{
// At least one of the moves has been changed
RecordedBattle_SetBattlerAction(battlerId, ACTION_MOVE_CHANGE);
RecordedBattle_SetBattlerAction(battler, ACTION_MOVE_CHANGE);
for (j = 0; j < MAX_MON_MOVES; j++)
{
for (k = 0; k < MAX_MON_MOVES; k++)
{
if (gBattleMons[battlerId].moves[j] == sPlayerMonMoves[battlerId / 2][k])
if (gBattleMons[battler].moves[j] == sPlayerMonMoves[battler / 2][k])
{
RecordedBattle_SetBattlerAction(battlerId, k);
RecordedBattle_SetBattlerAction(battler, k);
break;
}
}
@ -383,7 +383,7 @@ void RecordedBattle_CheckMovesetChanges(u8 mode)
}
else // B_RECORD_MODE_PLAYBACK
{
if (sBattleRecords[battlerId][sBattlerRecordSizes[battlerId]] == ACTION_MOVE_CHANGE)
if (sBattleRecords[battler][sBattlerRecordSizes[battler]] == ACTION_MOVE_CHANGE)
{
u8 ppBonuses[MAX_MON_MOVES];
u8 moveSlots[MAX_MON_MOVES];
@ -393,55 +393,56 @@ void RecordedBattle_CheckMovesetChanges(u8 mode)
// We know the current action is ACTION_MOVE_CHANGE, retrieve
// it without saving it to move on to the next action.
RecordedBattle_GetBattlerAction(RECORDED_BYTE, battlerId);
RecordedBattle_GetBattlerAction(RECORDED_BYTE, battler);
for (j = 0; j < MAX_MON_MOVES; j++)
ppBonuses[j] = ((gBattleMons[battlerId].ppBonuses & (3 << (j << 1))) >> (j << 1));
ppBonuses[j] = ((gBattleMons[battler].ppBonuses & (3 << (j << 1))) >> (j << 1));
for (j = 0; j < MAX_MON_MOVES; j++)
{
moveSlots[j] = RecordedBattle_GetBattlerAction(RECORDED_BYTE, battlerId);
movePp.moves[j] = gBattleMons[battlerId].moves[moveSlots[j]];
movePp.currentPp[j] = gBattleMons[battlerId].pp[moveSlots[j]];
moveSlots[j] = RecordedBattle_GetBattlerAction(RECORDED_BYTE, battler);
movePp.moves[j] = gBattleMons[battler].moves[moveSlots[j]];
movePp.currentPp[j] = gBattleMons[battler].pp[moveSlots[j]];
movePp.maxPp[j] = ppBonuses[moveSlots[j]];
mimickedMoveSlots[j] = (gDisableStructs[battlerId].mimickedMoves & gBitTable[j]) >> j;
mimickedMoveSlots[j] = (gDisableStructs[battler].mimickedMoves & (1u << j)) >> j;
}
for (j = 0; j < MAX_MON_MOVES; j++)
{
gBattleMons[battlerId].moves[j] = movePp.moves[j];
gBattleMons[battlerId].pp[j] = movePp.currentPp[j];
gBattleMons[battler].moves[j] = movePp.moves[j];
gBattleMons[battler].pp[j] = movePp.currentPp[j];
}
gBattleMons[battlerId].ppBonuses = 0;
gDisableStructs[battlerId].mimickedMoves = 0;
gBattleMons[battler].ppBonuses = 0;
gDisableStructs[battler].mimickedMoves = 0;
for (j = 0; j < MAX_MON_MOVES; j++)
{
gBattleMons[battlerId].ppBonuses |= movePp.maxPp[j] << (j << 1);
gDisableStructs[battlerId].mimickedMoves |= mimickedMoveSlots[j] << j;
gBattleMons[battler].ppBonuses |= movePp.maxPp[j] << (j << 1);
gDisableStructs[battler].mimickedMoves |= mimickedMoveSlots[j] << j;
}
if (!(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED))
if (!(gBattleMons[battler].volatiles.transformed))
{
struct Pokemon *mon = GetBattlerMon(battler);
for (j = 0; j < MAX_MON_MOVES; j++)
ppBonuses[j] = (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP_BONUSES, NULL) & ((3 << (j << 1)))) >> (j << 1);
ppBonuses[j] = (GetMonData(mon, MON_DATA_PP_BONUSES, NULL) & ((3 << (j << 1)))) >> (j << 1);
for (j = 0; j < MAX_MON_MOVES; j++)
{
movePp.moves[j] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_MOVE1 + moveSlots[j], NULL);
movePp.currentPp[j] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP1 + moveSlots[j], NULL);
movePp.moves[j] = GetMonData(mon, MON_DATA_MOVE1 + moveSlots[j], NULL);
movePp.currentPp[j] = GetMonData(mon, MON_DATA_PP1 + moveSlots[j], NULL);
movePp.maxPp[j] = ppBonuses[moveSlots[j]];
}
for (j = 0; j < MAX_MON_MOVES; j++)
{
SetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_MOVE1 + j, &movePp.moves[j]);
SetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP1 + j, &movePp.currentPp[j]);
SetMonData(mon, MON_DATA_MOVE1 + j, &movePp.moves[j]);
SetMonData(mon, MON_DATA_PP1 + j, &movePp.currentPp[j]);
}
ppBonusSet = 0;
for (j = 0; j < MAX_MON_MOVES; j++)
ppBonusSet |= movePp.maxPp[j] << (j << 1);
SetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP_BONUSES, &ppBonusSet);
SetMonData(mon, MON_DATA_PP_BONUSES, &ppBonusSet);
}
gChosenMoveByBattler[battlerId] = gBattleMons[battlerId].moves[*(gBattleStruct->chosenMovePositions + battlerId)];
gChosenMoveByBattler[battler] = GetChosenMoveFromPosition(battler);
}
}
}

Some files were not shown because too many files have changed in this diff Show More