diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index bbb544de27..f9da963107 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2237,6 +2237,16 @@ various 0, VARIOUS_DAMAGE_NON_TYPES .endm + .macro trysetstatus1, ptr:req + various 0, VARIOUS_TRY_SET_STATUS1 + .4byte \ptr + .endm + + .macro trysetstatus2, ptr:req + various 0, VARIOUS_TRY_SET_STATUS2 + .4byte \ptr + .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 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3fe0aa950f..0e77b5880e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -10358,7 +10358,7 @@ BattleScript_EffectMaxMove:: tryfaintmon BS_TARGET goto BattleScript_MoveEnd -BattleScript_EffectRaiseSideStats:: +BattleScript_EffectRaiseStatAllies:: savetarget setbyte gBattlerTarget, 0 BattleScript_RaiseSideStatsLoop: @@ -10378,7 +10378,7 @@ BattleScript_RaiseSideStatsEnd: restoretarget return -BattleScript_EffectLowerSideStats:: +BattleScript_EffectLowerStatFoes:: savetarget setbyte gBattlerTarget, 0 BattleScript_LowerSideStatsLoop: @@ -10460,6 +10460,57 @@ BattleScript_EffectTryReducePP:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd +BattleScript_EffectStatus1Foes:: + savetarget + setbyte gBattlerTarget, 0 +BattleScript_Status1FoesLoop: + jumpiftargetally BattleScript_Status1FoesIncrement + jumpiftargetabsent BattleScript_Status1FoesIncrement + trysetstatus1 BattleScript_Status1FoesIncrement + statusanimation BS_TARGET + updatestatusicon BS_TARGET + printfromtable gStatusConditionsStringIds + waitmessage B_WAIT_TIME_LONG + goto BattleScript_UpdateEffectStatusIconRet +BattleScript_Status1FoesIncrement: + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_Status1FoesLoop +BattleScript_Status1FoesEnd: + restoretarget + goto BattleScript_MoveEnd + +BattleScript_EffectStatus2Foes:: + savetarget + setbyte gBattlerTarget, 0 +BattleScript_Status2FoesLoop: + jumpiftargetally BattleScript_Status2FoesIncrement + jumpiftargetabsent BattleScript_Status2FoesIncrement + trysetstatus2 BattleScript_Status2FoesIncrement + jumpifbyte CMP_EQUAL, gBattleCommunication, 1, BattleScript_DoConfuseAnim + jumpifbyte CMP_EQUAL, gBattleCommunication, 2, BattleScript_DoInfatuationAnim +BattleScript_Status2FoesPrintMessage: + printfromtable gStatus2StringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_Status2FoesIncrement: + addbyte gBattlerTarget, 1 + jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_Status2FoesLoop +BattleScript_Status2FoesEnd: + restoretarget + goto BattleScript_MoveEnd + +BattleScript_DoConfuseAnim: + status2animation BS_TARGET, STATUS2_CONFUSION + goto BattleScript_Status2FoesPrintMessage + +BattleScript_DoInfatuationAnim: + status2animation BS_TARGET, STATUS2_INFATUATION + goto BattleScript_Status2FoesPrintMessage + +BattleScript_TormentEnds:: + printstring STRINGID_TORMENTEDNOMORE + waitmessage B_WAIT_TIME_LONG + end2 + BattleScript_PokemonCantUseTheMove:: attackstring ppreduce diff --git a/include/battle.h b/include/battle.h index 9a9da26274..26bfe1e38b 100644 --- a/include/battle.h +++ b/include/battle.h @@ -96,6 +96,7 @@ struct DisableStruct u8 laserFocusTimer; u8 throatChopTimer; u8 wrapTurns; + u8 tormentTimer:4; // used for G-Max Meltdown u8 usedMoves:4; u8 noRetreat:1; u8 tarShot:1; diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index 125f850119..bd13397c58 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -58,7 +58,8 @@ u16 GetMaxMove(u16 battlerId, u16 baseMove); u8 GetMaxMovePower(u16 move); bool8 IsMaxMove(u16 move); const u8 *GetMaxMoveName(u16 move); -void ChooseDamageNonTypesString(u8 move); +void ChooseDamageNonTypesString(u8 type); +u32 GetMaxMoveStatusEffect(u16 move); u16 SetMaxMoveEffect(u16 move); #endif diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 555f2618c3..604ce10d93 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -465,8 +465,8 @@ 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_EffectRaiseStatAllies[]; +extern const u8 BattleScript_EffectLowerStatFoes[]; extern const u8 BattleScript_EffectSetWeather[]; extern const u8 BattleScript_EffectSetTerrain[]; extern const u8 BattleScript_SteelsurgeActivates[]; @@ -478,5 +478,8 @@ extern const u8 BattleScript_EffectAuroraVeilSuccess[]; extern const u8 BattleScript_EffectGravitySuccess[]; extern const u8 BattleScript_EffectYawnSuccess[]; extern const u8 BattleScript_EffectTryReducePP[]; +extern const u8 BattleScript_EffectStatus1Foes[]; +extern const u8 BattleScript_EffectStatus2Foes[]; +extern const u8 BattleScript_TormentEnds[]; #endif // GUARD_BATTLE_SCRIPTS_H \ No newline at end of file diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 0eb219eaad..dd6892b254 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -265,6 +265,8 @@ #define VARIOUS_JUMP_IF_TARGET_ABSENT 173 #define VARIOUS_SET_STEELSURGE 174 #define VARIOUS_DAMAGE_NON_TYPES 175 +#define VARIOUS_TRY_SET_STATUS1 176 +#define VARIOUS_TRY_SET_STATUS2 177 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index baf5605c57..03966c1bca 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -99,7 +99,11 @@ bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove) u16 GetMaxMove(u16 battlerId, u16 baseMove) { u16 move = baseMove; - if (gBattleMoves[baseMove].split == SPLIT_STATUS) + if (baseMove == MOVE_STRUGGLE) + { + return MOVE_STRUGGLE; + } + else if (gBattleMoves[baseMove].split == SPLIT_STATUS) { move = MOVE_MAX_GUARD; } @@ -192,6 +196,45 @@ void ChooseDamageNonTypesString(u8 type) } } +// Returns the status effect that should be applied by a G-Max Move. +u32 GetMaxMoveStatusEffect(u16 move) +{ + u8 maxEffect = gBattleMoves[move].argument; + switch (maxEffect) + { + // Status 1 + case MAX_EFFECT_PARALYZE_FOES: + return STATUS1_PARALYSIS; + case MAX_EFFECT_POISON_FOES: + return STATUS1_POISON; + case MAX_EFFECT_POISON_PARALYZE_FOES: + if (Random() % 2) + return STATUS1_POISON; + else + return STATUS1_PARALYSIS; + case MAX_EFFECT_EFFECT_SPORE_FOES: + { + u8 effect = Random() % 3; + if (effect == 0) + return STATUS1_PARALYSIS; + else if (effect == 1) + return STATUS1_POISON; + else + return STATUS1_SLEEP; + } + // Status 2 + case MAX_EFFECT_CONFUSE_FOES: + case MAX_EFFECT_CONFUSE_FOES_PAY_DAY: + return STATUS2_CONFUSION; + case MAX_EFFECT_INFATUATE_FOES: + return STATUS2_INFATUATION; + case MAX_EFFECT_MEAN_LOOK: + return STATUS2_ESCAPE_PREVENTION; + case MAX_EFFECT_TORMENT_FOES: + return STATUS2_TORMENT; + } +} + // Activates the secondary effect of a Max Move. u16 SetMaxMoveEffect(u16 move) { @@ -214,7 +257,7 @@ u16 SetMaxMoveEffect(u16 move) // Max Effects are ordered by stat ID. SET_STATCHANGER(gBattleMoves[gCurrentMove].argument, 1, FALSE); BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_EffectRaiseSideStats; + gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; effect++; } break; @@ -245,7 +288,7 @@ u16 SetMaxMoveEffect(u16 move) } SET_STATCHANGER(statId, stage, TRUE); BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_EffectLowerSideStats; + gBattlescriptCurrInstr = BattleScript_EffectLowerStatFoes; effect++; } break; @@ -425,14 +468,7 @@ u16 SetMaxMoveEffect(u16 move) } case MAX_EFFECT_YAWN_FOE: if (!(gStatuses3[gBattlerTarget] & STATUS3_YAWN) - && !(gBattleMons[gBattlerTarget].status1 & STATUS1_ANY) - && gBattleMons[gBattlerTarget].ability != ABILITY_VITAL_SPIRIT - && gBattleMons[gBattlerTarget].ability != ABILITY_INSOMNIA - && gBattleMons[gBattlerTarget].ability != ABILITY_COMATOSE - && gBattleMons[gBattlerTarget].ability != ABILITY_PURIFYING_SALT - && !IsFlowerVeilProtected(gBattlerTarget) - && !(gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE) - && !UproarWakeUpCheck(gActiveBattler)) + && CanSleep(gBattlerTarget)) { gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2); BattleScriptPush(gBattlescriptCurrInstr + 1); @@ -449,6 +485,23 @@ u16 SetMaxMoveEffect(u16 move) effect++; } break; + case MAX_EFFECT_PARALYZE_FOES: + case MAX_EFFECT_POISON_FOES: + case MAX_EFFECT_POISON_PARALYZE_FOES: + case MAX_EFFECT_EFFECT_SPORE_FOES: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_EffectStatus1Foes; + effect++; + break; + case MAX_EFFECT_CONFUSE_FOES_PAY_DAY: + case MAX_EFFECT_CONFUSE_FOES: + case MAX_EFFECT_INFATUATE_FOES: + case MAX_EFFECT_TORMENT_FOES: + case MAX_EFFECT_MEAN_LOOK: + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_EffectStatus2Foes; + effect++; + break; } return effect; } diff --git a/src/battle_message.c b/src/battle_message.c index 8ebc73679f..6da7de6c3c 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1893,6 +1893,11 @@ const u16 gStatusConditionsStringIds[] = STRINGID_PKMNWASPOISONED, STRINGID_PKMNBADLYPOISONED, STRINGID_PKMNWASBURNED, STRINGID_PKMNWASPARALYZED, STRINGID_PKMNFELLASLEEP }; +const u16 gStatus2StringIds[] = +{ + STRINGID_PKMNWASCONFUSED, STRINGID_PKMNFELLINLOVE, STRINGID_TARGETCANTESCAPENOW, STRINGID_PKMNSUBJECTEDTOTORMENT +}; + const u16 gDamageNonTypesStartStringIds[] = { STRINGID_TEAMTRAPPEDWITHVINES, STRINGID_TEAMCAUGHTINVORTEX, STRINGID_TEAMSURROUNDEDBYFIRE, STRINGID_TEAMSURROUNDEDBYROCKS diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e5d7a94b26..44e2b21626 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -11210,6 +11210,120 @@ static void Cmd_various(void) } break; } + case VARIOUS_TRY_SET_STATUS1: + { + VARIOUS_ARGS(const u8 *failInstr); + u8 effect = 0; + u32 status1 = GetMaxMoveStatusEffect(gCurrentMove); + switch (status1) + { + case STATUS1_POISON: + if (CanBePoisoned(gBattlerAttacker, gBattlerTarget)) + { + gBattleMons[gBattlerTarget].status1 |= STATUS1_POISON; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + effect++; + } + break; + case STATUS1_PARALYSIS: + if (CanBeParalyzed(gBattlerTarget)) + { + gBattleMons[gBattlerTarget].status1 |= STATUS1_PARALYSIS; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + effect++; + } + break; + case STATUS1_SLEEP: + if (CanSleep(gBattlerTarget)) + { + #if B_SLEEP_TURNS >= GEN_5 + gBattleMons[gBattlerTarget].status1 |= STATUS1_SLEEP_TURN((Random() % 3) + 2); + #else + gBattleMons[gBattlerTarget].status1 |= STATUS1_SLEEP_TURN((Random() % 4) + 3); + #endif + gBattleCommunication[MULTISTRING_CHOOSER] = 4; + effect++; + } + break; + } + if (effect) + { + gActiveBattler = gEffectBattler = gBattlerTarget; + BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1); + MarkBattlerForControllerExec(gActiveBattler); + gBattlescriptCurrInstr = cmd->nextInstr; + } + else + { + gBattlescriptCurrInstr = cmd->failInstr; + } + return; + } + case VARIOUS_TRY_SET_STATUS2: + { + VARIOUS_ARGS(const u8 *failInstr); + u8 effect = 0; + u32 status2 = GetMaxMoveStatusEffect(gCurrentMove); + switch (status2) + { + case STATUS2_CONFUSION: + if (CanBeConfused(gBattlerTarget)) + { + gBattleMons[gBattlerTarget].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gBattleCommunication[MULTIUSE_STATE] = 1; + effect++; + } + break; + case STATUS2_INFATUATION: + { + u8 atkGender = GetGenderFromSpeciesAndPersonality(gBattleMons[gBattlerAttacker].species, gBattleMons[gBattlerAttacker].personality); + u8 defGender = GetGenderFromSpeciesAndPersonality(gBattleMons[gBattlerTarget].species, gBattleMons[gBattlerTarget].personality); + if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_INFATUATION) + && gBattleMons[gBattlerTarget].ability != ABILITY_OBLIVIOUS + && !IsAbilityOnSide(gBattlerTarget, ABILITY_AROMA_VEIL) + && atkGender != defGender + && atkGender != MON_GENDERLESS + && defGender != MON_GENDERLESS) + { + gBattleMons[gBattlerTarget].status2 |= STATUS2_INFATUATED_WITH(gBattlerAttacker); + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattleCommunication[MULTIUSE_STATE] = 2; + effect++; + } + break; + } + case STATUS2_ESCAPE_PREVENTION: + if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION)) + { + gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; + gBattleCommunication[MULTISTRING_CHOOSER] = 2; + effect++; + } + break; + case STATUS2_TORMENT: + if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT) + && !IsAbilityOnSide(gBattlerTarget, ABILITY_AROMA_VEIL)) + { + gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT; + gDisableStructs[gBattlerTarget].tormentTimer = 4; // 3 turns excluding current turn + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + effect++; + } + break; + } + if (effect) + { + gEffectBattler = gBattlerTarget; + gBattlescriptCurrInstr = cmd->nextInstr; + } + else + { + gBattlescriptCurrInstr = cmd->failInstr; + } + return; + } } // End of switch (cmd->id) gBattlescriptCurrInstr = cmd->nextInstr; @@ -14342,7 +14456,9 @@ static void Cmd_settorment(void) } else { + // TODO: Torment does not affect Dynamaxed Pokemon and prints a failure string. gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT; + gDisableStructs[gBattlerTarget].tormentTimer = 0xF; // permanent gBattlescriptCurrInstr = cmd->nextInstr; } } diff --git a/src/battle_util.c b/src/battle_util.c index da150277ab..2af89f63ab 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2675,6 +2675,7 @@ enum ENDTURN_SLOW_START, ENDTURN_PLASMA_FISTS, ENDTURN_CUD_CHEW, + ENDTURN_TORMENT, ENDTURN_BATTLER_COUNT }; @@ -3222,6 +3223,16 @@ u8 DoBattlerEndTurnEffects(void) gDisableStructs[gActiveBattler].cudChew = TRUE; gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_TORMENT: + if (gDisableStructs[gActiveBattler].tormentTimer <= 4 + && --gDisableStructs[gActiveBattler].tormentTimer == 0) + { + gBattleMons[gActiveBattler].status2 &= ~STATUS2_TORMENT; + BattleScriptExecute(BattleScript_TormentEnds); + effect++; + } + gBattleStruct->turnEffectsTracker++; + break; case ENDTURN_BATTLER_COUNT: // done gBattleStruct->turnEffectsTracker = 0; gBattleStruct->turnEffectsBattlerId++;