added basic Dynamax-in-battle

This commit is contained in:
AgustinGDLV 2023-03-10 10:20:27 -08:00
parent 6083a22945
commit 76073fab52
15 changed files with 153 additions and 8 deletions

View file

@ -2246,6 +2246,10 @@
various 0, VARIOUS_TRY_RECYCLE_BERRY
.4byte \ptr
.endm
.macro applydynamaxhpmultiplier
various 0, VARIOUS_APPLY_DYNAMAX_HP_MULTIPLIER
.endm
@ Tries to increase or decrease a battler's stat's stat stage by a specified amount. If impossible, jumps to \script.
.macro modifybattlerstatstage battler:req, stat:req, mode:req, amount:req, script:req, animation:req, customString

View file

@ -999,6 +999,7 @@ gBattleAnims_General::
.4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP
.4byte General_ZMoveActivate @ B_ANIM_ZMOVE_ACTIVATE
.4byte General_AffectionHangedOn @ B_ANIM_AFFECTION_HANGED_ON
.4byte General_DynamaxGrowth @ B_ANIM_DYNAMAX_GROWTH
.4byte General_SetWeather @ B_ANIM_MAX_SET_WEATHER
.align 2
@ -30943,3 +30944,11 @@ Move_G_MAX_RAPID_FLOW:
launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1
waitforvisualfinish
end
@@@ DYNAMAX AND MAX RAIDS
General_DynamaxGrowth:: @ PORTED FROM CFRU
createvisualtask SoundTask_PlayCryWithEcho, 2, ANIM_ATTACKER, 2
delay 8
launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x0
waitforvisualfinish
end

View file

@ -10588,7 +10588,24 @@ BattleScript_RecycleBerriesAlliesEnd:
restoretarget
goto BattleScript_MoveEnd
@@ End Max Moves
@@@ END MAX MOVES @@@
BattleScript_DynamaxBegins::
printstring STRINGID_EMPTYSTRING3
playanimation BS_SCRIPTING, B_ANIM_SLIDE_OFFSCREEN
waitanimation
returntoball BS_SCRIPTING
@applydynamaxhpmultiplier
switchinanim BS_SCRIPTING, TRUE
playanimation BS_SCRIPTING, B_ANIM_DYNAMAX_GROWTH
waitanimation
end
BattleScript_DynamaxEnds::
printstring STRINGID_EMPTYSTRING3
playanimation BS_SCRIPTING, B_ANIM_FORM_CHANGE
waitanimation
end2
BattleScript_PokemonCantUseTheMove::
attackstring

View file

