Skip to content

Commit

Permalink
Gimmick Refactor (#4449)
Browse files Browse the repository at this point in the history
* consolidated gimmick checks, triggers, communication, and activation; updated test runner

* fixed improper use of .usableGimmick

* cleaning up battle_dynamax.c, changing function args to u32s

* fixed '#ifdef TESTING' causing errors

* updated z-moves to use gimmick interface, pared down redundancies; no AI/tests

* added support for z-moves in tests, consolidated gimmick fields

* removed ShouldUseMaxMove and .usingMaxMove

* renamed TryChangeZIndicator, updated z move display

* added several z-move tests and fixed various z-move interactions; fixed z-move category calc

* fixed useless battler arg in GetTypeBasedZMove

* added basic test check for bad Z-Move or Mega usage

* reworked test runner gimmick functionality; added support for Ultra Burst + Z-Move to test Light That Burns the Sky

* fixed gimmick test logic; fixed damage category override

* fixed mega rayquaza test fail

* consolidated gimmick indicator logic; added graphics to gGimmicksInfo

* removed TeraData struct

* reimplemented AI logic for Z-Moves; no changes

* updated Z-Move and Ultra Burst trigger gfx

* added testrunner check for multiple gimmick use

* fixed duplicate z-move call in test

* reorganized data/graphics/gimmicks.h

* added signature Z-Move ability tests; implemented Guardian of Alola

* fixed bad test update

* fixed Thousand Arrows not affecting Tera Flying; clean-up

* fixed -ate tests

* fixed tera tests

* fixed tera tests really

* fixed last batch of tests

* fixed -ate mega test again

* code review

* code review pt.2

* tweaked CanTera again

* dynamax flag only required for player
  • Loading branch information
AgustinGDLV authored Jun 22, 2024
1 parent 2640bcd commit 9797640
Show file tree
Hide file tree
Showing 53 changed files with 2,207 additions and 2,657 deletions.
4 changes: 4 additions & 0 deletions asm/macros/battle_script.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,10 @@
callnative BS_ApplyTerastallization
.endm

.macro damagetoquartertargethp
callnative BS_DamageToQuarterTargetHP
.endm

@ various command changed to more readable macros
.macro cancelmultiturnmoves battler:req
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES
Expand Down
29 changes: 21 additions & 8 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@

.section script_data, "aw", %progbits

BattleScript_DamageToQuarterTargetHP::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
typecalc
bichalfword gMoveResultFlags, MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE
damagetoquartertargethp
goto BattleScript_HitFromAtkAnimation

BattleScript_Terastallization::
@ TODO: no string prints in S/V, but right now this helps with clarity
printstring STRINGID_PKMNSTORINGENERGY
Expand Down Expand Up @@ -6528,6 +6538,9 @@ BattleScript_PerishSongCountGoesDown::
waitmessage B_WAIT_TIME_LONG
end2

BattleScript_AllStatsUpZMove::
printfromtable gZEffectStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_AllStatsUp::
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AllStatsUpAtk
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_DEF, MAX_STAT_STAGE, BattleScript_AllStatsUpAtk
Expand Down Expand Up @@ -6986,13 +6999,13 @@ BattleScript_MegaEvolution::
BattleScript_MegaEvolutionAfterString:
waitmessage B_WAIT_TIME_LONG
setbyte gIsCriticalHit, 0
handlemegaevo BS_ATTACKER, 0
playanimation BS_ATTACKER, B_ANIM_MEGA_EVOLUTION
handlemegaevo BS_SCRIPTING, 0
playanimation BS_SCRIPTING, B_ANIM_MEGA_EVOLUTION
waitanimation
handlemegaevo BS_ATTACKER, 1
handlemegaevo BS_SCRIPTING, 1
printstring STRINGID_MEGAEVOEVOLVED
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
switchinabilities BS_SCRIPTING
end3

BattleScript_WishMegaEvolution::
Expand Down Expand Up @@ -7029,13 +7042,13 @@ BattleScript_UltraBurst::
printstring STRINGID_ULTRABURSTREACTING
waitmessage B_WAIT_TIME_LONG
setbyte gIsCriticalHit, 0
handleultraburst BS_ATTACKER, 0
playanimation BS_ATTACKER, B_ANIM_ULTRA_BURST
handleultraburst BS_SCRIPTING, 0
playanimation BS_SCRIPTING, B_ANIM_ULTRA_BURST
waitanimation
handleultraburst BS_ATTACKER, 1
handleultraburst BS_SCRIPTING, 1
printstring STRINGID_ULTRABURSTCOMPLETED
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
switchinabilities BS_SCRIPTING
end3

BattleScript_GulpMissileFormChange::
Expand Down
Binary file modified graphics/battle_interface/burst_trigger.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified graphics/battle_interface/z_move_trigger.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 13 additions & 50 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "battle_debug.h"
#include "battle_dynamax.h"
#include "battle_terastal.h"
#include "battle_gimmick.h"
#include "random.h" // for rng_value_t

// Helper for accessing command arguments and advancing gBattlescriptCurrInstr.
Expand Down Expand Up @@ -370,8 +371,6 @@ struct AiLogicData
bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once.
u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId.
struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c
bool8 shouldTerastal[MAX_BATTLERS_COUNT];
bool8 shouldDynamax[MAX_BATTLERS_COUNT];
};

