diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 49410fd02..7bbdc829d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1006,14 +1006,14 @@ .byte 0xbb .endm - .macro maxattackhalvehp param0:req + .macro halvehp failInstr:req .byte 0xbc - .4byte \param0 + .4byte \failInstr .endm - .macro copyfoestats param0:req + .macro copyfoestats unused:req .byte 0xbd - .4byte \param0 + .4byte \unused .endm .macro rapidspinfree @@ -1024,36 +1024,53 @@ .byte 0xbf .endm - .macro recoverbasedonsunlight param0:req + .macro recoverbasedonsunlight failInstr:req .byte 0xc0 - .4byte \param0 + .4byte \failInstr .endm - .macro hiddenpowercalc + .macro setstickyweb failInstr:req .byte 0xc1 + .4byte \failInstr .endm .macro selectfirstvalidtarget .byte 0xc2 .endm - .macro trysetfutureattack param0:req + .macro trysetfutureattack failInstr:req .byte 0xc3 - .4byte \param0 + .4byte \failInstr .endm - .macro trydobeatup param0:req, param1:req + .macro trydobeatup endInstr, failInstr .byte 0xc4 - .4byte \param0 - .4byte \param1 + .4byte \endInstr + .4byte \failInstr .endm - .macro setsemiinvulnerablebit + .macro setsemiinvulnerablebit clear=FALSE .byte 0xc5 + .byte \clear .endm .macro clearsemiinvulnerablebit + setsemiinvulnerablebit TRUE + .endm + + .macro tryfiretwoturnmovenowbyeffect battler:req, checkChargeTurnEffects:req, jumpInstr:req .byte 0xc6 + .byte \battler + .byte \checkChargeTurnEffects + .4byte \jumpInstr + .endm + + .macro tryfiretwoturnmovewithoutcharging battler:req, jumpInstr:req + tryfiretwoturnmovenowbyeffect \battler, TRUE, \jumpInstr + .endm + + .macro tryfiretwoturnmoveaftercharging battler:req, jumpInstr:req + tryfiretwoturnmovenowbyeffect \battler, FALSE, \jumpInstr .endm .macro setminimize @@ -1064,9 +1081,9 @@ .byte 0xc8 .endm - .macro trymemento ptr:req + .macro trymemento failInstr:req .byte 0xc9 - .4byte \ptr + .4byte \failInstr .endm .macro setforcedtarget diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index c90f0c5fc..a9447b09d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1425,11 +1425,6 @@ BattleScript_EffectMoonlight:: recoverbasedonsunlight BattleScript_AlreadyAtFullHp goto BattleScript_PresentHealTarget -BattleScript_EffectHiddenPower:: - attackcanceler - hiddenpowercalc - goto BattleScript_HitFromAccCheck - BattleScript_EffectRainDance:: attackcanceler attackstring @@ -1466,12 +1461,16 @@ BattleScript_EffectBellyDrum:: attackcanceler attackstring ppreduce - maxattackhalvehp BattleScript_ButItFailed + jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed + halvehp BattleScript_ButItFailed orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE attackanimation waitanimation healthbarupdate BS_ATTACKER datahpupdate BS_ATTACKER + playstatchangeanimation BS_ATTACKER, BIT_ATK, STAT_CHANGE_BY_TWO + setstatchanger STAT_ATK, MAX_STAT_STAGE, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_MoveEnd printstring STRINGID_PKMNCUTHPMAXEDATTACK waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -1604,6 +1603,15 @@ BattleScript_PrintAbilityMadeIneffective:: BattleScript_EffectBeatUp:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE +.if B_BEAT_UP >= GEN_5 + attackstring + ppreduce + critcalc + damagecalc + adjustdamage + trydobeatup + goto BattleScript_HitFromAtkAnimation +.else attackstring pause B_WAIT_TIME_SHORT ppreduce @@ -1613,7 +1621,7 @@ BattleScript_BeatUpLoop:: trydobeatup BattleScript_BeatUpEnd, BattleScript_ButItFailed printstring STRINGID_PKMNATTACK critcalc - jumpifbyte CMP_NOT_EQUAL, gCritMultiplier, 2, BattleScript_BeatUpAttack + jumpifbyte CMP_NOT_EQUAL, gIsCriticalHit, TRUE, BattleScript_BeatUpAttack manipulatedamage DMG_DOUBLED BattleScript_BeatUpAttack:: adjustdamage @@ -1633,23 +1641,7 @@ BattleScript_BeatUpAttack:: goto BattleScript_BeatUpLoop BattleScript_BeatUpEnd:: end - -BattleScript_SecondTurnSemiInvulnerable:: - attackcanceler - setmoveeffect MOVE_EFFECT_CHARGING - setbyte sB_ANIM_TURN, 1 - clearstatusfromeffect BS_ATTACKER - orword gHitMarker, HITMARKER_NO_PPDEDUCT - jumpifnotmove MOVE_BOUNCE, BattleScript_SemiInvulnerableTryHit - setmoveeffect MOVE_EFFECT_PARALYSIS -BattleScript_SemiInvulnerableTryHit:: - accuracycheck BattleScript_SemiInvulnerableMiss, ACC_CURR_MOVE - clearsemiinvulnerablebit - goto BattleScript_HitFromAtkString - -BattleScript_SemiInvulnerableMiss:: - clearsemiinvulnerablebit - goto BattleScript_PrintMoveMissed +.endif BattleScript_EffectDefenseCurl:: attackcanceler @@ -3126,6 +3118,26 @@ BattleScript_SpikesFree:: waitmessage B_WAIT_TIME_LONG return +BattleScript_ToxicSpikesFree:: + printstring STRINGID_PKMNBLEWAWAYTOXICSPIKES + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_StickyWebFree:: + printstring STRINGID_PKMNBLEWAWAYSTICKYWEB + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_StealthRockFree:: + printstring STRINGID_PKMNBLEWAWAYSTEALTHROCK + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_SteelsurgeFree:: + printstring STRINGID_PKMNBLEWAWAYSHARPSTEEL + waitmessage B_WAIT_TIME_LONG + return + BattleScript_MonTookFutureAttack:: printstring STRINGID_PKMNTOOKATTACK waitmessage B_WAIT_TIME_LONG diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index f781867cd..e117a5df6 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -45,6 +45,7 @@ u32 IsAbilityStatusProtected(u32 battler); bool32 TryResetBattlerStatChanges(u8 battler); bool32 CanBattlerSwitch(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); +u16 GetNaturePowerMove(void); extern void (* const gBattleScriptingCommandsTable[])(void); extern const struct StatFractions gAccuracyStageRatios[]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 5985f0b0e..14b4df5d9 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -367,7 +367,6 @@ extern const u8 BattleScript_EffectHit[]; extern const u8 BattleScript_EffectMorningSun[]; extern const u8 BattleScript_EffectSynthesis[]; extern const u8 BattleScript_EffectMoonlight[]; -extern const u8 BattleScript_EffectHiddenPower[]; extern const u8 BattleScript_EffectRainDance[]; extern const u8 BattleScript_EffectSunnyDay[]; extern const u8 BattleScript_EffectDefenseUpHit[]; @@ -623,7 +622,6 @@ extern const u8 BattleScript_DmgHazardsOnFaintedBattler[]; extern const u8 BattleScript_PerishSongTakesLife[]; extern const u8 BattleScript_PerishSongCountGoesDown[]; extern const u8 BattleScript_AllStatsUp[]; -extern const u8 BattleScript_RapidSpinAway[]; extern const u8 BattleScript_WrapFree[]; extern const u8 BattleScript_LeechSeedFree[]; extern const u8 BattleScript_SpikesFree[]; diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 95275b7fa..feade1a18 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -567,8 +567,12 @@ #define STRINGID_SEVERELY 564 #define STRINGID_CLEARAMULETWONTLOWERSTATS 565 #define STRINGID_CELEBRATEMESSAGE 566 +#define STRINGID_PKMNBLEWAWAYTOXICSPIKES 567 +#define STRINGID_PKMNBLEWAWAYSTICKYWEB 568 +#define STRINGID_PKMNBLEWAWAYSTEALTHROCK 569 +#define STRINGID_PKMNBLEWAWAYSHARPSTEEL 570 -#define BATTLESTRINGS_COUNT 567 +#define BATTLESTRINGS_COUNT 571 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/src/battle_message.c b/src/battle_message.c index 1b1a3560e..1dd553cb6 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -696,6 +696,10 @@ static const u8 sText_drastically[] = _("drastically "); static const u8 sText_severely[] = _("severely "); static const u8 sText_ClearAmuletWontLowerStats[] = _("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM} prevents\nits stats from being lowered!"); static const u8 sText_CelebrateMessage[] = _("Congratulations, {B_PLAYER_NAME}!"); +static const u8 sText_PkmnBlewAwayToxicSpikes[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nToxic Spikes!"); +static const u8 sText_PkmnBlewAwayStickyWeb[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nSticky Web!"); +static const u8 sText_PkmnBlewAwayStealthRock[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nStealth Rock!"); +static const u8 sText_PkmnBlewAwaySharpSteel[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nsharp steel!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_START] = { @@ -1254,6 +1258,10 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_ST [STRINGID_SEVERELY - BATTLESTRINGS_TABLE_START] = sText_severely, [STRINGID_CLEARAMULETWONTLOWERSTATS - BATTLESTRINGS_TABLE_START] = sText_ClearAmuletWontLowerStats, [STRINGID_CELEBRATEMESSAGE - BATTLESTRINGS_TABLE_START] = sText_CelebrateMessage, + [STRINGID_PKMNBLEWAWAYTOXICSPIKES - BATTLESTRINGS_TABLE_START] = sText_PkmnBlewAwayToxicSpikes, + [STRINGID_PKMNBLEWAWAYSTICKYWEB - BATTLESTRINGS_TABLE_START] = sText_PkmnBlewAwayStickyWeb, + [STRINGID_PKMNBLEWAWAYSTEALTHROCK - BATTLESTRINGS_TABLE_START] = sText_PkmnBlewAwayStealthRock, + [STRINGID_PKMNBLEWAWAYSHARPSTEEL - BATTLESTRINGS_TABLE_START] = sText_PkmnBlewAwaySharpSteel, }; const u16 gTrainerUsedItemStringIds[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 547512c8c..9006f659c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -529,17 +529,17 @@ static void Cmd_setsafeguard(void); static void Cmd_magnitudedamagecalculation(void); static void Cmd_jumpifnopursuitswitchdmg(void); static void Cmd_setsunny(void); -static void Cmd_maxattackhalvehp(void); +static void Cmd_halvehp(void); static void Cmd_copyfoestats(void); static void Cmd_rapidspinfree(void); static void Cmd_setdefensecurlbit(void); static void Cmd_recoverbasedonsunlight(void); -static void Cmd_hiddenpowercalc(void); +static void Cmd_setstickyweb(void); static void Cmd_selectfirstvalidtarget(void); static void Cmd_trysetfutureattack(void); static void Cmd_trydobeatup(void); static void Cmd_setsemiinvulnerablebit(void); -static void Cmd_clearsemiinvulnerablebit(void); +static void Cmd_tryfiretwoturnmovenowbyeffect(void); static void Cmd_setminimize(void); static void Cmd_sethail(void); static void Cmd_trymemento(void); @@ -781,23 +781,23 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_magnitudedamagecalculation, //0xB9 // done Cmd_jumpifnopursuitswitchdmg, //0xBA // done Cmd_setsunny, //0xBB // done - Cmd_maxattackhalvehp, //0xBC - Cmd_copyfoestats, //0xBD - Cmd_rapidspinfree, //0xBE - Cmd_setdefensecurlbit, //0xBF - Cmd_recoverbasedonsunlight, //0xC0 - Cmd_hiddenpowercalc, //0xC1 - Cmd_selectfirstvalidtarget, //0xC2 - Cmd_trysetfutureattack, //0xC3 - Cmd_trydobeatup, //0xC4 - Cmd_setsemiinvulnerablebit, //0xC5 - Cmd_clearsemiinvulnerablebit, //0xC6 - Cmd_setminimize, //0xC7 - Cmd_sethail, //0xC8 - Cmd_trymemento, //0xC9 - Cmd_setforcedtarget, //0xCA + Cmd_halvehp, //0xBC // done + Cmd_copyfoestats, //0xBD // done + Cmd_rapidspinfree, //0xBE // done + Cmd_setdefensecurlbit, //0xBF // done + Cmd_recoverbasedonsunlight, //0xC0 // done + Cmd_setstickyweb, //0xC1 // done + Cmd_selectfirstvalidtarget, //0xC2 // done + Cmd_trysetfutureattack, //0xC3 // done + Cmd_trydobeatup, //0xC4 // done + Cmd_setsemiinvulnerablebit, //0xC5 // done + Cmd_tryfiretwoturnmovenowbyeffect, //0xC6 // done + Cmd_setminimize, //0xC7 // done + Cmd_sethail, //0xC8 // done + Cmd_trymemento, //0xC9 // done + Cmd_setforcedtarget, //0xCA // done Cmd_setcharge, //0xCB // done - Cmd_callterrainattack, //0xCC + Cmd_callterrainattack, //0xCC // done Cmd_cureifburnedparalysedorpoisoned, //0xCD Cmd_settorment, //0xCE Cmd_jumpifnodamage, //0xCF @@ -13868,32 +13868,39 @@ static void Cmd_setsunny(void) } // Belly Drum -static void Cmd_maxattackhalvehp(void) +static void Cmd_halvehp(void) { + CMD_ARGS(const u8 *failInstr); + + // TODO: Dynamax + // u32 halfHp = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; u32 halfHp = gBattleMons[gBattlerAttacker].maxHP / 2; - if (!(gBattleMons[gBattlerAttacker].maxHP / 2)) + // TODO: Dynamax + if (/* !(GetNonDynamaxMaxHP(gBattlerAttacker) / 2) */ !(gBattleMons[gBattlerAttacker].maxHP / 2)) halfHp = 1; - if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE - && gBattleMons[gBattlerAttacker].hp > halfHp) + if (gBattleMons[gBattlerAttacker].hp > halfHp) { - gBattleMons[gBattlerAttacker].statStages[STAT_ATK] = MAX_STAT_STAGE; + // TODO: Dynamax + // gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = cmd->nextInstr; } else { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } } // Psych Up static void Cmd_copyfoestats(void) { + CMD_ARGS(const u8 *unused); + s32 i; for (i = 0; i < NUM_BATTLE_STATS; i++) @@ -13901,23 +13908,21 @@ static void Cmd_copyfoestats(void) gBattleMons[gBattlerAttacker].statStages[i] = gBattleMons[gBattlerTarget].statStages[i]; } - gBattlescriptCurrInstr += 5; // Has an unused jump ptr(possibly for a failed attempt) parameter. + gBattlescriptCurrInstr = cmd->nextInstr; // Has an unused jump ptr(possibly for a failed attempt) parameter. } static void Cmd_rapidspinfree(void) { + CMD_ARGS(); + + u8 atkSide = GetBattlerSide(gBattlerAttacker); + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_WRAPPED) { gBattleScripting.battler = gBattlerTarget; gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_WRAPPED; gBattlerTarget = *(gBattleStruct->wrappedBy + gBattlerAttacker); - - gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN; - gBattleTextBuff1[1] = B_BUFF_MOVE; - gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gBattlerAttacker * 2 + 0); - gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gBattlerAttacker * 2 + 1); - gBattleTextBuff1[4] = B_BUFF_EOS; - + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[gBattlerAttacker]); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_WrapFree; } @@ -13928,130 +13933,184 @@ static void Cmd_rapidspinfree(void) BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_LeechSeedFree; } - else if (gSideStatuses[GetBattlerSide(gBattlerAttacker)] & SIDE_STATUS_SPIKES) + else if (gSideStatuses[atkSide] & SIDE_STATUS_SPIKES) { - gSideStatuses[GetBattlerSide(gBattlerAttacker)] &= ~SIDE_STATUS_SPIKES; - gSideTimers[GetBattlerSide(gBattlerAttacker)].spikesAmount = 0; + gSideStatuses[atkSide] &= ~SIDE_STATUS_SPIKES; + gSideTimers[atkSide].spikesAmount = 0; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_SpikesFree; } + else if (gSideStatuses[atkSide] & SIDE_STATUS_TOXIC_SPIKES) + { + gSideStatuses[atkSide] &= ~SIDE_STATUS_TOXIC_SPIKES; + gSideTimers[atkSide].toxicSpikesAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ToxicSpikesFree; + } + else if (gSideStatuses[atkSide] & SIDE_STATUS_STICKY_WEB) + { + gSideStatuses[atkSide] &= ~SIDE_STATUS_STICKY_WEB; + gSideTimers[atkSide].stickyWebAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StickyWebFree; + } + else if (gSideStatuses[atkSide] & SIDE_STATUS_STEALTH_ROCK) + { + gSideStatuses[atkSide] &= ~SIDE_STATUS_STEALTH_ROCK; + gSideTimers[atkSide].stealthRockAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StealthRockFree; + } + else if (gSideStatuses[atkSide] & SIDE_STATUS_STEELSURGE) + { + gSideStatuses[atkSide] &= ~SIDE_STATUS_STEELSURGE; + gSideTimers[atkSide].steelsurgeAmount = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SteelsurgeFree; + } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; } } static void Cmd_setdefensecurlbit(void) { + CMD_ARGS(); + gBattleMons[gBattlerAttacker].status2 |= STATUS2_DEFENSE_CURL; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_recoverbasedonsunlight(void) { - gBattlerTarget = gBattlerAttacker; + CMD_ARGS(const u8 *failInstr); + gBattlerTarget = gBattlerAttacker; if (gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP) { - if (gBattleWeather == 0 || !WEATHER_HAS_EFFECT) - gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2; - else if (gBattleWeather & B_WEATHER_SUN) - gBattleMoveDamage = 20 * gBattleMons[gBattlerAttacker].maxHP / 30; - else // not sunny weather - gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4; + if (gCurrentMove == MOVE_SHORE_UP) + { + if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM) + { + // TODO: Dynamax + // gBattleMoveDamage = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; + gBattleMoveDamage = 20 * gBattleMons[gBattlerAttacker].maxHP / 30; + } + else + { + // TODO: Dynamax + // gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2; + } + } + else + { + if (!(gBattleWeather & B_WEATHER_ANY) || !WEATHER_HAS_EFFECT || GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA) + { + // TODO: Dynamax + // gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2; + } + else if (gBattleWeather & B_WEATHER_SUN) + { + // TODO: Dynamax + // gBattleMoveDamage = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; + gBattleMoveDamage = 20 * gBattleMons[gBattlerAttacker].maxHP / 30; + } + else // not sunny weather + { + // TODO: Dynamax + // gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 4; + } + } if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; gBattleMoveDamage *= -1; - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = cmd->nextInstr; } else { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } } -static void Cmd_hiddenpowercalc(void) +static void Cmd_setstickyweb(void) { - s32 powerBits, typeBits; + CMD_ARGS(const u8 *failInstr); - powerBits = ((gBattleMons[gBattlerAttacker].hpIV & 2) >> 1) - | ((gBattleMons[gBattlerAttacker].attackIV & 2) << 0) - | ((gBattleMons[gBattlerAttacker].defenseIV & 2) << 1) - | ((gBattleMons[gBattlerAttacker].speedIV & 2) << 2) - | ((gBattleMons[gBattlerAttacker].spAttackIV & 2) << 3) - | ((gBattleMons[gBattlerAttacker].spDefenseIV & 2) << 4); - typeBits = ((gBattleMons[gBattlerAttacker].hpIV & 1) << 0) - | ((gBattleMons[gBattlerAttacker].attackIV & 1) << 1) - | ((gBattleMons[gBattlerAttacker].defenseIV & 1) << 2) - | ((gBattleMons[gBattlerAttacker].speedIV & 1) << 3) - | ((gBattleMons[gBattlerAttacker].spAttackIV & 1) << 4) - | ((gBattleMons[gBattlerAttacker].spDefenseIV & 1) << 5); + u8 targetSide = GetBattlerSide(gBattlerTarget); - gDynamicBasePower = (40 * powerBits) / 63 + 30; - - // Subtract 3 instead of 1 below because 2 types are excluded (TYPE_NORMAL and TYPE_MYSTERY) - // The final + 1 skips past Normal, and the following conditional skips TYPE_MYSTERY - gBattleStruct->dynamicMoveType = ((NUMBER_OF_MON_TYPES - 3) * typeBits) / 63 + 1; - if (gBattleStruct->dynamicMoveType >= TYPE_MYSTERY) - gBattleStruct->dynamicMoveType++; - gBattleStruct->dynamicMoveType |= F_DYNAMIC_TYPE_IGNORE_PHYSICALITY | F_DYNAMIC_TYPE_SET; - - gBattlescriptCurrInstr++; + if (gSideStatuses[targetSide] & SIDE_STATUS_STICKY_WEB) + { + gBattlescriptCurrInstr = cmd->failInstr; + } + else + { + gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB; + gSideTimers[targetSide].stickyWebBattlerId = gBattlerAttacker; // For Mirror Armor + gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side + gSideTimers[targetSide].stickyWebAmount = 1; + gBattlescriptCurrInstr = cmd->nextInstr; + } } static void Cmd_selectfirstvalidtarget(void) { + CMD_ARGS(); + for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { - if (gBattlerTarget == gBattlerAttacker) + if (gBattlerTarget == gBattlerAttacker && !(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER)) continue; - if (!(gAbsentBattlerFlags & gBitTable[gBattlerTarget])) + if (IsBattlerAlive(gBattlerTarget)) break; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_trysetfutureattack(void) { + CMD_ARGS(const u8 *failInstr); + if (gWishFutureKnock.futureSightCounter[gBattlerTarget] != 0) { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } else { + gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK; gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove; - gWishFutureKnock.futureSightAttacker[gBattlerTarget] = gBattlerAttacker; + gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; + gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker]; gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3; - gWishFutureKnock.futureSightDmg[gBattlerTarget] = CalculateBaseDamageOld(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove, - gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)], 0, - 0, gBattlerAttacker, gBattlerTarget); - - if (gProtectStructs[gBattlerAttacker].helpingHand) - gWishFutureKnock.futureSightDmg[gBattlerTarget] = gWishFutureKnock.futureSightDmg[gBattlerTarget] * 15 / 10; if (gCurrentMove == MOVE_DOOM_DESIRE) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE; else gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FUTURE_SIGHT; - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = cmd->nextInstr; } } static void Cmd_trydobeatup(void) { - struct Pokemon *party; +#if B_BEAT_UP >= GEN_5 + CMD_ARGS(); - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - party = gPlayerParty; - else - party = gEnemyParty; + gBattleStruct->beatUpSlot++; + gBattlescriptCurrInstr = cmd->nextInstr; +#else + CMD_ARGS(const u8 *endInstr, const u8 *failInstr); + struct Pokemon *party = GetBattlerParty(gBattlerAttacker); if (gBattleMons[gBattlerTarget].hp == 0) { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->endInstr; } else { @@ -14059,7 +14118,7 @@ static void Cmd_trydobeatup(void) for (;gBattleCommunication[0] < PARTY_SIZE; gBattleCommunication[0]++) { if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP) - && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES_OR_EGG) + && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE && GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG && !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS)) break; @@ -14068,7 +14127,7 @@ static void Cmd_trydobeatup(void) { PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattleCommunication[0]) - gBattlescriptCurrInstr += 9; + gBattlescriptCurrInstr = cmd->nextInstr; gBattleMoveDamage = gSpeciesInfo[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack; gBattleMoveDamage *= gMovesInfo[gCurrentMove].power; @@ -14081,101 +14140,130 @@ static void Cmd_trydobeatup(void) gBattleCommunication[0]++; } else if (beforeLoop != 0) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->endInstr; else - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 5); + gBattlescriptCurrInstr = cmd->failInstr; } +#endif } static void Cmd_setsemiinvulnerablebit(void) { - switch (gCurrentMove) + CMD_ARGS(bool8 clear); + + if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == TRUE) { - case MOVE_FLY: - case MOVE_BOUNCE: - gStatuses3[gBattlerAttacker] |= STATUS3_ON_AIR; - break; - case MOVE_DIG: - gStatuses3[gBattlerAttacker] |= STATUS3_UNDERGROUND; - break; - case MOVE_DIVE: - gStatuses3[gBattlerAttacker] |= STATUS3_UNDERWATER; - break; + u32 semiInvulnerableEffect = UNCOMPRESS_BITS(HIHALF(gMovesInfo[gCurrentMove].argument)); + if (cmd->clear) + gStatuses3[gBattlerAttacker] &= ~semiInvulnerableEffect; + else + gStatuses3[gBattlerAttacker] |= semiInvulnerableEffect; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_clearsemiinvulnerablebit(void) +static bool32 CheckIfCanFireTwoTurnMoveNow(u8 battler, bool8 checkChargeTurnEffects) { - switch (gCurrentMove) - { - case MOVE_FLY: - case MOVE_BOUNCE: - gStatuses3[gBattlerAttacker] &= ~STATUS3_ON_AIR; - break; - case MOVE_DIG: - gStatuses3[gBattlerAttacker] &= ~STATUS3_UNDERGROUND; - break; - case MOVE_DIVE: - gStatuses3[gBattlerAttacker] &= ~STATUS3_UNDERWATER; - break; - } + // Semi-invulnerable moves cannot skip their charge turn (except with Power Herb) + if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == TRUE) + return FALSE; - gBattlescriptCurrInstr++; + // If this move has charge turn effects, it must charge, activate them, then try to fire + if (checkChargeTurnEffects && MoveHasChargeTurnAdditionalEffect(gCurrentMove)) + return FALSE; + + // Insert custom conditions here + + // Certain two-turn moves may fire on the first turn in the right weather (Solar Beam, Electro Shot) + // By default, all two-turn moves have the option of adding weather to their argument + if (IsBattlerWeatherAffected(battler, HIHALF(gMovesInfo[gCurrentMove].argument))) + return TRUE; + + return FALSE; +} + +static void Cmd_tryfiretwoturnmovenowbyeffect(void) +{ + CMD_ARGS(u8 battler, bool8 checkChargeTurnEffects, const u8 *jumpInstr); + + if (CheckIfCanFireTwoTurnMoveNow(cmd->battler, cmd->checkChargeTurnEffects) == TRUE) + { + gBattleScripting.animTurn = 1; + gBattlescriptCurrInstr = cmd->jumpInstr; + } + else + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_setminimize(void) { + CMD_ARGS(); + if (gHitMarker & HITMARKER_OBEYS) gStatuses3[gBattlerAttacker] |= STATUS3_MINIMIZED; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_sethail(void) { - if (gBattleWeather & B_WEATHER_HAIL) + CMD_ARGS(); + + if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_HAIL, FALSE)) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; } else { - gBattleWeather = B_WEATHER_HAIL_TEMPORARY; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_HAIL; - gWishFutureKnock.weatherDuration = 5; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_trymemento(void) { - if (gBattleMons[gBattlerTarget].statStages[STAT_ATK] == MIN_STAT_STAGE + CMD_ARGS(const u8 *failInstr); + + if (B_MEMENTO_FAIL >= GEN_4 + && (gBattleCommunication[MISS_TYPE] == B_MSG_PROTECTED + || gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE + || IsBattlerProtected(gBattlerTarget, gCurrentMove) + || DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))) + { + // Failed, target was protected. + gBattlescriptCurrInstr = cmd->failInstr; + } + else if (B_MEMENTO_FAIL < GEN_4 + && gBattleMons[gBattlerTarget].statStages[STAT_ATK] == MIN_STAT_STAGE && gBattleMons[gBattlerTarget].statStages[STAT_SPATK] == MIN_STAT_STAGE && gBattleCommunication[MISS_TYPE] != B_MSG_PROTECTED) { // Failed, unprotected target already has minimum Attack and Special Attack. - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } else { // Success, drop user's HP bar to 0 gActiveBattler = gBattlerAttacker; - gBattleMoveDamage = gBattleMons[gActiveBattler].hp; + gBattleMoveDamage = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(BUFFER_A, INSTANT_HP_BAR_DROP); - MarkBattlerForControllerExec(gActiveBattler); - gBattlescriptCurrInstr += 5; + MarkBattlerForControllerExec(gBattlerAttacker); + gBattlescriptCurrInstr = cmd->nextInstr; } } // Follow Me static void Cmd_setforcedtarget(void) { - gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTimer = 1; - gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTarget = gBattlerAttacker; - gBattlescriptCurrInstr++; + CMD_ARGS(); + + gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer = 1; + gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTarget = gBattlerTarget; + gSideTimers[GetBattlerSide(gBattlerTarget)].followmePowder = gMovesInfo[gCurrentMove].powderMove; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_setcharge(void) @@ -14192,11 +14280,28 @@ static void Cmd_setcharge(void) // Nature Power static void Cmd_callterrainattack(void) { + CMD_ARGS(); + gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gCurrentMove = sNaturePowerMoves[gBattleTerrain]; + gCurrentMove = GetNaturePowerMove(); gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = cmd->nextInstr; +} + +u16 GetNaturePowerMove(void) +{ + if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + return MOVE_MOONBLAST; + else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + return MOVE_THUNDERBOLT; + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + return MOVE_ENERGY_BALL; + else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + return MOVE_PSYCHIC; + else if (sNaturePowerMoves[gBattleTerrain] == MOVE_NONE) + return MOVE_TRI_ATTACK; + return sNaturePowerMoves[gBattleTerrain]; } // Refresh