Skip to content

Commit

Permalink
Implement Ultra Burst (#3221)
Browse files Browse the repository at this point in the history
  • Loading branch information
AsparagusEduardo authored Aug 30, 2023
2 parents 766a1a2 + c427d96 commit deb2055
Show file tree
Hide file tree
Showing 31 changed files with 574 additions and 18 deletions.
5 changes: 5 additions & 0 deletions asm/macros/battle_script.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,11 @@
.byte \case
.endm

.macro handleultraburst battler:req, case:req
various \battler, VARIOUS_HANDLE_ULTRA_BURST
.byte \case
.endm

.macro handleformchange battler:req, case:req
various \battler, VARIOUS_HANDLE_FORM_CHANGE
.byte \case
Expand Down
38 changes: 38 additions & 0 deletions data/battle_anim_scripts.s
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ gBattleAnims_General::
.4byte General_ZMoveActivate @ B_ANIM_ZMOVE_ACTIVATE
.4byte General_AffectionHangedOn @ B_ANIM_AFFECTION_HANGED_ON
.4byte General_Snow @ B_ANIM_SNOW_CONTINUES
.4byte General_UltraBurst @ B_ANIM_ULTRA_BURST

.align 2
gBattleAnims_Special::
Expand Down Expand Up @@ -27002,6 +27003,43 @@ General_PrimalReversion_Omega:
blendoff
end

General_UltraBurst::
loadspritegfx ANIM_TAG_ULTRA_BURST_SYMBOL
loadspritegfx ANIM_TAG_SPARK_2 @spark
loadspritegfx ANIM_TAG_LEAF @green
loadspritegfx ANIM_TAG_ELECTRIC_ORBS @charge particles
loadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT @psycho boost
monbg ANIM_ATTACKER
setalpha 12, 8
createvisualtask AnimTask_BlendBattleAnimPal, 0xa, (F_PAL_BG | F_PAL_ADJACENT), 0x2, 0x0, 0xF, 0x0000
waitforvisualfinish
createvisualtask AnimTask_ElectricChargingParticles, 2, ANIM_ATTACKER, 60, 2, 12 @ charge particles to attacker
delay 0x1e
loopsewithpan SE_M_CHARGE, SOUND_PAN_ATTACKER, 0xe, 0xa
createsprite gSuperpowerOrbSpriteTemplate, ANIM_TARGET, 3, 0x0
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
call LightThatBurnsTheSkyGreenSparks
delay 20
createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 0, 16, RGB_WHITEALPHA
createvisualtask AnimTask_TransformMon, 2, 1, 0
createsprite gUltraBurstSymbolSpriteTemplate, ANIM_ATTACKER, 0x0, 0x0, 0x0, 0x0, 0x0
waitforvisualfinish
createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 16, 0, RGB_WHITEALPHA
createvisualtask AnimTask_HorizontalShake, 5, ANIM_TARGET, 5, 14
waitforvisualfinish
createvisualtask SoundTask_PlayNormalCry, 0
waitforvisualfinish
clearmonbg ANIM_ATK_PARTNER
blendoff
end

General_AffectionHangedOn::
loadspritegfx ANIM_TAG_RED_HEART
loopsewithpan SE_M_CHARM, SOUND_PAN_ATTACKER, 12, 3
Expand Down
15 changes: 15 additions & 0 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -7796,6 +7796,21 @@ BattleScript_PrimalReversionRet::
switchinabilities BS_ATTACKER
return

BattleScript_UltraBurst::
printstring STRINGID_EMPTYSTRING3
trytrainerslidezmovemsg BS_ATTACKER
printstring STRINGID_ULTRABURSTREACTING
waitmessage B_WAIT_TIME_LONG
setbyte gIsCriticalHit, 0
handleultraburst BS_ATTACKER, 0
playanimation BS_ATTACKER, B_ANIM_ULTRA_BURST
waitanimation
handleultraburst BS_ATTACKER, 1
printstring STRINGID_ULTRABURSTCOMPLETED
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
end3

BattleScript_AttackerFormChange::
pause 5
copybyte gBattlerAbility, gBattlerAttacker
Expand Down
Binary file added 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.
10 changes: 10 additions & 0 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,15 @@ struct MegaEvolutionData
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 Down Expand Up @@ -616,6 +625,7 @@ struct BattleStruct
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler
bool8 throwingPokeBall;
struct MegaEvolutionData mega;
struct UltraBurstData burst;
struct ZMoveData zmove;
const u8 *trainerSlideMsg;
bool8 trainerSlideLowHpMsgDone;
Expand Down
2 changes: 2 additions & 0 deletions include/battle_controllers.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ enum {
// Special return values in gBattleBufferB from Battle Controller functions.
#define RET_VALUE_LEVELED_UP 11
#define RET_MEGA_EVOLUTION 0x80
#define RET_ULTRA_BURST 0x70

struct UnusedControllerStruct
{
Expand Down Expand Up @@ -129,6 +130,7 @@ struct ChooseMoveStruct
u8 monType2;
u8 monType3;
struct MegaEvolutionData mega;
struct UltraBurstData burst;
struct ZMoveData zmove;
};

Expand Down
7 changes: 7 additions & 0 deletions include/battle_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ enum
#define TAG_ALPHA_INDICATOR_TILE 0xD779
#define TAG_OMEGA_INDICATOR_TILE 0xD77A
#define TAG_ZMOVE_TRIGGER_TILE 0xD77B
#define TAG_BURST_TRIGGER_TILE 0xD77C

#define TAG_MEGA_TRIGGER_PAL 0xD777
#define TAG_MEGA_INDICATOR_PAL 0xD778
#define TAG_ALPHA_OMEGA_INDICATOR_PAL 0xD779 // Alpha and Omega indicators use the same palette as each of them only uses 4 different colors.
#define TAG_ZMOVE_TRIGGER_PAL 0xD77B
#define TAG_BURST_TRIGGER_PAL 0xD77C

enum
{
Expand Down Expand Up @@ -91,6 +93,11 @@ void CreateMegaTriggerSprite(u8 battlerId, u8 palId);
bool32 IsMegaTriggerSpriteActive(void);
void HideMegaTriggerSprite(void);
void DestroyMegaTriggerSprite(void);
void ChangeBurstTriggerSprite(u8 spriteId, u8 animId);
void CreateBurstTriggerSprite(u8 battlerId, u8 palId);
bool32 IsBurstTriggerSpriteActive(void);
void HideBurstTriggerSprite(void);
void DestroyBurstTriggerSprite(void);
void MegaIndicator_LoadSpritesGfx(void);
u8 CreatePartyStatusSummarySprites(u8 battler, struct HpAndStatus *partyInfo, bool8 skipPlayer, bool8 isBattleStart);
void Task_HidePartyStatusSummary(u8 taskId);
Expand Down
1 change: 1 addition & 0 deletions include/battle_scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ extern const u8 BattleScript_SpikesActivates[];
extern const u8 BattleScript_BerserkGeneRet[];
extern const u8 BattleScript_TargetFormChangeWithStringNoPopup[];
extern const u8 BattleScript_DefDown[];
extern const u8 BattleScript_UltraBurst[];

// zmoves
extern const u8 BattleScript_ZMoveActivateDamaging[];
Expand Down
2 changes: 2 additions & 0 deletions include/battle_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,10 @@ uq4_12_t GetTypeModifier(u8 atkType, u8 defType);
s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId);
s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp);
bool32 CanMegaEvolve(u8 battlerId);
bool32 CanUltraBurst(u8 battlerId);
bool32 IsBattlerMegaEvolved(u8 battlerId);
bool32 IsBattlerPrimalReverted(u8 battlerId);
bool32 IsBattlerUltraBursted(u8 battlerId);
u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method);
bool32 TryBattleFormChange(u8 battlerId, u16 method);
bool32 DoBattlersShareType(u32 battler1, u32 battler2);
Expand Down
5 changes: 5 additions & 0 deletions include/constants/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,4 +495,9 @@
#define PARENTAL_BOND_2ND_HIT 1
#define PARENTAL_BOND_OFF 0