@ -524,6 +524,10 @@ struct ZMoveData
struct DynamaxData
{
bool8 playerSelect;
bool8 toDynamax[MAX_BATTLERS_COUNT];
bool8 alreadyDynamaxed[NUM_BATTLE_SIDES];
bool8 dynamaxed[MAX_BATTLERS_COUNT];
u8 dynamaxTurns[MAX_BATTLERS_COUNT];
u8 usingMaxMove[MAX_BATTLERS_COUNT];
u8 activeSplit;

View file

@ -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_DYNAMAX 0x40
struct UnusedControllerStruct
{

View file

@ -1,6 +1,8 @@
#ifndef GUARD_BATTLE_DYNAMAX_H
#define GUARD_BATTLE_DYNAMAX_H
#define DYNAMAX_TURNS 3
enum MaxMoveEffect
{
MAX_EFFECT_NONE,
@ -55,6 +57,9 @@ enum MaxMoveEffect
};
bool8 IsDynamaxed(u16 battlerId);
bool8 CanDynamax(u16 battlerId);
void PrepareBattlerForDynamax(u16 battlerId);
void UndoDynamax(u16 battlerId);
bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove);
u16 GetMaxMove(u16 battlerId, u16 baseMove);
u8 GetMaxMovePower(u16 move);

View file

@ -486,4 +486,8 @@ extern const u8 BattleScript_EffectHealOneSixthAllies[];
extern const u8 BattleScript_EffectCureStatusAllies[];
extern const u8 BattleScript_EffectRecycleBerriesAllies[];
// dynamax and max raids
extern const u8 BattleScript_DynamaxBegins[];
extern const u8 BattleScript_DynamaxEnds[];
#endif // GUARD_BATTLE_SCRIPTS_H

View file

@ -544,7 +544,8 @@
#define B_ANIM_SHELL_TRAP_SETUP 34
#define B_ANIM_ZMOVE_ACTIVATE 35 // Using Z Moves
#define B_ANIM_AFFECTION_HANGED_ON 36
#define B_ANIM_MAX_SET_WEATHER 37
#define B_ANIM_DYNAMAX_GROWTH 37
#define B_ANIM_MAX_SET_WEATHER 38
// special animations table (gBattleAnims_Special)
#define B_ANIM_LVL_UP 0

View file

@ -267,6 +267,7 @@
#define VARIOUS_TRY_SET_STATUS2 175
#define VARIOUS_TRY_HEAL_SIXTH_HP 176
#define VARIOUS_TRY_RECYCLE_BERRY 177
#define VARIOUS_APPLY_DYNAMAX_HP_MULTIPLIER 178
// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0

View file

@ -4188,3 +4188,4 @@ gCryTable_Reverse::
cry_reverse Cry_Unown
cry_reverse Cry_Unown
.endif
@ TODO: Gigantamax Cries

View file

@ -379,6 +379,8 @@ static void HandleInputChooseTarget(void)
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget;
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->dynamax.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8));
EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX);
@ -537,6 +539,8 @@ static void HandleInputShowEntireFieldTargets(void)
HideAllTargets();
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->dynamax.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8));
HideMegaTriggerSprite();
@ -565,6 +569,8 @@ static void HandleInputShowTargets(void)
HideShownTargets();
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->dynamax.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8));
HideTriggerSprites();
@ -680,6 +686,8 @@ static void HandleInputChooseMove(void)
default:
if (gBattleStruct->mega.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_MEGA_EVOLUTION | (gMultiUsePlayerCursor << 8));
else if (gBattleStruct->dynamax.playerSelect)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8));
HideTriggerSprites();
@ -716,6 +724,7 @@ static void HandleInputChooseMove(void)
else
{
gBattleStruct->mega.playerSelect = FALSE;
gBattleStruct->dynamax.playerSelect = FALSE;
gBattleStruct->zmove.viable = FALSE;
BtlController_EmitTwoReturnValues(BUFFER_B, 10, 0xFFFF);
HideTriggerSprites();
@ -810,12 +819,20 @@ static void HandleInputChooseMove(void)
else
ReloadMoveNames();
}
else if (CanDynamax(gActiveBattler))
{
gBattleStruct->dynamax.playerSelect ^= 1;
MoveSelectionDisplayMoveNames();
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
PlaySE(SE_SELECT);
}
}
}
static void ReloadMoveNames(void)
{
gBattleStruct->mega.playerSelect = FALSE;
gBattleStruct->dynamax.playerSelect = FALSE;
gBattleStruct->zmove.viewing = FALSE;
MoveSelectionDestroyCursorAt(0);
MoveSelectionDisplayMoveNames();
@ -1685,7 +1702,8 @@ static void MoveSelectionDisplayMoveNames(void)
for (i = 0; i < MAX_MON_MOVES; i++)
{
MoveSelectionDestroyCursorAt(i);
if (IsDynamaxed(gActiveBattler))
if ((gBattleStruct->dynamax.playerSelect && CanDynamax(gActiveBattler))
|| IsDynamaxed(gActiveBattler))
StringCopy(gDisplayedStringBattle, gMoveNames[GetMaxMove(gActiveBattler, moveInfo->moves[i])]);
else
StringCopy(gDisplayedStringBattle, gMoveNames[moveInfo->moves[i]]);
@ -2867,6 +2885,7 @@ static void PlayerHandleChooseMove(void)
InitMoveSelectionsVarsAndStrings();
gBattleStruct->mega.playerSelect = FALSE;
gBattleStruct->dynamax.playerSelect = FALSE;
if (!IsMegaTriggerSpriteActive())
gBattleStruct->mega.triggerSpriteId = 0xFF;
if (CanMegaEvolve(gActiveBattler))

View file

@ -84,20 +84,52 @@ static const struct GMaxMove sGMaxMoveTable[] =
extern u8 gMaxMovePowers[MOVES_COUNT];
// Returns whether a battler is Dynamaxed.
bool8 IsDynamaxed(u16 battlerId)
{
if (/*IsRaidBoss(battlerId) ||*/ gBattleStruct->dynamax.dynamaxTurns[battlerId] > 0)
u8 side = GetBattlerSide(battlerId);
if (gBattleStruct->dynamax.dynamaxed[battlerId]
/*|| IsRaidBoss(battlerId)*/)
return TRUE;
return FALSE;
}
// Returns whether a battler can Dynamax.
bool8 CanDynamax(u16 battlerId)
{
// TODO: Requires Dynamax Band if not in a Max Raid (as well as special flag).
if (!gBattleStruct->dynamax.alreadyDynamaxed[GetBattlerSide(battlerId)]
&& !gBattleStruct->dynamax.dynamaxed[battlerId]
&& !gBattleStruct->dynamax.dynamaxed[BATTLE_PARTNER(battlerId)]
&& !gBattleStruct->dynamax.toDynamax[BATTLE_PARTNER(battlerId)])
return TRUE;
return FALSE;
}
// Sets flags used for Dynamaxing.
void PrepareBattlerForDynamax(u16 battlerId)
{
u8 side = GetBattlerSide(battlerId);
gBattleStruct->dynamax.alreadyDynamaxed[side] = TRUE;
gBattleStruct->dynamax.dynamaxed[battlerId] = TRUE;
gBattleStruct->dynamax.dynamaxTurns[battlerId] = DYNAMAX_TURNS;
}
void UndoDynamax(u16 battlerId)
{
u8 side = GetBattlerSide(battlerId);
gBattleStruct->dynamax.dynamaxed[battlerId] = FALSE;
gBattleStruct->dynamax.dynamaxTurns[battlerId] = 0; // safety check for switch-in / faint
// TODO: Undo Gigantamax form change.
}
// Returns whether a move should be converted into a Max Move.
bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove)
{
// TODO: Raids
//if (IsRaidBoss(battlerId))
// return !IsRaidBossUsingRegularMove(battlerId, baseMove);
return IsDynamaxed(battlerId);
return IsDynamaxed(battlerId) || gBattleStruct->dynamax.toDynamax[battlerId];
}
static u16 GetTypeBasedMaxMove(u16 battlerId, u16 type)

View file

@ -3169,6 +3169,9 @@ void SwitchInClearSetData(void)
// Reset G-Max Chi Strike boosts.
gBattleStruct->bonusCritStages[gActiveBattler] = 0;
// Reset Dynamax flags.
UndoDynamax(gActiveBattler);
gBattleStruct->overwrittenAbilities[gActiveBattler] = ABILITY_NONE;
Ai_UpdateSwitchInData(gActiveBattler);
@ -3272,6 +3275,7 @@ void FaintClearSetData(void)
UndoFormChange(gBattlerPartyIndexes[gActiveBattler], GET_BATTLER_SIDE(gActiveBattler), FALSE);
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]);
// TODO: UndoDynamax
gBattleStruct->overwrittenAbilities[gActiveBattler] = ABILITY_NONE;
@ -4267,11 +4271,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_DYNAMAX;
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_DYNAMAX)
gBattleStruct->dynamax.toDynamax[gActiveBattler] = TRUE;
if (ShouldUseMaxMove(gActiveBattler, gChosenMoveByBattler[gActiveBattler])) // max move check
{
gBattleStruct->dynamax.moveSlot[gActiveBattler] = gBattleStruct->chosenMovePositions[gActiveBattler];
@ -4888,6 +4894,7 @@ void SpecialStatusesClear(void)
memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses));
}
// TODO: Rename function to denote use for Dynamax, too.
static void CheckMegaEvolutionBeforeTurn(void)
{
if (!(gHitMarker & HITMARKER_RUN))
@ -4896,6 +4903,16 @@ static void CheckMegaEvolutionBeforeTurn(void)
{
gActiveBattler = gBattlerAttacker = gBattleStruct->mega.battlerId;
gBattleStruct->mega.battlerId++;
// Dynamax Check
if (gBattleStruct->dynamax.toDynamax[gActiveBattler])
{
gBattleStruct->dynamax.toDynamax[gActiveBattler] = FALSE;
gBattleScripting.battler = gActiveBattler;
PrepareBattlerForDynamax(gActiveBattler);
BattleScriptExecute(BattleScript_DynamaxBegins);
return;
}
// Mega Evo Check
if (gBattleStruct->mega.toEvolve & gBitTable[gActiveBattler]
&& !(gProtectStructs[gActiveBattler].noValidMoves))
{
@ -5265,6 +5282,7 @@ static void HandleEndTurn_FinishBattle(void)
UndoMegaEvolution(i);
UndoFormChange(i, B_SIDE_PLAYER, FALSE);
DoBurmyFormChange(i);
// TODO: UndoDynamax(i)
}
#if B_RECALCULATE_STATS >= GEN_5
// Recalculate the stats of every party member before the end

View file

@ -11348,6 +11348,23 @@ static void Cmd_various(void)
}
return;
}
case VARIOUS_APPLY_DYNAMAX_HP_MULTIPLIER:
{
VARIOUS_ARGS();
if (gBattleMons[gBattleScripting.battler].species != SPECIES_SHEDINJA)
{
u16 multiplier = UQ_4_12(2.0); // placeholder; TODO: Dynamax level
gBattleMons[gBattleScripting.battler].hp = UQ_4_12_TO_INT((gBattleMons[gBattleScripting.battler].hp * multiplier) + UQ_4_12_ROUND);
gBattleMons[gBattleScripting.battler].maxHP = UQ_4_12_TO_INT((gBattleMons[gBattleScripting.battler].maxHP * multiplier) + UQ_4_12_ROUND);
BtlController_EmitSetMonData(BUFFER_A, REQUEST_MAX_HP_BATTLE, 0, sizeof(gBattleMons[gBattleScripting.battler].maxHP), &gBattleMons[gBattleScripting.battler].maxHP);
BtlController_EmitSetMonData(BUFFER_A, REQUEST_HP_BATTLE, 0, sizeof(gBattleMons[gBattleScripting.battler].hp), &gBattleMons[gBattleScripting.battler].hp);
MarkBattlerForControllerExec(gBattleScripting.battler);
}
break;
}
} // End of switch (cmd->id)
gBattlescriptCurrInstr = cmd->nextInstr;

View file

@ -1746,7 +1746,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_DYNAMAX;
u32 move = gBattleMons[gActiveBattler].moves[moveId];
u32 holdEffect = GetBattlerHoldEffect(gActiveBattler, TRUE);
u16 *choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
@ -2674,7 +2674,8 @@ enum
ENDTURN_SLOW_START,
ENDTURN_PLASMA_FISTS,
ENDTURN_CUD_CHEW,
ENDTURN_TORMENT,
ENDTURN_TORMENT, // supposedly this goes after Taunt, before Encore, but Encore is first right now?
ENDTURN_DYNAMAX,
ENDTURN_BATTLER_COUNT
};
@ -3232,6 +3233,17 @@ u8 DoBattlerEndTurnEffects(void)
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_DYNAMAX:
if (IsDynamaxed(gActiveBattler)
&& --gBattleStruct->dynamax.dynamaxTurns[gActiveBattler] == 0)
{
gBattleScripting.battler = gActiveBattler;
UndoDynamax(gActiveBattler);
BattleScriptExecute(BattleScript_DynamaxEnds);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_BATTLER_COUNT: // done
gBattleStruct->turnEffectsTracker = 0;
gBattleStruct->turnEffectsBattlerId++;