diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 146fea5cc4..bc63397341 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2145,3 +2145,18 @@ .macro trysymbiosis various BS_ATTACKER, VARIOUS_TRY_SYMBIOSIS .endm + + @ The next few macros are used by Max Moves. + .macro setmaxmoveeffect + various 0, VARIOUS_SET_MAX_MOVE_EFFECT + .endm + + .macro jumpiftargetabsent, ptr:req + various 0, VARIOUS_JUMP_IF_TARGET_ABSENT + .4byte \ptr + .endm + + .macro jumpiftargetnotally, ptr:req + various 0, VARIOUS_JUMP_IF_TARGET_NOT_ALLY + .4byte \ptr + .endm diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 96928560e4..33c8eb71c8 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -916,6 +916,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_SetWeather @ B_ANIM_MAX_SET_WEATHER .align 2 gBattleAnims_Special:: @@ -30654,23 +30655,71 @@ SoulStealingSevenStarStrikeExplosion: return @@@@@@@@@@ MAX MOVES @@@@@@@@@@ -Move_MAX_GUARD: -Move_MAX_STRIKE: +General_SetWeather:: + createvisualtask AnimTask_GetWeatherToSet, 2 + jumpreteq 1, General_Sun + jumpreteq 2, General_Rain + jumpreteq 3, General_Sandstorm + jumpreteq 4, General_Hail + end + Move_MAX_KNUCKLE: -Move_MAX_AIRSTREAM: -Move_MAX_OOZE: Move_MAX_QUAKE: Move_MAX_ROCKFALL: Move_MAX_FLUTTERBY: Move_MAX_PHANTASM: Move_MAX_STEELSPIKE: -Move_MAX_FLARE: -Move_MAX_GEYSER: -Move_MAX_OVERGROWTH: -Move_MAX_LIGHTNING: Move_MAX_HAILSTORM: Move_MAX_MINDSTORM: Move_MAX_WYRMWIND: Move_MAX_DARKNESS: Move_MAX_STARFALL: end + +Move_MAX_GUARD: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_PROTECT + end + +Move_MAX_STRIKE:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_GIGA_IMPACT + end + +Move_MAX_AIRSTREAM:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_AEROBLAST + end + +Move_MAX_OOZE:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_GUNK_SHOT + end + +Move_MAX_FLARE:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_BLAST_BURN + end + +Move_MAX_GEYSER:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_HYDRO_CANNON + end + +Move_MAX_OVERGROWTH:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_FRENZY_PLANT + end + +Move_MAX_LIGHTNING:: + launchtask AnimTask_DynamaxGrowth 0x5 0x1 0x1 + waitforvisualfinish + goto Move_ZAP_CANNON + end diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index b46fbba590..dd291aedfc 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -417,14 +417,6 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectTerrainHit @ EFFECT_DAMAGE_SET_TERRAIN .4byte BattleScript_EffectMaxMove @ EFFECT_MAX_MOVE -BattleScript_EffectMaxMove:: - attackcanceler - @setmaxmoveeffect - accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON - attackstring - ppreduce - goto BattleScript_HitFromCritCalc - BattleScript_AffectionBasedEndurance:: playanimation BS_TARGET, B_ANIM_AFFECTION_HANGED_ON printstring STRINGID_TARGETTOUGHEDITOUT @@ -9889,3 +9881,67 @@ BattleScript_SymbiosisActivates:: printstring STRINGID_SYMBIOSISITEMPASS waitmessage B_WAIT_TIME_LONG return + +@@@ MAX MOVES @@@ +BattleScript_EffectMaxMove:: + attackcanceler + setmaxmoveeffect + accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON + attackstring + ppreduce + goto BattleScript_HitFromCritCalc + +BattleScript_EffectRaiseSideStats:: + savetarget + setbyte gBattlerTarget, 0 +BattleScript_RaiseSideStatsLoop: + jumpiftargetnotally BattleScript_RaiseSideStatsIncrement + jumpiftargetabsent BattleScript_RaiseSideStatsIncrement + statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_RaiseSideStatsIncrement + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_RaiseSideStatsIncrement + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_RaiseSideStatsIncrement: + setbyte sSTAT_ANIM_PLAYED, FALSE + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_RaiseSideStatsLoop +BattleScript_RaiseSideStatsEnd: + restoretarget + return + +BattleScript_EffectLowerSideStats:: + savetarget + setbyte gBattlerTarget, 0 +BattleScript_LowerSideStatsLoop: + jumpiftargetally BattleScript_LowerSideStatsIncrement + jumpiftargetabsent BattleScript_LowerSideStatsIncrement + statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_LowerSideStatsIncrement + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_LowerSideStatsIncrement + setgraphicalstatchangevalues + playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 + printfromtable gStatDownStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_LowerSideStatsIncrement: + setbyte sSTAT_ANIM_PLAYED, FALSE + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_LowerSideStatsLoop +BattleScript_LowerSideStatsEnd: + restoretarget + return + +BattleScript_EffectSetWeather:: + playanimation 0, B_ANIM_MAX_SET_WEATHER + printfromtable gMoveWeatherChangeStringIds + waitmessage B_WAIT_TIME_LONG + call BattleScript_WeatherFormChanges + return + +BattleScript_EffectSetTerrain:: + printfromtable gTerrainStringIds + waitmessage B_WAIT_TIME_LONG + playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG + call BattleScript_TerrainSeedLoop + jumpifabilitypresent ABILITY_MIMICRY, BattleScript_ApplyMimicry + return diff --git a/include/battle.h b/include/battle.h index 3739a04307..701c9c8df9 100644 --- a/include/battle.h +++ b/include/battle.h @@ -148,6 +148,7 @@ struct ProtectStruct u16 quickDraw:1; u16 beakBlastCharge:1; u16 quash:1; + u16 maxGuarded:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; @@ -510,6 +511,14 @@ struct ZMoveData u8 splits[MAX_BATTLERS_COUNT]; }; +struct DynamaxData +{ + u8 dynamaxTurns[MAX_BATTLERS_COUNT]; + u8 usingMaxMove[MAX_BATTLERS_COUNT]; + u8 activeSplit; + u8 splits[MAX_BATTLERS_COUNT]; +}; + struct StolenItem { u16 originalItem:15; @@ -615,6 +624,7 @@ struct BattleStruct bool8 throwingPokeBall; struct MegaEvolutionData mega; struct ZMoveData zmove; + struct DynamaxData dynamax; const u8 *trainerSlideMsg; bool8 trainerSlideLowHpMsgDone; u8 introState; diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index 33613328a8..403abdaf95 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -1,5 +1,5 @@ -#ifndef GUARD_BATTLE_RAID_H -#define GUARD_BATTLE_RAID_H +#ifndef GUARD_BATTLE_DYNAMAX_H +#define GUARD_BATTLE_DYNAMAX_H enum MaxMoveEffect { @@ -52,4 +52,8 @@ enum MaxMoveEffect MAX_EFFECT_FIRE_SPIN_FOES, }; +bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove); +u16 GetMaxMove(u16 battlerId, u16 baseMove); +bool8 IsMaxMove(u16 move); + #endif diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 2d6364fb96..83c25b1ca6 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -439,4 +439,10 @@ extern const u8 BattleScript_StatUpZMove[]; extern const u8 BattleScript_HealReplacementZMove[]; extern const u8 BattleScript_EffectExtremeEvoboost[]; +// max moves +extern const u8 BattleScript_EffectRaiseSideStats[]; +extern const u8 BattleScript_EffectLowerSideStats[]; +extern const u8 BattleScript_EffectSetWeather[]; +extern const u8 BattleScript_EffectSetTerrain[]; + #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle.h b/include/constants/battle.h index c4f68882e9..6224dd2838 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -368,8 +368,12 @@ #define MOVE_EFFECT_TRAP_BOTH 0x48 #define MOVE_EFFECT_SKY_DROP 0x49 #define MOVE_EFFECT_SCALE_SHOT 0x4A +#define MOVE_EFFECT_RAISE_SIDE_STATS 0x4B +#define MOVE_EFFECT_LOWER_SIDE_STATS 0x4C +#define MOVE_EFFECT_WEATHER 0x4D +#define MOVE_EFFECT_TERRAIN 0x4E -#define NUM_MOVE_EFFECTS 0x4B +#define NUM_MOVE_EFFECTS 0x4F #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index 52b20ecaa4..252f855c33 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -535,6 +535,7 @@ #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 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index b11e7eb653..7701675ba0 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -245,6 +245,9 @@ #define VARIOUS_TRY_SYMBIOSIS 154 #define VARIOUS_CAN_TELEPORT 155 #define VARIOUS_GET_BATTLER_SIDE 156 +#define VARIOUS_SET_MAX_MOVE_EFFECT 157 +#define VARIOUS_JUMP_IF_TARGET_NOT_ALLY 158 +#define VARIOUS_JUMP_IF_TARGET_ABSENT 159 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 0a65deb282..dd88bfad45 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -7903,3 +7903,60 @@ void AnimTask_AffectionHangedOn(u8 taskId) gBattleAnimArgs[0] = GetBattlerFriendshipScore(gBattleAnimTarget); DestroyAnimVisualTask(taskId); } + +// DYNAMAX +static const union AffineAnimCmd sDynamaxGrowthAffineAnimCmds[] = // from CFRU +{ + AFFINEANIMCMD_FRAME(-2, -2, 0, 64), //Double in size over 1 second + AFFINEANIMCMD_FRAME(0, 0, 0, 64), //Pause for 1 seconds + AFFINEANIMCMD_FRAME(16, 16, 0, 8), //Shrink back down in 1/8 of a second + AFFINEANIMCMD_END, +}; + +static const union AffineAnimCmd sDynamaxGrowthAttackAnimationAffineAnimCmds[] = +{ + AFFINEANIMCMD_FRAME(-4, -4, 0, 32), //Double in size quicker + AFFINEANIMCMD_FRAME(0, 0, 0, 32), //Pause for less + AFFINEANIMCMD_FRAME(16, 16, 0, 8), + AFFINEANIMCMD_END, +}; + +static void AnimTask_DynamaxGrowthStep(u8 taskId) // from CFRU +{ + struct Task* task = &gTasks[taskId]; + if (!RunAffineAnimFromTaskData(task)) + DestroyAnimVisualTask(taskId); +} + +//Arg 0: Animation for attack +void AnimTask_DynamaxGrowth(u8 taskId) // from CFRU +{ + struct Task* task = &gTasks[taskId]; + u8 spriteId = GetAnimBattlerSpriteId(ANIM_ATTACKER); + + if (gBattleAnimArgs[0] == 0) + PrepareAffineAnimInTaskData(task, spriteId, sDynamaxGrowthAffineAnimCmds); + else + PrepareAffineAnimInTaskData(task, spriteId, sDynamaxGrowthAttackAnimationAffineAnimCmds); + task->func = AnimTask_DynamaxGrowthStep; +} + +void AnimTask_GetWeatherToSet(u8 taskId) +{ + switch (gBattleMoves[gCurrentMove].argument) + { + case MAX_EFFECT_SUN: + gBattleAnimArgs[ARG_RET_ID] = 1; + break; + case MAX_EFFECT_RAIN: + gBattleAnimArgs[ARG_RET_ID] = 2; + break; + case MAX_EFFECT_SANDSTORM: + gBattleAnimArgs[ARG_RET_ID] = 3; + break; + case MAX_EFFECT_HAIL: + gBattleAnimArgs[ARG_RET_ID] = 4; + break; + } + DestroyAnimVisualTask(taskId); +} diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c new file mode 100644 index 0000000000..798fd87e14 --- /dev/null +++ b/src/battle_dynamax.c @@ -0,0 +1,103 @@ +#include "global.h" +#include "pokemon.h" +#include "battle.h" +#include "constants/moves.h" + +// Constant Data +static const u16 sMaxMoveTable[] = +{ + [TYPE_NORMAL] = MOVE_MAX_STRIKE, + [TYPE_FIGHTING] = MOVE_MAX_KNUCKLE, + [TYPE_FLYING] = MOVE_MAX_AIRSTREAM, + [TYPE_POISON] = MOVE_MAX_OOZE, + [TYPE_GROUND] = MOVE_MAX_QUAKE, + [TYPE_ROCK] = MOVE_MAX_ROCKFALL, + [TYPE_BUG] = MOVE_MAX_FLUTTERBY, + [TYPE_GHOST] = MOVE_MAX_PHANTASM, + [TYPE_STEEL] = MOVE_MAX_STEELSPIKE, + [TYPE_FIRE] = MOVE_MAX_FLARE, + [TYPE_WATER] = MOVE_MAX_GEYSER, + [TYPE_GRASS] = MOVE_MAX_OVERGROWTH, + [TYPE_ELECTRIC] = MOVE_MAX_LIGHTNING, + [TYPE_PSYCHIC] = MOVE_MAX_MINDSTORM, + [TYPE_ICE] = MOVE_MAX_HAILSTORM, + [TYPE_DRAGON] = MOVE_MAX_WYRMWIND, + [TYPE_DARK] = MOVE_MAX_DARKNESS, + [TYPE_FAIRY] = MOVE_MAX_STARFALL, +}; + +struct GMaxMove +{ + u16 species; + u8 moveType; + u16 gmaxMove; +}; + +static const struct GMaxMove sGMaxMoveTable[] = +{ + {SPECIES_VENUSAUR_GMAX, TYPE_GRASS, MOVE_G_MAX_VINE_LASH}, + {SPECIES_CHARIZARD_GMAX, TYPE_FIRE, MOVE_G_MAX_WILDFIRE}, + {SPECIES_BLASTOISE_GMAX, TYPE_WATER, MOVE_G_MAX_CANNONADE}, + {SPECIES_BUTTERFREE_GMAX, TYPE_BUG, MOVE_G_MAX_BEFUDDLE}, + {SPECIES_PIKACHU_GMAX, TYPE_ELECTRIC, MOVE_G_MAX_VOLT_CRASH}, + {SPECIES_MEOWTH_GMAX, TYPE_NORMAL, MOVE_G_MAX_GOLD_RUSH}, + {SPECIES_MACHAMP_GMAX, TYPE_FIGHTING, MOVE_G_MAX_CHI_STRIKE}, + {SPECIES_GENGAR_GMAX, TYPE_GHOST, MOVE_G_MAX_TERROR}, + {SPECIES_KINGLER_GMAX, TYPE_WATER, MOVE_G_MAX_FOAM_BURST}, + {SPECIES_LAPRAS_GMAX, TYPE_ICE, MOVE_G_MAX_RESONANCE}, + {SPECIES_EEVEE_GMAX, TYPE_NORMAL, MOVE_G_MAX_CUDDLE}, + {SPECIES_SNORLAX_GMAX, TYPE_NORMAL, MOVE_G_MAX_REPLENISH}, + {SPECIES_GARBODOR_GMAX, TYPE_POISON, MOVE_G_MAX_MALODOR}, + {SPECIES_MELMETAL_GMAX, TYPE_STEEL, MOVE_G_MAX_MELTDOWN}, + {SPECIES_RILLABOOM_GMAX, TYPE_GRASS, MOVE_G_MAX_DRUM_SOLO}, + {SPECIES_CINDERACE_GMAX, TYPE_FIRE, MOVE_G_MAX_FIREBALL}, + {SPECIES_INTELEON_GMAX, TYPE_WATER, MOVE_G_MAX_HYDROSNIPE}, + {SPECIES_CORVIKNIGHT_GMAX, TYPE_FLYING, MOVE_G_MAX_WIND_RAGE}, + {SPECIES_ORBEETLE_GMAX, TYPE_PSYCHIC, MOVE_G_MAX_GRAVITAS}, + {SPECIES_DREDNAW_GMAX, TYPE_WATER, MOVE_G_MAX_STONESURGE}, + {SPECIES_COALOSSAL_GMAX, TYPE_ROCK, MOVE_G_MAX_VOLCALITH}, + {SPECIES_FLAPPLE_GMAX, TYPE_GRASS, MOVE_G_MAX_TARTNESS}, + {SPECIES_APPLETUN_GMAX, TYPE_GRASS, MOVE_G_MAX_SWEETNESS}, + {SPECIES_SANDACONDA_GMAX, TYPE_GROUND, MOVE_G_MAX_SANDBLAST}, + {SPECIES_TOXTRICITY_GMAX, TYPE_ELECTRIC, MOVE_G_MAX_STUN_SHOCK}, + {SPECIES_CENTISKORCH_GMAX, TYPE_FIRE, MOVE_G_MAX_CENTIFERNO}, + {SPECIES_HATTERENE_GMAX, TYPE_FAIRY, MOVE_G_MAX_SMITE}, + {SPECIES_GRIMMSNARL_GMAX, TYPE_DARK, MOVE_G_MAX_SNOOZE}, + {SPECIES_ALCREMIE_GMAX, TYPE_FAIRY, MOVE_G_MAX_FINALE}, + {SPECIES_COPPERAJAH_GMAX, TYPE_STEEL, MOVE_G_MAX_STEELSURGE}, + {SPECIES_DURALUDON_GMAX, TYPE_DRAGON, MOVE_G_MAX_DEPLETION}, + {SPECIES_URSHIFU_GMAX, TYPE_DARK, MOVE_G_MAX_ONE_BLOW}, + {SPECIES_URSHIFU_RAPID_STRIKE_STYLE_GMAX, TYPE_WATER, MOVE_G_MAX_RAPID_FLOW}, +}; + +// Functions: +bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove) +{ + // TODO: Raids + //if (IsRaidBoss(battlerId)) + // return !IsRaidBossUsingRegularMove(battlerId, baseMove); + if (gBattleStruct->dynamax.dynamaxTurns[battlerId] > 0) + return TRUE; + return TRUE; +} + +u16 GetMaxMove(u16 battlerId, u16 baseMove) +{ + u16 move = baseMove; + if (gBattleMoves[baseMove].split == SPLIT_STATUS) + { + move = MOVE_MAX_GUARD; + } + else + { + move = sMaxMoveTable[gBattleMoves[baseMove].type]; + gBattleStruct->dynamax.splits[battlerId] = gBattleMoves[baseMove].split; + } + + return move; +} + +bool8 IsMaxMove(u16 move) +{ + return move >= FIRST_MAX_MOVE && move <= LAST_MAX_MOVE; +} \ No newline at end of file diff --git a/src/battle_main.c b/src/battle_main.c index e798796627..9381020a63 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4225,6 +4225,8 @@ static void HandleTurnActionSelectionState(void) *(gBattleStruct->moveTarget + gActiveBattler) = gBattleResources->bufferB[gActiveBattler][3]; if (gBattleResources->bufferB[gActiveBattler][2] & RET_MEGA_EVOLUTION) gBattleStruct->mega.toEvolve |= gBitTable[gActiveBattler]; + if (ShouldUseMaxMove(gActiveBattler, gChosenMoveByBattler[gActiveBattler])) // max move check + gBattleStruct->dynamax.usingMaxMove[gActiveBattler] = TRUE; gBattleCommunication[gActiveBattler]++; } break; @@ -4524,6 +4526,11 @@ s8 GetMovePriority(u32 battlerId, u16 move) u16 ability = GetBattlerAbility(battlerId); priority = gBattleMoves[move].priority; + + // Max Guard check + if (gBattleStruct->dynamax.usingMaxMove[battlerId] && gBattleMoves[move].split == SPLIT_STATUS) + return gBattleMoves[MOVE_MAX_GUARD].priority; + if (ability == ABILITY_GALE_WINGS #if B_GALE_WINGS >= GEN_7 && BATTLER_MAX_HP(battlerId) diff --git a/src/battle_message.c b/src/battle_message.c index 568aac774d..63590905db 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -2837,6 +2837,8 @@ void BufferStringBattle(u16 stringID) case STRINGID_USEDMOVE: // pokemon used a move msg if (gBattleStruct->zmove.active && gBattleStruct->zmove.activeSplit != SPLIT_STATUS) StringCopy(gBattleTextBuff3, GetZMoveName(gBattleMsgDataPtr->currentMove)); + else if (IsMaxMove(gBattleMsgDataPtr->currentMove)) + StringCopy(gBattleTextBuff3, gMoveNames[gBattleMsgDataPtr->currentMove]); else if (gBattleMsgDataPtr->currentMove >= MOVES_COUNT) StringCopy(gBattleTextBuff3, sATypeMove_Table[*(&gBattleStruct->stringMoveType)]); else diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index eaa7bbde1a..6d19d99a79 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3616,6 +3616,89 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattlescriptCurrInstr = BattleScript_DefDownSpeedUp; } break; + // MAX MOVE EFFECTS + case MOVE_EFFECT_RAISE_SIDE_STATS: + if (!NoAliveMonsForEitherParty()) + { + SET_STATCHANGER(gBattleMoves[gCurrentMove].argument, 1, FALSE); // see enum MaxMoveEffect + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_EffectRaiseSideStats; + break; + } + case MOVE_EFFECT_LOWER_SIDE_STATS: + if (!NoAliveMonsForEitherParty()) + { + SET_STATCHANGER(gBattleMoves[gCurrentMove].argument - 5, 1, TRUE); // see enum MaxMoveEffect + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_EffectLowerSideStats; + break; + } + case MOVE_EFFECT_WEATHER: + { + u8 weather, msg; + switch (gBattleMoves[gCurrentMove].argument) + { + case MAX_EFFECT_SUN: + weather = ENUM_WEATHER_SUN; + msg = B_MSG_STARTED_SUNLIGHT; + break; + case MAX_EFFECT_RAIN: + weather = ENUM_WEATHER_RAIN; + msg = B_MSG_STARTED_RAIN; + break; + case MAX_EFFECT_SANDSTORM: + weather = ENUM_WEATHER_SANDSTORM; + msg = B_MSG_STARTED_SANDSTORM; + break; + case MAX_EFFECT_HAIL: + weather = ENUM_WEATHER_HAIL; + msg = B_MSG_STARTED_HAIL; + break; + } + if (TryChangeBattleWeather(gBattlerAttacker, weather, FALSE)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = msg; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_EffectSetWeather; + } + break; + } + case MOVE_EFFECT_TERRAIN: + { + u32 statusFlag = 0; + u8 *timer = NULL; + switch (gBattleMoves[gCurrentMove].argument) + { + case MAX_EFFECT_MISTY_TERRAIN: + statusFlag = STATUS_FIELD_MISTY_TERRAIN, timer = &gFieldTimers.terrainTimer; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + break; + case MAX_EFFECT_GRASSY_TERRAIN: + statusFlag = STATUS_FIELD_GRASSY_TERRAIN, timer = &gFieldTimers.terrainTimer; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + break; + case MAX_EFFECT_ELECTRIC_TERRAIN: + statusFlag = STATUS_FIELD_ELECTRIC_TERRAIN, timer = &gFieldTimers.terrainTimer; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + break; + case MAX_EFFECT_PSYCHIC_TERRAIN: + statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN, timer = &gFieldTimers.terrainTimer; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + break; + } + if (!(gFieldStatuses & statusFlag) && statusFlag != 0) + { + gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; + gFieldStatuses |= statusFlag; + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_TERRAIN_EXTENDER) + *timer = 8; + else + *timer = 5; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_EffectSetTerrain; + } + break; + } } } } @@ -9898,6 +9981,49 @@ static void Cmd_various(void) else gBattleCommunication[0] = B_SIDE_OPPONENT; break; + case VARIOUS_SET_MAX_MOVE_EFFECT: + switch (gBattleMoves[gCurrentMove].argument) + { + case MAX_EFFECT_RAISE_TEAM_ATTACK: + case MAX_EFFECT_RAISE_TEAM_DEFENSE: + case MAX_EFFECT_RAISE_TEAM_SPEED: + case MAX_EFFECT_RAISE_TEAM_SP_ATK: + case MAX_EFFECT_RAISE_TEAM_SP_DEF: + gBattleScripting.moveEffect = MOVE_EFFECT_RAISE_SIDE_STATS; + break; + case MAX_EFFECT_LOWER_ATTACK: + case MAX_EFFECT_LOWER_DEFENSE: + case MAX_EFFECT_LOWER_SPEED: + case MAX_EFFECT_LOWER_SP_ATK: + case MAX_EFFECT_LOWER_SP_DEF: + gBattleScripting.moveEffect = MOVE_EFFECT_LOWER_SIDE_STATS; + break; + case MAX_EFFECT_SUN: + case MAX_EFFECT_RAIN: + case MAX_EFFECT_SANDSTORM: + case MAX_EFFECT_HAIL: + gBattleScripting.moveEffect = MOVE_EFFECT_WEATHER; + break; + case MAX_EFFECT_MISTY_TERRAIN: + case MAX_EFFECT_GRASSY_TERRAIN: // TODO: Grassy terrain not working? + case MAX_EFFECT_ELECTRIC_TERRAIN: + case MAX_EFFECT_PSYCHIC_TERRAIN: + gBattleScripting.moveEffect = MOVE_EFFECT_TERRAIN; + break; + } + break; + case VARIOUS_JUMP_IF_TARGET_NOT_ALLY: + if (GetBattlerSide(gBattlerTarget) != GetBattlerSide(gBattlerAttacker)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; + return; + case VARIOUS_JUMP_IF_TARGET_ABSENT: + if (!IsBattlerAlive(gBattlerTarget)) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else + gBattlescriptCurrInstr += 7; + return; } // End of switch (gBattlescriptCurrInstr[2]) gBattlescriptCurrInstr += 3; @@ -9948,6 +10074,11 @@ static void Cmd_setprotectlike(void) gProtectStructs[gBattlerAttacker].obstructed = TRUE; gBattleCommunication[MULTISTRING_CHOOSER] = 0; } + else if (gCurrentMove == MOVE_MAX_GUARD) + { + gProtectStructs[gBattlerAttacker].maxGuarded = TRUE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PROTECTED_ITSELF; + } gDisableStructs[gBattlerAttacker].protectUses++; fail = FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index d83f8429e9..dc3ef260e8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -48,6 +48,7 @@ #include "constants/pokemon.h" extern struct Evolution gEvolutionTable[][EVOS_PER_MON]; +extern u8 gDynamaxMovePowers[MOVES_COUNT]; /* NOTE: The data and functions in this file up until (but not including) sSoundMovesTable @@ -303,6 +304,14 @@ void HandleAction_UseMove(void) gCurrentMove = gBattleStruct->zmove.toBeUsed[gBattlerAttacker]; } + // check max move used + if (gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker]) + { + gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); + gBattleStruct->dynamax.activeSplit = gBattleStruct->dynamax.splits[gBattlerAttacker]; + gBattleStruct->moveTarget[gBattlerAttacker] = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + } + if (gBattleMons[gBattlerAttacker].hp != 0) { if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) @@ -911,6 +920,7 @@ void HandleAction_ActionFinished(void) gBattleCommunication[4] = 0; gBattleScripting.multihitMoveEffect = 0; gBattleResources->battleScriptsStack->size = 0; + gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker] = 0; #if B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already @@ -7908,6 +7918,15 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) return FALSE; } + // Max Moves bypass any protection except Max Guard + if (IsMaxMove(move)) + { + if (gProtectStructs[battlerId].maxGuarded) + return TRUE; + else + return FALSE; + } + // Protective Pads doesn't stop Unseen Fist from bypassing Protect effects, so IsMoveMakingContact() isn't used here. // This means extra logic is needed to handle Shell Side Arm. if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNSEEN_FIST @@ -8404,6 +8423,9 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN)) basePower *= 2; break; + case EFFECT_MAX_MOVE: + basePower = gDynamaxMovePowers[gBattleMons[battlerAtk].moves[gBattleStruct->chosenMovePositions[battlerAtk]]]; + break; } // Move-specific base power changes @@ -9869,6 +9891,8 @@ u8 GetBattleMoveSplit(u32 moveId) { if (gBattleStruct != NULL && gBattleStruct->zmove.active && !IS_MOVE_STATUS(moveId)) return gBattleStruct->zmove.activeSplit; + if (gBattleStruct != NULL && IsMaxMove(moveId)) // TODO: Might be buggy depending on when this is called. + return gBattleStruct->dynamax.activeSplit; if (gBattleStruct != NULL && gBattleStruct->swapDamageCategory) // Photon Geyser, Shell Side Arm, Light That Burns the Sky return SPLIT_PHYSICAL; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 46fb13335e..064b68a6e0 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -14355,6 +14355,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_PSYCHIC_TERRAIN, }, + [MOVE_MAX_ROCKFALL] = { .effect = EFFECT_MAX_MOVE, @@ -14369,6 +14370,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_SANDSTORM, }, + [MOVE_MAX_QUAKE] = { .effect = EFFECT_MAX_MOVE, @@ -14383,6 +14385,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAISE_TEAM_SP_DEF, }, + [MOVE_MAX_DARKNESS] = { .effect = EFFECT_MAX_MOVE, @@ -14397,6 +14400,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_SP_DEF, }, + [MOVE_MAX_OVERGROWTH] = { .effect = EFFECT_MAX_MOVE, @@ -14411,6 +14415,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_GRASSY_TERRAIN, }, + [MOVE_MAX_STEELSPIKE] = { .effect = EFFECT_MAX_MOVE,