mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
Implement Ultra Burst (#3221)
This commit is contained in:
commit
deb20552cd
@ -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
|
||||
|
@ -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::
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
BIN
graphics/battle_interface/burst_trigger.png
Normal file
BIN
graphics/battle_interface/burst_trigger.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 314 B |
@ -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;
|
||||
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
@ -129,6 +130,7 @@ struct ChooseMoveStruct
|
||||
u8 monType2;
|
||||
u8 monType3;
|
||||
struct MegaEvolutionData mega;
|
||||
struct UltraBurstData burst;
|
||||
struct ZMoveData zmove;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
@ -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);
|
||||
|
@ -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[];
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 =
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
@ -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)
|
||||
@ -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();
|
||||
@ -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();
|
||||
@ -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();
|
||||
@ -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
|
||||
@ -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);
|
||||
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -194,6 +194,7 @@ static void SpriteCB_StatusSummaryBalls_Exit(struct Sprite *);
|
||||
static void SpriteCB_StatusSummaryBalls_OnSwitchout(struct Sprite *);
|
||||
|
||||
static void SpriteCb_MegaTrigger(struct Sprite *);
|
||||
static void SpriteCb_BurstTrigger(struct Sprite *);
|
||||
static void MegaIndicator_SetVisibilities(u32 healthboxId, bool32 invisible);
|
||||
static void MegaIndicator_UpdateLevel(u32 healthboxId, u32 level);
|
||||
static void MegaIndicator_CreateSprite(u32 battlerId, u32 healthboxSpriteId);
|
||||
@ -676,6 +677,64 @@ static const struct SpriteTemplate sSpriteTemplate_MegaTrigger =
|
||||
.callback = SpriteCb_MegaTrigger
|
||||
};
|
||||
|
||||
static const u8 ALIGNED(4) sBurstTriggerGfx[] = INCBIN_U8("graphics/battle_interface/burst_trigger.4bpp");
|
||||
static const u16 sBurstTriggerPal[] = INCBIN_U16("graphics/battle_interface/burst_trigger.gbapal");
|
||||
|
||||
static const struct SpriteSheet sSpriteSheet_BurstTrigger =
|
||||
{
|
||||
sBurstTriggerGfx, sizeof(sBurstTriggerGfx), TAG_BURST_TRIGGER_TILE
|
||||
};
|
||||
static const struct SpritePalette sSpritePalette_BurstTrigger =
|
||||
{
|
||||
sBurstTriggerPal, TAG_BURST_TRIGGER_PAL
|
||||
};
|
||||
|
||||
static const struct OamData sOamData_BurstTrigger =
|
||||
{
|
||||
.y = 0,
|
||||
.affineMode = 0,
|
||||
.objMode = 0,
|
||||
.mosaic = 0,
|
||||
.bpp = 0,
|
||||
.shape = ST_OAM_SQUARE,
|
||||
.x = 0,
|
||||
.matrixNum = 0,
|
||||
.size = 2,
|
||||
.tileNum = 0,
|
||||
.priority = 1,
|
||||
.paletteNum = 0,
|
||||
.affineParam = 0,
|
||||
};
|
||||
|
||||
static const union AnimCmd sSpriteAnim_BurstTriggerOff[] =
|
||||
{
|
||||
ANIMCMD_FRAME(0, 0),
|
||||
ANIMCMD_END
|
||||
};
|
||||
|
||||
static const union AnimCmd sSpriteAnim_BurstTriggerOn[] =
|
||||
{
|
||||
ANIMCMD_FRAME(16, 0),
|
||||
ANIMCMD_END
|
||||
};
|
||||
|
||||
static const union AnimCmd *const sSpriteAnimTable_BurstTrigger[] =
|
||||
{
|
||||
sSpriteAnim_BurstTriggerOff,
|
||||
sSpriteAnim_BurstTriggerOn,
|
||||
};
|
||||
|
||||
static const struct SpriteTemplate sSpriteTemplate_BurstTrigger =
|
||||
{
|
||||
.tileTag = TAG_BURST_TRIGGER_TILE,
|
||||
.paletteTag = TAG_BURST_TRIGGER_PAL,
|
||||
.oam = &sOamData_BurstTrigger,
|
||||
.anims = sSpriteAnimTable_BurstTrigger,
|
||||
.images = NULL,
|
||||
.affineAnims = gDummySpriteAffineAnimTable,
|
||||
.callback = SpriteCb_BurstTrigger
|
||||
};
|
||||
|
||||
// Because the healthbox is too large to fit into one sprite, it is divided into two sprites.
|
||||
// healthboxLeft or healthboxMain is the left part that is used as the 'main' sprite.
|
||||
// healthboxRight or healthboxOther is the right part of the healthbox.
|
||||
@ -1418,6 +1477,7 @@ void HideMegaTriggerSprite(void)
|
||||
void HideTriggerSprites(void)
|
||||
{
|
||||
HideMegaTriggerSprite();
|
||||
HideBurstTriggerSprite();
|
||||
HideZMoveTriggerSprite();
|
||||
}
|
||||
|
||||
@ -1433,6 +1493,128 @@ void DestroyMegaTriggerSprite(void)
|
||||
#undef tBattler
|
||||
#undef tHide
|
||||
|
||||
// Ultra Burst Trigger icon functions.
|
||||
void ChangeBurstTriggerSprite(u8 spriteId, u8 animId)
|
||||
{
|
||||
StartSpriteAnim(&gSprites[spriteId], animId);
|
||||
}
|
||||
|
||||
#define SINGLES_BURST_TRIGGER_POS_X_OPTIMAL (30)
|
||||
#define SINGLES_BURST_TRIGGER_POS_X_PRIORITY (31)
|
||||
#define SINGLES_BURST_TRIGGER_POS_X_SLIDE (15)
|
||||
#define SINGLES_BURST_TRIGGER_POS_Y_DIFF (-11)
|
||||
|
||||
#define DOUBLES_BURST_TRIGGER_POS_X_OPTIMAL (30)
|
||||
#define DOUBLES_BURST_TRIGGER_POS_X_PRIORITY (31)
|
||||
#define DOUBLES_BURST_TRIGGER_POS_X_SLIDE (15)
|
||||
#define DOUBLES_BURST_TRIGGER_POS_Y_DIFF (-4)
|
||||
|
||||
#define tBattler data[0]
|
||||
#define tHide data[1]
|
||||
|
||||
void CreateBurstTriggerSprite(u8 battlerId, u8 palId)
|
||||
{
|
||||
LoadSpritePalette(&sSpritePalette_BurstTrigger);
|
||||
if (GetSpriteTileStartByTag(TAG_BURST_TRIGGER_TILE) == 0xFFFF)
|
||||
LoadSpriteSheet(&sSpriteSheet_BurstTrigger);
|
||||
if (gBattleStruct->burst.triggerSpriteId == 0xFF)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
gBattleStruct->burst.triggerSpriteId = CreateSprite(&sSpriteTemplate_BurstTrigger,
|
||||
gSprites[gHealthboxSpriteIds[battlerId]].x - DOUBLES_BURST_TRIGGER_POS_X_SLIDE,
|
||||
gSprites[gHealthboxSpriteIds[battlerId]].y - DOUBLES_BURST_TRIGGER_POS_Y_DIFF, 0);
|
||||
else
|
||||
gBattleStruct->burst.triggerSpriteId = CreateSprite(&sSpriteTemplate_BurstTrigger,
|
||||
gSprites[gHealthboxSpriteIds[battlerId]].x - SINGLES_BURST_TRIGGER_POS_X_SLIDE,
|
||||
gSprites[gHealthboxSpriteIds[battlerId]].y - SINGLES_BURST_TRIGGER_POS_Y_DIFF, 0);
|
||||
}
|
||||
gSprites[gBattleStruct->burst.triggerSpriteId].tBattler = battlerId;
|
||||
gSprites[gBattleStruct->burst.triggerSpriteId].tHide = FALSE;
|
||||
|
||||
ChangeBurstTriggerSprite(gBattleStruct->burst.triggerSpriteId, palId);
|
||||
}
|
||||
|
||||
static void SpriteCb_BurstTrigger(struct Sprite *sprite)
|
||||
{
|
||||
s32 xSlide, xPriority, xOptimal;
|
||||
s32 yDiff;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
{
|
||||
xSlide = DOUBLES_BURST_TRIGGER_POS_X_SLIDE;
|
||||
xPriority = DOUBLES_BURST_TRIGGER_POS_X_PRIORITY;
|
||||
xOptimal = DOUBLES_BURST_TRIGGER_POS_X_OPTIMAL;
|
||||
yDiff = DOUBLES_BURST_TRIGGER_POS_Y_DIFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
xSlide = SINGLES_BURST_TRIGGER_POS_X_SLIDE;
|
||||
xPriority = SINGLES_BURST_TRIGGER_POS_X_PRIORITY;
|
||||
xOptimal = SINGLES_BURST_TRIGGER_POS_X_OPTIMAL;
|
||||
yDiff = SINGLES_BURST_TRIGGER_POS_Y_DIFF;
|
||||
}
|
||||
|
||||
if (sprite->tHide)
|
||||
{
|
||||
if (sprite->x != gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xSlide)
|
||||
sprite->x++;
|
||||
|
||||
if (sprite->x >= gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xPriority)
|
||||
sprite->oam.priority = 2;
|
||||
else
|
||||
sprite->oam.priority = 1;
|
||||
|
||||
sprite->y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y - yDiff;
|
||||
sprite->y2 = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y2 - yDiff;
|
||||
if (sprite->x == gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xSlide)
|
||||
DestroyBurstTriggerSprite();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sprite->x != gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xOptimal)
|
||||
sprite->x--;
|
||||
|
||||
if (sprite->x >= gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xPriority)
|
||||
sprite->oam.priority = 2;
|
||||
else
|
||||
sprite->oam.priority = 1;
|
||||
|
||||
sprite->y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y - yDiff;
|
||||
sprite->y2 = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y2 - yDiff;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 IsBurstTriggerSpriteActive(void)
|
||||
{
|
||||
if (GetSpriteTileStartByTag(TAG_BURST_TRIGGER_TILE) == 0xFFFF)
|
||||
return FALSE;
|
||||
else if (IndexOfSpritePaletteTag(TAG_BURST_TRIGGER_PAL) != 0xFF)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void HideBurstTriggerSprite(void)
|
||||
{
|
||||
if (gBattleStruct->burst.triggerSpriteId >= MAX_SPRITES)
|
||||
return;
|
||||
ChangeBurstTriggerSprite(gBattleStruct->burst.triggerSpriteId, 0);
|
||||
gSprites[gBattleStruct->burst.triggerSpriteId].tHide = TRUE;
|
||||
}
|
||||
|
||||
void DestroyBurstTriggerSprite(void)
|
||||
{
|
||||
FreeSpritePaletteByTag(TAG_BURST_TRIGGER_PAL);
|
||||
FreeSpriteTilesByTag(TAG_BURST_TRIGGER_TILE);
|
||||
if (gBattleStruct->burst.triggerSpriteId != 0xFF)
|
||||
DestroySprite(&gSprites[gBattleStruct->burst.triggerSpriteId]);
|
||||
gBattleStruct->burst.triggerSpriteId = 0xFF;
|
||||
}
|
||||
|
||||
#undef tBattler
|
||||
#undef tHide
|
||||
|
||||
|
||||
// Code for Mega Evolution (And Alpha/Omega) Trigger icon visible on the battler's healthbox.
|
||||
enum
|
||||
{
|
||||
|
@ -3110,6 +3110,7 @@ static void BattleStartClearSetData(void)
|
||||
gBattleStruct->arenaLostOpponentMons = 0;
|
||||
|
||||
gBattleStruct->mega.triggerSpriteId = 0xFF;
|
||||
gBattleStruct->burst.triggerSpriteId = 0xFF;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||
{
|
||||
@ -4285,6 +4286,7 @@ static void HandleTurnActionSelectionState(void)
|
||||
}
|
||||
|
||||
gBattleStruct->mega.toEvolve &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))]);
|
||||
gBattleStruct->burst.toBurst &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))]);
|
||||
gBattleStruct->zmove.toBeUsed[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))] = MOVE_NONE;
|
||||
BtlController_EmitEndBounceEffect(BUFFER_A);
|
||||
MarkBattlerForControllerExec(gActiveBattler);
|
||||
@ -4371,11 +4373,13 @@ static void HandleTurnActionSelectionState(void)
|
||||
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleResources->bufferB[gActiveBattler][2]);
|
||||
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleResources->bufferB[gActiveBattler][3]);
|
||||
}
|
||||
*(gBattleStruct->chosenMovePositions + gActiveBattler) = gBattleResources->bufferB[gActiveBattler][2] & ~RET_MEGA_EVOLUTION;
|
||||
*(gBattleStruct->chosenMovePositions + gActiveBattler) = gBattleResources->bufferB[gActiveBattler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST);
|
||||
gChosenMoveByBattler[gActiveBattler] = gBattleMons[gActiveBattler].moves[*(gBattleStruct->chosenMovePositions + gActiveBattler)];
|
||||
*(gBattleStruct->moveTarget + gActiveBattler) = gBattleResources->bufferB[gActiveBattler][3];
|
||||
if (gBattleResources->bufferB[gActiveBattler][2] & RET_MEGA_EVOLUTION)
|
||||
gBattleStruct->mega.toEvolve |= gBitTable[gActiveBattler];
|
||||
else if (gBattleResources->bufferB[gActiveBattler][2] & RET_ULTRA_BURST)
|
||||
gBattleStruct->burst.toBurst |= gBitTable[gActiveBattler];
|
||||
gBattleCommunication[gActiveBattler]++;
|
||||
}
|
||||
break;
|
||||
@ -4993,7 +4997,7 @@ static void PopulateArrayWithBattlers(u8 *battlers)
|
||||
|
||||
static bool32 TryDoMegaEvosBeforeMoves(void)
|
||||
{
|
||||
if (!(gHitMarker & HITMARKER_RUN) && gBattleStruct->mega.toEvolve)
|
||||
if (!(gHitMarker & HITMARKER_RUN) && (gBattleStruct->mega.toEvolve || gBattleStruct->burst.toBurst))
|
||||
{
|
||||
u32 i;
|
||||
struct Pokemon *party;
|
||||
@ -5018,6 +5022,18 @@ static bool32 TryDoMegaEvosBeforeMoves(void)
|
||||
BattleScriptExecute(BattleScript_MegaEvolution);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (gBattleStruct->burst.toBurst & gBitTable[megaOrder[i]]
|
||||
&& !(gProtectStructs[megaOrder[i]].noValidMoves))
|
||||
{
|
||||
gActiveBattler = gBattlerAttacker = megaOrder[i];
|
||||
gBattleStruct->burst.toBurst &= ~(gBitTable[gActiveBattler]);
|
||||
gLastUsedItem = gBattleMons[gActiveBattler].item;
|
||||
party = GetBattlerParty(gActiveBattler);
|
||||
mon = &party[gBattlerPartyIndexes[gActiveBattler]];
|
||||
BattleScriptExecute(BattleScript_UltraBurst);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -800,6 +800,9 @@ static const u8 sText_ItemRestoredSpeciesPP[] = _("{B_BUFF1} had its\nPP restore
|
||||
static const u8 sText_AtkTrappedDef[] = _("{B_ATK_NAME_WITH_PREFIX} trapped\nthe {B_DEF_NAME_WITH_PREFIX}!");
|
||||
static const u8 sText_MirrorHerbCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used its {B_LAST_ITEM}\nto mirror its opponent's stat changes!");
|
||||
static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!");
|
||||
static const u8 sText_UltraBurstReacting[] = _("Bright light is about to\nburst out of {B_ATK_NAME_WITH_PREFIX}!");
|
||||
static const u8 sText_UltraBurstCompleted[] = _("{B_ATK_NAME_WITH_PREFIX} regained its\ntrue power through Ultra Burst!");
|
||||
|
||||
|
||||
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
||||
{
|
||||
@ -1456,6 +1459,8 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
||||
[STRINGID_PKMNFROSTBITEHEALED - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealed,
|
||||
[STRINGID_PKMNFROSTBITEHEALED2 - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealed2,
|
||||
[STRINGID_PKMNFROSTBITEHEALEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealedBy,
|
||||
[STRINGID_ULTRABURSTREACTING - BATTLESTRINGS_TABLE_START] = sText_UltraBurstReacting,
|
||||
[STRINGID_ULTRABURSTCOMPLETED - BATTLESTRINGS_TABLE_START] = sText_UltraBurstCompleted,
|
||||
};
|
||||
|
||||
const u16 gTrainerUsedItemStringIds[] =
|
||||
|
@ -4998,7 +4998,8 @@ static void Cmd_playanimation(void)
|
||||
|| animId == B_ANIM_ILLUSION_OFF
|
||||
|| animId == B_ANIM_FORM_CHANGE
|
||||
|| animId == B_ANIM_SUBSTITUTE_FADE
|
||||
|| animId == B_ANIM_PRIMAL_REVERSION)
|
||||
|| animId == B_ANIM_PRIMAL_REVERSION
|
||||
|| animId == B_ANIM_ULTRA_BURST)
|
||||
{
|
||||
BtlController_EmitBattleAnimation(BUFFER_A, animId, *argPtr);
|
||||
MarkBattlerForControllerExec(gActiveBattler);
|
||||
@ -5049,7 +5050,8 @@ static void Cmd_playanimation_var(void)
|
||||
|| *animIdPtr == B_ANIM_ILLUSION_OFF
|
||||
|| *animIdPtr == B_ANIM_FORM_CHANGE
|
||||
|| *animIdPtr == B_ANIM_SUBSTITUTE_FADE
|
||||
|| *animIdPtr == B_ANIM_PRIMAL_REVERSION)
|
||||
|| *animIdPtr == B_ANIM_PRIMAL_REVERSION
|
||||
|| *animIdPtr == B_ANIM_ULTRA_BURST)
|
||||
{
|
||||
BtlController_EmitBattleAnimation(BUFFER_A, *animIdPtr, *argPtr);
|
||||
MarkBattlerForControllerExec(gActiveBattler);
|
||||
@ -8561,7 +8563,7 @@ static bool32 CourtChangeSwapSideStatuses(void)
|
||||
SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp);
|
||||
}
|
||||
|
||||
static void HandleScriptMegaPrimal(u32 caseId, u32 battlerId, bool32 isMega)
|
||||
static void HandleScriptMegaPrimalBurst(u32 caseId, u32 battlerId, u32 type)
|
||||
{
|
||||
struct Pokemon *party = GetBattlerParty(battlerId);
|
||||
struct Pokemon *mon = &party[gBattlerPartyIndexes[battlerId]];
|
||||
@ -8571,13 +8573,15 @@ static void HandleScriptMegaPrimal(u32 caseId, u32 battlerId, bool32 isMega)
|
||||
// Change species.
|
||||
if (caseId == 0)
|
||||
{
|
||||
if (isMega)
|
||||
if (type == HANDLE_TYPE_MEGA_EVOLUTION)
|
||||
{
|
||||
if (!TryBattleFormChange(battlerId, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM))
|
||||
TryBattleFormChange(battlerId, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE);
|
||||
}
|
||||
else
|
||||
else if (type == HANDLE_TYPE_PRIMAL_REVERSION)
|
||||
TryBattleFormChange(battlerId, FORM_CHANGE_BATTLE_PRIMAL_REVERSION);
|
||||
else
|
||||
TryBattleFormChange(battlerId, FORM_CHANGE_BATTLE_ULTRA_BURST);
|
||||
|
||||
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[battlerId].species);
|
||||
|
||||
@ -8590,8 +8594,10 @@ static void HandleScriptMegaPrimal(u32 caseId, u32 battlerId, bool32 isMega)
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[battlerId], mon, HEALTHBOX_ALL);
|
||||
if (side == B_SIDE_OPPONENT)
|
||||
SetBattlerShadowSpriteCallback(battlerId, gBattleMons[battlerId].species);
|
||||
if (isMega)
|
||||
if (type == HANDLE_TYPE_MEGA_EVOLUTION)
|
||||
gBattleStruct->mega.alreadyEvolved[position] = TRUE;
|
||||
if (type == HANDLE_TYPE_ULTRA_BURST)
|
||||
gBattleStruct->burst.alreadyBursted[position] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9621,14 +9627,21 @@ static void Cmd_various(void)
|
||||
case VARIOUS_HANDLE_MEGA_EVO:
|
||||
{
|
||||
VARIOUS_ARGS(u8 case_);
|
||||
HandleScriptMegaPrimal(cmd->case_, gActiveBattler, TRUE);
|
||||
HandleScriptMegaPrimalBurst(cmd->case_, gActiveBattler, HANDLE_TYPE_MEGA_EVOLUTION);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
return;
|
||||
}
|
||||
case VARIOUS_HANDLE_PRIMAL_REVERSION:
|
||||
{
|
||||
VARIOUS_ARGS(u8 case_);
|
||||
HandleScriptMegaPrimal(cmd->case_, gActiveBattler, FALSE);
|
||||
HandleScriptMegaPrimalBurst(cmd->case_, gActiveBattler, HANDLE_TYPE_PRIMAL_REVERSION);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
return;
|
||||
}
|
||||
case VARIOUS_HANDLE_ULTRA_BURST:
|
||||
{
|
||||
VARIOUS_ARGS(u8 case_);
|
||||
HandleScriptMegaPrimalBurst(cmd->case_, gActiveBattler, HANDLE_TYPE_ULTRA_BURST);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
return;
|
||||
}
|
||||
|
@ -1612,7 +1612,7 @@ static bool32 IsBelchPreventingMove(u32 battler, u32 move)
|
||||
u8 TrySetCantSelectMoveBattleScript(void)
|
||||
{
|
||||
u32 limitations = 0;
|
||||
u8 moveId = gBattleResources->bufferB[gActiveBattler][2] & ~RET_MEGA_EVOLUTION;
|
||||
u8 moveId = gBattleResources->bufferB[gActiveBattler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST);
|
||||
u32 move = gBattleMons[gActiveBattler].moves[moveId];
|
||||
u32 holdEffect = GetBattlerHoldEffect(gActiveBattler, TRUE);
|
||||
u16 *choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
|
||||
@ -10092,6 +10092,7 @@ bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId)
|
||||
{
|
||||
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM:
|
||||
case FORM_CHANGE_BATTLE_PRIMAL_REVERSION:
|
||||
case FORM_CHANGE_BATTLE_ULTRA_BURST:
|
||||
case FORM_CHANGE_ITEM_HOLD:
|
||||
if (formChanges[i].param1 == heldItemId)
|
||||
return TRUE;
|
||||
@ -10166,6 +10167,61 @@ bool32 CanMegaEvolve(u8 battlerId)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanUltraBurst(u8 battlerId)
|
||||
{
|
||||
u32 itemId, holdEffect, species;
|
||||
struct Pokemon *mon;
|
||||
u8 battlerPosition = GetBattlerPosition(battlerId);
|
||||
u8 partnerPosition = GetBattlerPosition(BATTLE_PARTNER(battlerId));
|
||||
|
||||
// Check if Player has a Z Ring
|
||||
if ((GetBattlerPosition(battlerId) == B_POSITION_PLAYER_LEFT || (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && GetBattlerPosition(battlerId) == B_POSITION_PLAYER_RIGHT))
|
||||
&& !CheckBagHasItem(ITEM_Z_POWER_RING, 1))
|
||||
return FALSE;
|
||||
|
||||
// Check if trainer already ultra bursted a pokemon.
|
||||
if (gBattleStruct->burst.alreadyBursted[battlerPosition])
|
||||
return FALSE;
|
||||
|
||||
// Cannot use z move and ultra burst on same turn
|
||||
if (gBattleStruct->zmove.toBeUsed[battlerId])
|
||||
return FALSE;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
|
||||
&& IsPartnerMonFromSameTrainer(battlerId)
|
||||
&& (gBattleStruct->burst.alreadyBursted[partnerPosition] || (gBattleStruct->burst.toBurst & gBitTable[BATTLE_PARTNER(battlerId)])))
|
||||
return FALSE;
|
||||
|
||||
// Check if mon is currently held by Sky Drop
|
||||
if (gStatuses3[battlerId] & STATUS3_SKY_DROPPED)
|
||||
return FALSE;
|
||||
|
||||
// Gets mon data.
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
|
||||
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
|
||||
else
|
||||
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
|
||||
|
||||
species = GetMonData(mon, MON_DATA_SPECIES);
|
||||
itemId = GetMonData(mon, MON_DATA_HELD_ITEM);
|
||||
|
||||
// Check if there is an entry in the evolution table for Ultra Burst.
|
||||
if (GetBattleFormChangeTargetSpecies(battlerId, FORM_CHANGE_BATTLE_ULTRA_BURST) != SPECIES_NONE)
|
||||
{
|
||||
if (itemId == ITEM_ENIGMA_BERRY_E_READER)
|
||||
holdEffect = gEnigmaBerries[battlerId].holdEffect;
|
||||
else
|
||||
holdEffect = ItemId_GetHoldEffect(itemId);
|
||||
|
||||
// Can Ultra Burst via Z Crystal.
|
||||
if (holdEffect == HOLD_EFFECT_Z_CRYSTAL)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// No checks passed, the mon CAN'T ultra burst.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsBattlerMegaEvolved(u8 battlerId)
|
||||
{
|
||||
// While Transform does copy stats and visuals, it shouldn't be counted as true Mega Evolution.
|
||||
@ -10182,6 +10238,14 @@ bool32 IsBattlerPrimalReverted(u8 battlerId)
|
||||
return (gSpeciesInfo[gBattleMons[battlerId].species].flags & SPECIES_FLAG_PRIMAL_REVERSION);
|
||||
}
|
||||
|
||||
bool32 IsBattlerUltraBursted(u8 battlerId)
|
||||
{
|
||||
// While Transform does copy stats and visuals, it shouldn't be counted as true Ultra Burst.
|
||||
if (gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED)
|
||||
return FALSE;
|
||||
return (gSpeciesInfo[gBattleMons[battlerId].species].flags & SPECIES_FLAG_ULTRA_BURST);
|
||||
}
|
||||
|
||||
// Returns SPECIES_NONE if no form change is possible
|
||||
u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method)
|
||||
{
|
||||
@ -10205,6 +10269,7 @@ u16 GetBattleFormChangeTargetSpecies(u8 battlerId, u16 method)
|
||||
{
|
||||
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM:
|
||||
case FORM_CHANGE_BATTLE_PRIMAL_REVERSION:
|
||||
case FORM_CHANGE_BATTLE_ULTRA_BURST:
|
||||
if (heldItem == formChanges[i].param1)
|
||||
targetSpecies = formChanges[i].targetSpecies;
|
||||
break;
|
||||
@ -10275,8 +10340,8 @@ bool32 CanBattlerFormChange(u8 battlerId, u16 method)
|
||||
if (gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED
|
||||
&& B_TRANSFORM_FORM_CHANGES >= GEN_5)
|
||||
return FALSE;
|
||||
// Mega Evolved Pokémon should always revert to normal upon fainting or ending the battle.
|
||||
if (IsBattlerMegaEvolved(battlerId) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
|
||||
// Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle.
|
||||
if ((IsBattlerMegaEvolved(battlerId) || IsBattlerUltraBursted(battlerId)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
|
||||
return TRUE;
|
||||
else if (IsBattlerPrimalReverted(battlerId) && (method == FORM_CHANGE_END_BATTLE))
|
||||
return TRUE;
|
||||
@ -10312,8 +10377,8 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method)
|
||||
{
|
||||
bool8 restoreSpecies = FALSE;
|
||||
|
||||
// Mega Evolved Pokémon should always revert to normal upon fainting or ending the battle, so no need to add it to the form change tables.
|
||||
if (IsBattlerMegaEvolved(battlerId) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
|
||||
// Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle, so no need to add it to the form change tables.
|
||||
if ((IsBattlerMegaEvolved(battlerId) || IsBattlerUltraBursted(battlerId)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
|
||||
restoreSpecies = TRUE;
|
||||
|
||||
// Unlike Megas, Primal Reversion isn't canceled on fainting.
|
||||
|
@ -210,6 +210,8 @@ const struct FormChange *const gFormChangeTablePointers[NUM_SPECIES] =
|
||||
[SPECIES_MINIOR_CORE_VIOLET] = sMiniorVioletFormChangeTable,
|
||||
[SPECIES_MINIOR_METEOR_YELLOW] = sMiniorYellowFormChangeTable,
|
||||
[SPECIES_MINIOR_CORE_YELLOW] = sMiniorYellowFormChangeTable,
|
||||
[SPECIES_NECROZMA_DUSK_MANE] = sNecrozmaDuskManeFormChangeTable,
|
||||
[SPECIES_NECROZMA_DAWN_WINGS] = sNecrozmaDawnWingsFormChangeTable,
|
||||
#endif
|
||||
#if P_GEN_8_POKEMON == TRUE
|
||||
[SPECIES_CRAMORANT] = sCramorantFormChangeTable,
|
||||
|
@ -548,6 +548,14 @@ static const struct FormChange sMiniorYellowFormChangeTable[] = {
|
||||
{FORM_CHANGE_END_BATTLE, SPECIES_MINIOR_CORE_YELLOW},
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
static const struct FormChange sNecrozmaDuskManeFormChangeTable[] = {
|
||||
{FORM_CHANGE_BATTLE_ULTRA_BURST, SPECIES_NECROZMA_ULTRA, ITEM_ULTRANECROZIUM_Z},
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
static const struct FormChange sNecrozmaDawnWingsFormChangeTable[] = {
|
||||
{FORM_CHANGE_BATTLE_ULTRA_BURST, SPECIES_NECROZMA_ULTRA, ITEM_ULTRANECROZIUM_Z},
|
||||
{FORM_CHANGE_TERMINATOR},
|
||||
};
|
||||
#endif
|
||||
|
||||
#if P_GEN_8_POKEMON == TRUE
|
||||
|
@ -24484,7 +24484,7 @@ const struct SpeciesInfo gSpeciesInfo[] =
|
||||
.abilities = {ABILITY_NEUROFORCE, ABILITY_NONE},
|
||||
.bodyColor = BODY_COLOR_YELLOW,
|
||||
.noFlip = TRUE,
|
||||
.flags = SPECIES_FLAG_LEGENDARY,
|
||||
.flags = SPECIES_FLAG_LEGENDARY | SPECIES_FLAG_ULTRA_BURST,
|
||||
},
|
||||
|
||||
[SPECIES_MAGEARNA_ORIGINAL_COLOR] = MAGEARNA_SPECIES_INFO(BODY_COLOR_RED),
|
||||
|
127
test/battle/form_change/ultra_burst.c
Normal file
127
test/battle/form_change/ultra_burst.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Dusk Mane Necrozma can Ultra Burst holding Ultranecrozium Z")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, ultraBurst: TRUE); }
|
||||
} SCENE {
|
||||
MESSAGE("Bright light is about to burst out of Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, player);
|
||||
MESSAGE("Necrozma regained its true power through Ultra Burst!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, SPECIES_NECROZMA_ULTRA);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ultra Burst's order is determined by Speed - opponent faster")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); Speed(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(3); }
|
||||
OPPONENT(SPECIES_NECROZMA_DAWN_WINGS) { Item(ITEM_ULTRANECROZIUM_Z); Speed(3); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_CELEBRATE, ultraBurst: TRUE); MOVE(playerLeft, MOVE_CELEBRATE, ultraBurst: TRUE); }
|
||||
} SCENE {
|
||||
MESSAGE("Bright light is about to burst out of Foe Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, opponentLeft);
|
||||
MESSAGE("Foe Necrozma regained its true power through Ultra Burst!");
|
||||
MESSAGE("Bright light is about to burst out of Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, playerLeft);
|
||||
MESSAGE("Necrozma regained its true power through Ultra Burst!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ultra Burst's order is determined by Speed - player faster")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); Speed(5); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(3); }
|
||||
OPPONENT(SPECIES_NECROZMA_DAWN_WINGS) { Item(ITEM_ULTRANECROZIUM_Z); Speed(2); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_CELEBRATE, ultraBurst: TRUE); MOVE(playerLeft, MOVE_CELEBRATE, ultraBurst: TRUE); }
|
||||
} SCENE {
|
||||
MESSAGE("Bright light is about to burst out of Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, playerLeft);
|
||||
MESSAGE("Necrozma regained its true power through Ultra Burst!");
|
||||
MESSAGE("Bright light is about to burst out of Foe Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, opponentLeft);
|
||||
MESSAGE("Foe Necrozma regained its true power through Ultra Burst!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ultra Burst affects turn order")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
ASSUME(B_MEGA_EVO_TURN_ORDER);
|
||||
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); Speed(105); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(106); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, ultraBurst: TRUE); }
|
||||
} SCENE {
|
||||
MESSAGE("Necrozma used Celebrate!");
|
||||
MESSAGE("Foe Wobbuffet used Celebrate!");
|
||||
} THEN {
|
||||
ASSUME(player->speed == 263);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Ultra Burst happens after switching, but before Focus Punch-like Moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
ASSUME(gBattleMoves[MOVE_FOCUS_PUNCH].effect == EFFECT_FOCUS_PUNCH);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { SWITCH(opponentRight, 2); MOVE(playerRight, MOVE_FOCUS_PUNCH, ultraBurst: TRUE, target: opponentLeft); MOVE(playerLeft, MOVE_FOCUS_PUNCH, target: opponentLeft); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
MESSAGE("2 withdrew Wobbuffet!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
|
||||
MESSAGE("Bright light is about to burst out of Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, playerRight);
|
||||
MESSAGE("Necrozma regained its true power through Ultra Burst!");
|
||||
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FOCUS_PUNCH_SETUP, playerRight);
|
||||
MESSAGE("Necrozma is tightening its focus!");
|
||||
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FOCUS_PUNCH_SETUP, playerLeft);
|
||||
MESSAGE("Wobbuffet is tightening its focus!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Ultra Burst and Mega Evolution can happen on the same turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(P_GEN_7_POKEMON == TRUE);
|
||||
PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); Speed(3); }
|
||||
OPPONENT(SPECIES_GARDEVOIR) { Item(ITEM_GARDEVOIRITE); Speed(2); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CELEBRATE, ultraBurst: TRUE); MOVE(opponent, MOVE_CELEBRATE, megaEvolve: TRUE); }
|
||||
} SCENE {
|
||||
MESSAGE("Bright light is about to burst out of Necrozma!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ULTRA_BURST, player);
|
||||
MESSAGE("Necrozma regained its true power through Ultra Burst!");
|
||||
|
||||
MESSAGE("Foe Gardevoir's Gardevoirite is reacting to 's Mega Ring!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
MESSAGE("Foe Gardevoir has Mega Evolved into Mega Gardevoir!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->species, SPECIES_NECROZMA_ULTRA);
|
||||
EXPECT_EQ(opponent->species, SPECIES_GARDEVOIR_MEGA);
|
||||
}
|
||||
}
|
@ -1483,6 +1483,9 @@ void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx)
|
||||
if (ctx.explicitMegaEvolve && ctx.megaEvolve)
|
||||
moveSlot |= RET_MEGA_EVOLUTION;
|
||||
|
||||
if (ctx.explicitUltraBurst && ctx.ultraBurst)
|
||||
moveSlot |= RET_ULTRA_BURST;
|
||||
|
||||
if (ctx.explicitTarget)
|
||||
{
|
||||
target = ctx.target - gBattleMons;
|
||||
|
Loading…
Reference in New Issue
Block a user