struct AI_ThinkingStruct
Expand Down Expand Up @@ -558,24 +557,6 @@ struct LinkBattlerHeader
struct BattleEnigmaBerry battleEnigmaBerry;
};

struct MegaEvolutionData
{
u8 toEvolve; // As flags using gBitTable.
bool8 alreadyEvolved[4]; // Array id is used for mon position.
u8 battlerId;
bool8 playerSelect;
u8 triggerSpriteId;
};

struct UltraBurstData
{
u8 toBurst; // As flags using gBitTable.
bool8 alreadyBursted[4]; // Array id is used for mon position.
u8 battlerId;
bool8 playerSelect;
u8 triggerSpriteId;
};

struct Illusion
{
u8 on;
Expand All @@ -587,48 +568,30 @@ struct Illusion

struct ZMoveData
{
u8 viable:1; // current move can become a z move
u8 viable:1; // current move can become a z move
u8 viewing:1; // if player is viewing the z move name instead of regular moves
u8 active:1; // is z move being used this turn
u8 zStatusActive:1;
u8 healReplacement:1;
u8 activeCategory:2; // active z move category
u8 zUnused:1;
u8 triggerSpriteId;
u8 healReplacement:6;
u8 possibleZMoves[MAX_BATTLERS_COUNT];
u16 chosenZMove; // z move of move cursor is on
u8 effect;
u8 used[MAX_BATTLERS_COUNT]; //one per bank for multi-battles
u16 toBeUsed[MAX_BATTLERS_COUNT]; // z moves per battler to be used
u16 baseMoves[MAX_BATTLERS_COUNT];
u8 categories[MAX_BATTLERS_COUNT];
};

struct DynamaxData
{
bool8 playerSelect;
u8 triggerSpriteId;
u8 toDynamax; // flags using gBitTable
bool8 alreadyDynamaxed[NUM_BATTLE_SIDES];
bool8 dynamaxed[MAX_BATTLERS_COUNT];
u8 dynamaxTurns[MAX_BATTLERS_COUNT];
u8 usingMaxMove[MAX_BATTLERS_COUNT];
u8 activeCategory;
u8 categories[MAX_BATTLERS_COUNT];
u16 baseMove[MAX_BATTLERS_COUNT]; // base move of Max Move
u16 baseMoves[MAX_BATTLERS_COUNT]; // base move of Max Move
u16 lastUsedBaseMove;
u16 levelUpHP;
};

struct TeraData
struct BattleGimmickData
{
bool8 toTera; // flags using gBitTable
bool8 isTerastallized[NUM_BATTLE_SIDES]; // stored as a bitfield for each side's party members
bool8 alreadyTerastallized[MAX_BATTLERS_COUNT];
bool8 playerSelect;
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
u8 usableGimmick[MAX_BATTLERS_COUNT]; // first usable gimmick that can be selected for each battler
bool8 playerSelect; // used to toggle trigger and update battle UI
u8 triggerSpriteId;
u8 indicatorSpriteId[MAX_BATTLERS_COUNT];
u8 toActivate; // stores whether a battler should transform at start of turn as bitfield
u8 activeGimmick[NUM_BATTLE_SIDES][PARTY_SIZE]; // stores the active gimmick for each party member
bool8 activated[MAX_BATTLERS_COUNT][GIMMICKS_COUNT]; // stores whether a trainer has used gimmick
};

struct LostItem
Expand Down Expand Up @@ -753,11 +716,9 @@ struct BattleStruct
u8 activeAbilityPopUps; // as bits for each battler
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler
bool8 throwingPokeBall;
struct MegaEvolutionData mega;
struct UltraBurstData burst;
struct ZMoveData zmove;
struct DynamaxData dynamax;
struct TeraData tera;
struct BattleGimmickData gimmick;
const u8 *trainerSlideMsg;
bool8 trainerSlideLowHpMsgDone;
u8 introState;
Expand Down Expand Up @@ -832,6 +793,8 @@ struct BattleStruct
u8 shellSideArmCategory[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT];
u8 boosterEnergyActivates;
u8 distortedTypeMatchups;
u8 categoryOverride; // for Z-Moves and Max Moves
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
};

// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,
Expand Down
7 changes: 1 addition & 6 deletions include/battle_controllers.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,7 @@ enum {

// Special return values in gBattleBufferB from Battle Controller functions.
#define RET_VALUE_LEVELED_UP 11
#define RET_MEGA_EVOLUTION (1 << 7)
#define RET_ULTRA_BURST (1 << 6)
#define RET_DYNAMAX (1 << 5)
#define RET_TERASTAL (1 << 4)
#define RET_GIMMICK (1 << 7)

struct UnusedControllerStruct
{
Expand Down Expand Up @@ -131,8 +128,6 @@ struct ChooseMoveStruct
u8 monType1;
u8 monType2;
u8 monType3;
struct MegaEvolutionData mega;
struct UltraBurstData burst;
struct ZMoveData zmove;
};

Expand Down
30 changes: 11 additions & 19 deletions include/battle_dynamax.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,19 @@ enum MaxMoveEffect
MAX_EFFECT_BYPASS_PROTECT,
};

bool32 IsDynamaxed(u16 battlerId);
bool32 CanDynamax(u16 battlerId);
bool32 IsGigantamaxed(u16 battlerId);
bool32 CanDynamax(u32 battler);
bool32 IsGigantamaxed(u32 battler);
void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon);
void PrepareBattlerForDynamax(u16 battlerId);
u16 GetNonDynamaxHP(u16 battlerId);
u16 GetNonDynamaxMaxHP(u32 battlerId);
void UndoDynamax(u16 battlerId);
bool32 IsMoveBlockedByMaxGuard(u16 move);
bool32 IsMoveBlockedByDynamax(u16 move);
void ActivateDynamax(u32 battler);
u16 GetNonDynamaxHP(u32 battler);
u16 GetNonDynamaxMaxHP(u32 battler);
void UndoDynamax(u32 battler);
bool32 IsMoveBlockedByMaxGuard(u32 move);
bool32 IsMoveBlockedByDynamax(u32 move);

bool32 ShouldUseMaxMove(u16 battlerId, u16 baseMove);
u16 GetMaxMove(u16 battlerId, u16 baseMove);
u8 GetMaxMovePower(u16 move);
bool32 IsMaxMove(u16 move);
u16 GetMaxMove(u32 battler, u32 baseMove);
u8 GetMaxMovePower(u32 move);
bool32 IsMaxMove(u32 move);
void ChooseDamageNonTypesString(u8 type);

void BS_UpdateDynamax(void);
Expand All @@ -83,10 +81,4 @@ void BS_HealOneSixth(void);
void BS_TryRecycleBerry(void);
void BS_JumpIfDynamaxed(void);

void ChangeDynamaxTriggerSprite(u8 spriteId, u8 animId);
void CreateDynamaxTriggerSprite(u8, bool8);
void HideDynamaxTriggerSprite(void);
bool32 IsDynamaxTriggerSpriteActive(void);
void DestroyDynamaxTriggerSprite(void);

#endif
51 changes: 51 additions & 0 deletions include/battle_gimmick.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef GUARD_BATTLE_GIMMICK_H
#define GUARD_BATTLE_GIMMICK_H

enum Gimmick
{
GIMMICK_NONE,
GIMMICK_MEGA,
GIMMICK_ULTRA_BURST,
GIMMICK_Z_MOVE,
GIMMICK_DYNAMAX,
GIMMICK_TERA,
GIMMICKS_COUNT,
};

struct GimmickInfo
{
const struct SpritePalette *triggerPal; // trigger gfx data
const struct SpriteSheet *triggerSheet;
const struct SpriteTemplate *triggerTemplate;
const struct SpritePalette *indicatorPal; // indicator gfx data
const struct SpriteSheet *indicatorSheet;
bool32 (*CanActivate)(u32 battler);
void (*ActivateGimmick)(u32 battler);
};

void AssignUsableGimmicks(void);
bool32 CanActivateGimmick(u32 battler, enum Gimmick gimmick);
bool32 IsGimmickSelected(u32 battler, enum Gimmick gimmick);
void SetActiveGimmick(u32 battler, enum Gimmick gimmick);
enum Gimmick GetActiveGimmick(u32 battler);
bool32 ShouldTrainerBattlerUseGimmick(u32 battler, enum Gimmick gimmick);
bool32 HasTrainerUsedGimmick(u32 battler, enum Gimmick gimmick);
void SetGimmickAsActivated(u32 battler, enum Gimmick gimmick);

void ChangeGimmickTriggerSprite(u32 spriteId, u32 animId);
void CreateGimmickTriggerSprite(u32 battler);
bool32 IsGimmickTriggerSpriteActive(void);
void HideGimmickTriggerSprite(void);
void DestroyGimmickTriggerSprite(void);

void LoadIndicatorSpritesGfx(void);
u32 GetIndicatorTileTag(u32 battler);
u32 GetIndicatorPalTag(u32 battler);
void UpdateIndicatorVisibilityAndType(u32 healthboxId, bool32 invisible);
void UpdateIndicatorOamPriority(u32 healthboxId, u32 oamPriority);
void UpdateIndicatorLevelData(u32 healthboxId, u32 level);
void CreateIndicatorSprite(u32 battler);

extern const struct GimmickInfo gGimmicksInfo[];

#endif
Loading

0 comments on commit 9797640

Please sign in to comment.