updated up to Cmd_callterrainattack

This commit is contained in:
cawtds
2024-05-02 10:42:24 +02:00
parent f8a1b4d4c6
commit dd1fba7834
7 changed files with 323 additions and 178 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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[];

View File

@@ -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[];

View File

@@ -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,

View File

@@ -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[] =

View File

@@ -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