// Constants for if HandleScriptMegaPrimalBurst should handle Mega Evolution, Primal Reversion, or Ultra Burst.
#define HANDLE_TYPE_MEGA_EVOLUTION 0
#define HANDLE_TYPE_PRIMAL_REVERSION 1
#define HANDLE_TYPE_ULTRA_BURST 2

#endif // GUARD_CONSTANTS_BATTLE_H
1 change: 1 addition & 0 deletions include/constants/battle_anim.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@
#define B_ANIM_ZMOVE_ACTIVATE 34 // Using Z Moves
#define B_ANIM_AFFECTION_HANGED_ON 35
#define B_ANIM_SNOW_CONTINUES 36
#define B_ANIM_ULTRA_BURST 37

// special animations table (gBattleAnims_Special)
#define B_ANIM_LVL_UP 0
Expand Down
1 change: 1 addition & 0 deletions include/constants/battle_script_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@
#define VARIOUS_TRY_REVIVAL_BLESSING 165
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_Z_MOVE 166
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_MEGA_EVOLUTION 167
#define VARIOUS_HANDLE_ULTRA_BURST 168

// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0
Expand Down
4 changes: 3 additions & 1 deletion include/constants/battle_string_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,10 @@
#define STRINGID_SNOWSTOPPED 663
#define STRINGID_SNOWWARNINGSNOW 664
#define STRINGID_PKMNITEMMELTED 665
#define STRINGID_ULTRABURSTREACTING 666
#define STRINGID_ULTRABURSTCOMPLETED 667

