Proper Roar handling in double battles

This commit is contained in:
DizzyEggg 2019-03-06 12:09:34 +01:00
parent fddb5159b4
commit 7a8f524bc5
6 changed files with 73 additions and 48 deletions

View File

@ -1597,6 +1597,11 @@
various \battler, VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS
.4byte \ptr
.endm
.macro jumpifroarfails ptr:req
various BS_ATTACKER, VARIOUS_JUMP_IF_ROAR_FAILS
.4byte \ptr
.endm
@ helpful macros
.macro setstatchanger stat:req, stages:req, down:req

View File

@ -2123,6 +2123,7 @@ BattleScript_EffectRoar::
attackcanceler
attackstring
ppreduce
jumpifroarfails BattleScript_ButItFailed
jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut
jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
@ -4967,18 +4968,9 @@ BattleScript_BideNoEnergyToAttack::
printstring STRINGID_PKMNUNLEASHEDENERGY
waitmessage 0x40
goto BattleScript_ButItFailed
BattleScript_SuccessForceOut::
attackanimation
waitanimation
switchoutabilities BS_TARGET
returntoball BS_TARGET
waitstate
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_TrainerBattleForceOut
setoutcomeonteleport BS_ATTACKER
finishaction
BattleScript_TrainerBattleForceOut::
BattleScript_RoarSuccessSwitch::
call BattleScript_RoarSuccessRet
getswitchedmondata BS_TARGET
switchindataupdate BS_TARGET
switchinanim BS_TARGET, FALSE
@ -4986,6 +4978,19 @@ BattleScript_TrainerBattleForceOut::
printstring STRINGID_PKMNWASDRAGGEDOUT
switchineffects BS_TARGET
goto BattleScript_MoveEnd
BattleScript_RoarSuccessEndBattle::
call BattleScript_RoarSuccessRet
setoutcomeonteleport BS_ATTACKER
finishaction
BattleScript_RoarSuccessRet:
attackanimation
waitanimation
switchoutabilities BS_TARGET
returntoball BS_TARGET
waitstate
return
BattleScript_MistProtected::
pause 0x20

View File

@ -53,7 +53,8 @@ extern const u8 BattleScript_LeechSeedTurnDrain[];
extern const u8 BattleScript_BideStoringEnergy[];
extern const u8 BattleScript_BideAttack[];
extern const u8 BattleScript_BideNoEnergyToAttack[];
extern const u8 BattleScript_SuccessForceOut[];
extern const u8 BattleScript_RoarSuccessSwitch[];
extern const u8 BattleScript_RoarSuccessEndBattle[];
extern const u8 BattleScript_MistProtected[];
extern const u8 BattleScript_RageIsBuilding[];
extern const u8 BattleScript_MoveUsedIsDisabled[];

View File

@ -38,6 +38,8 @@
#define WEATHER_HAS_EFFECT ((!ABILITY_ON_FIELD(ABILITY_CLOUD_NINE) && !ABILITY_ON_FIELD(ABILITY_AIR_LOCK)))
#define IS_WHOLE_SIDE_ALIVE(battler)((IsBattlerAlive(battler) && IsBattlerAlive(BATTLE_PARTNER(battler))))
u8 GetBattlerForBattleScript(u8 caseId);
void PressurePPLose(u8 target, u8 attacker, u16 move);
void PressurePPLoseOnUsingPerishSong(u8 attacker);

View File

@ -138,6 +138,7 @@
#define VARIOUS_SPECTRAL_THIEF 75
#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76
#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77
#define VARIOUS_JUMP_IF_ROAR_FAILS 78
// atk80, dmg manipulation
#define ATK80_DMG_CHANGE_SIGN 0

View File

@ -6368,6 +6368,21 @@ static void atk76_various(void)
switch (gBattlescriptCurrInstr[2])
{
// Roar will fail in a double wild battle when used by the player against one of the two alive wild mons.
// Also when an opposing wild mon uses it againt its partner.
case VARIOUS_JUMP_IF_ROAR_FAILS:
if (WILD_DOUBLE_BATTLE
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER
&& GetBattlerSide(gBattlerTarget) == B_SIDE_OPPONENT
&& IS_WHOLE_SIDE_ALIVE(gBattlerTarget))
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else if (WILD_DOUBLE_BATTLE
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
&& GetBattlerSide(gBattlerTarget) == B_SIDE_OPPONENT)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else
gBattlescriptCurrInstr += 7;
return;
case VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS:
if ((gStatuses3[gActiveBattler] & (STATUS3_SEMI_INVULNERABLE))
|| BATTLER_MAX_HP(gActiveBattler)
@ -8027,27 +8042,6 @@ static void atk8E_initmultihitstring(void)
gBattlescriptCurrInstr++;
}
static bool8 TryDoForceSwitchOut(void)
{
if (gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
{
*(gBattleStruct->field_58 + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget];
}
else
{
u16 random = Random() & 0xFF;
if ((u32)((random * (gBattleMons[gBattlerAttacker].level + gBattleMons[gBattlerTarget].level) >> 8) + 1) <= (gBattleMons[gBattlerTarget].level / 4))
{
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
return FALSE;
}
*(gBattleStruct->field_58 + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget];
}
gBattlescriptCurrInstr = BattleScript_SuccessForceOut;
return TRUE;
}
static void atk8F_forcerandomswitch(void)
{
s32 i;
@ -8060,14 +8054,26 @@ static void atk8F_forcerandomswitch(void)
s32 validMons = 0;
s32 minNeeded = 0;
if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER))
// Swapping pokemon happens in:
// trainer battles
// wild double battles when an opposing pokemon uses it against one of the two alive player mons
// wild double battle when a player pokemon uses it against its partner
if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|| (WILD_DOUBLE_BATTLE
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
&& GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER
&& IS_WHOLE_SIDE_ALIVE(gBattlerTarget))
|| (WILD_DOUBLE_BATTLE
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER
&& GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
)
{
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
party = gPlayerParty;
else
party = gEnemyParty;
if (BATTLE_TWO_VS_ONE_OPPONENT && (gBattlerTarget & BIT_SIDE) == B_SIDE_OPPONENT)
if (BATTLE_TWO_VS_ONE_OPPONENT && GetBattlerSide(gBattlerTarget) == B_SIDE_OPPONENT)
{
firstMonId = 0;
lastMonId = 6;
@ -8175,19 +8181,20 @@ static void atk8F_forcerandomswitch(void)
}
else
{
if (TryDoForceSwitchOut())
*(gBattleStruct->field_58 + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget];
gBattlescriptCurrInstr = BattleScript_RoarSuccessSwitch;
do
{
do
{
i = Random() % monsCount;
i += firstMonId;
}
while (i == battler2PartyId
|| i == battler1PartyId
|| GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE
|| GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE
|| GetMonData(&party[i], MON_DATA_HP) == 0);
i = Random() % monsCount;
i += firstMonId;
}
while (i == battler2PartyId
|| i == battler1PartyId
|| GetMonData(&party[i], MON_DATA_SPECIES) == SPECIES_NONE
|| GetMonData(&party[i], MON_DATA_IS_EGG) == TRUE
|| GetMonData(&party[i], MON_DATA_HP) == 0);
*(gBattleStruct->monToSwitchIntoId + gBattlerTarget) = i;
if (!IsMultiBattle())
@ -8208,7 +8215,11 @@ static void atk8F_forcerandomswitch(void)
}
else
{
TryDoForceSwitchOut();
// In normal wild doubles, Roar will always fail if the user's level is less than the target's.
if (gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
gBattlescriptCurrInstr = BattleScript_RoarSuccessEndBattle;
else
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
}
}