#define BATTLESTRINGS_COUNT 666
#define BATTLESTRINGS_COUNT 668

// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
Expand Down
5 changes: 5 additions & 0 deletions include/constants/form_change_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,9 @@
// param1: ability to check.
#define FORM_CHANGE_BATTLE_TURN_END 15

// Form change that activates when the mon has the defined item.
// If it's on the player's side, it also requires for the player to trigger it by pressing START before selecting a move.
// param1: item to hold.
#define FORM_CHANGE_BATTLE_ULTRA_BURST 16

#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H
1 change: 1 addition & 0 deletions include/constants/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@
#define SPECIES_FLAG_HISUIAN_FORM (1 << 7)
#define SPECIES_FLAG_ALL_PERFECT_IVS (1 << 8)
#define SPECIES_FLAG_CANNOT_BE_TRADED (1 << 9)
#define SPECIES_FLAG_ULTRA_BURST (1 << 10)

#define LEGENDARY_PERFECT_IV_COUNT 3

Expand Down
2 changes: 2 additions & 0 deletions include/test/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,8 @@ struct MoveContext
u16 explicitSecondaryEffect:1;
u16 megaEvolve:1;
u16 explicitMegaEvolve:1;
u16 ultraBurst:1;
u16 explicitUltraBurst:1;
// TODO: u8 zMove:1;
u16 allowed:1;
u16 explicitAllowed:1;
Expand Down
1 change: 1 addition & 0 deletions src/battle_anim.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ void LaunchBattleAnimation(u32 animType, u32 animId)
case B_ANIM_WISH_HEAL:
case B_ANIM_MEGA_EVOLUTION:
case B_ANIM_PRIMAL_REVERSION:
case B_ANIM_ULTRA_BURST:
case B_ANIM_GULP_MISSILE:
sAnimHideHpBoxes = TRUE;
break;
Expand Down
12 changes: 12 additions & 0 deletions src/battle_anim_new.c
Original file line number Diff line number Diff line change
Expand Up @@ -4761,6 +4761,18 @@ const struct SpriteTemplate gSpriteTemplate_BitterMaliceRing = {
.callback = AnimParticleInVortex
};

//ultra burst
const struct SpriteTemplate gUltraBurstSymbolSpriteTemplate =
{
.tileTag = ANIM_TAG_ULTRA_BURST_SYMBOL,
.paletteTag = ANIM_TAG_ULTRA_BURST_SYMBOL,
.oam = &gOamData_AffineDouble_ObjBlend_32x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gAffineAnims_LusterPurgeCircle,
.callback = AnimSpriteOnMonPos
};

// Z MOVES
//activate
const struct SpriteTemplate gZMoveSymbolSpriteTemplate =
Expand Down
2 changes: 2 additions & 0 deletions src/battle_controller_opponent.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,8 @@ static void OpponentHandleChooseMove(u32 battler)
QueueZMove(battler, chosenMove);
if (CanMegaEvolve(battler)) // If opponent can mega evolve, do it.
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8));
else if (CanUltraBurst(gActiveBattler))
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (RET_ULTRA_BURST) | (gBattlerTarget << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8));
}
Expand Down
23 changes: 22 additions & 1 deletion src/battle_controller_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@ static void HandleInputChooseTarget(u32 battler)
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget;
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->burst.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8));
EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX);
Expand Down Expand Up @@ -594,9 +596,11 @@ static void HandleInputShowEntireFieldTargets(u32 battler)
HideAllTargets();
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->burst.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8));
HideMegaTriggerSprite();
HideTriggerSprites();
PlayerBufferExecCompleted(battler);
}
else if (JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59)
Expand All @@ -622,6 +626,8 @@ static void HandleInputShowTargets(u32 battler)
HideShownTargets(battler);
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->burst.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8));
HideTriggerSprites();
Expand Down Expand Up @@ -737,6 +743,8 @@ static void HandleInputChooseMove(u32 battler)
default:
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->burst.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8));
HideTriggerSprites();
Expand Down Expand Up @@ -773,6 +781,7 @@ static void HandleInputChooseMove(u32 battler)
else
{
gBattleStruct->mega.playerSelect = FALSE;
gBattleStruct->burst.playerSelect = FALSE;
gBattleStruct->zmove.viable = FALSE;
BtlController_EmitTwoReturnValues(BUFFER_B, 10, 0xFFFF);
HideTriggerSprites();
Expand Down Expand Up @@ -857,6 +866,12 @@ static void HandleInputChooseMove(u32 battler)
ChangeMegaTriggerSprite(gBattleStruct->mega.triggerSpriteId, gBattleStruct->mega.playerSelect);
PlaySE(SE_SELECT);
}
else if (CanUltraBurst(gActiveBattler))
{
gBattleStruct->burst.playerSelect ^= 1;
ChangeBurstTriggerSprite(gBattleStruct->burst.triggerSpriteId, gBattleStruct->burst.playerSelect);
PlaySE(SE_SELECT);
}
else if (gBattleStruct->zmove.viable)
{
// show z move name / info
Expand All @@ -873,6 +888,7 @@ static void HandleInputChooseMove(u32 battler)
static void ReloadMoveNames(u32 battler)
{
gBattleStruct->mega.playerSelect = FALSE;
gBattleStruct->burst.playerSelect = FALSE;
gBattleStruct->zmove.viewing = FALSE;
MoveSelectionDestroyCursorAt(battler);
MoveSelectionDisplayMoveNames(battler);
Expand Down Expand Up @@ -1954,10 +1970,15 @@ static void PlayerHandleChooseMove(u32 battler)

InitMoveSelectionsVarsAndStrings(battler);
gBattleStruct->mega.playerSelect = FALSE;
gBattleStruct->burst.playerSelect = FALSE;
if (!IsMegaTriggerSpriteActive())
gBattleStruct->mega.triggerSpriteId = 0xFF;
if (CanMegaEvolve(battler))
CreateMegaTriggerSprite(battler, 0);
if (!IsBurstTriggerSpriteActive())
gBattleStruct->burst.triggerSpriteId = 0xFF;
if (CanUltraBurst(battler))
CreateBurstTriggerSprite(battler, 0);
if (!IsZMoveTriggerSpriteActive())
gBattleStruct->zmove.triggerSpriteId = 0xFF;

Expand Down
2 changes: 2 additions & 0 deletions src/battle_controller_player_partner.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ static void PlayerPartnerHandleChooseMove(u32 battler)
// If partner can mega evolve, do it.
if (CanMegaEvolve(battler))
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8));
else if (CanUltraBurst(battler))
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (RET_ULTRA_BURST) | (gBattlerTarget << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8));
}
Expand Down
Loading

0 comments on commit deb2055

Please sign in to comment.