EndTurnEffectsOrder Refactor

This commit is contained in:
AlexOn1ine 2025-02-03 14:12:30 +01:00
parent 37dd57b1b5
commit f2bd88a7f9
22 changed files with 2054 additions and 1818 deletions

View File

@ -1007,7 +1007,7 @@
.4byte \jumpInstr
.endm
.macro unused_bb
.macro tryhealingitem
.byte 0xbb
.endm
@ -1140,9 +1140,8 @@
.4byte \failInstr
.endm
.macro trywish turnNumber:req, failInstr:req
.macro trywish failInstr:req
.byte 0xd4
.byte \turnNumber
.4byte \failInstr
.endm

View File

@ -410,12 +410,12 @@ BattleScript_MoveEffectSaltCure::
return
BattleScript_SaltCureExtraDamage::
playanimation BS_TARGET, B_ANIM_SALT_CURE_DAMAGE, NULL
playanimation BS_ATTACKER, B_ANIM_SALT_CURE_DAMAGE, NULL
waitanimation
call BattleScript_HurtTarget_NoString
printstring STRINGID_TARGETISHURTBYSALTCURE
waitmessage B_WAIT_TIME_LONG
tryfaintmon BS_TARGET
tryfaintmon BS_ATTACKER
end2
BattleScript_HurtTarget_NoString:
@ -5044,7 +5044,7 @@ BattleScript_EffectWish::
attackcanceler
attackstring
ppreduce
trywish 0, BattleScript_ButItFailed
trywish BattleScript_ButItFailed
attackanimation
waitanimation
goto BattleScript_MoveEnd
@ -5842,13 +5842,13 @@ BattleScript_FogEnded_Ret::
return
BattleScript_IceBodyHeal::
call BattleScript_AbilityPopUpScripting
playanimation BS_SCRIPTING, B_ANIM_SIMPLE_HEAL
healthbarupdate BS_SCRIPTING
datahpupdate BS_SCRIPTING
call BattleScript_AbilityPopUp
playanimation BS_ATTACKER, B_ANIM_SIMPLE_HEAL
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
printstring STRINGID_ICEBODYHPGAIN
waitmessage B_WAIT_TIME_LONG
end2
end3
BattleScript_OverworldStatusStarts::
printfromtable gStartingStatusStringIds
@ -6674,7 +6674,6 @@ BattleScript_SelectingNotAllowedCurrentMoveInPalace::
goto BattleScript_SelectingUnusableMoveInPalace
BattleScript_WishComesTrue::
trywish 1, BattleScript_WishButFullHp
playanimation BS_TARGET, B_ANIM_WISH_HEAL
printstring STRINGID_PKMNWISHCAMETRUE
waitmessage B_WAIT_TIME_LONG
@ -6993,7 +6992,7 @@ BattleScript_CudChewActivates::
pause B_WAIT_TIME_SHORTEST
call BattleScript_AbilityPopUp
setbyte sBERRY_OVERRIDE, 1 @ override the requirements for eating berries
consumeberry BS_SCRIPTING, FALSE
consumeberry BS_ATTACKER, FALSE
setbyte sBERRY_OVERRIDE, 0
end3
@ -7145,6 +7144,7 @@ BattleScript_DoTurnDmg:
datahpupdate BS_ATTACKER
tryfaintmon BS_ATTACKER
checkteamslost BattleScript_DoTurnDmgEnd
tryhealingitem
BattleScript_DoTurnDmgEnd:
end2
@ -7608,6 +7608,37 @@ BattleScript_EmergencyExitWildNoPopUp::
finishaction
return
BattleScript_EmergencyExitEnd2::
pause 5
call BattleScript_AbilityPopUp
pause B_WAIT_TIME_LONG
playanimation BS_ATTACKER, B_ANIM_SLIDE_OFFSCREEN
waitanimation
openpartyscreen BS_ATTACKER, BattleScript_EmergencyExitRetEnd2
switchoutabilities BS_ATTACKER
waitstate
switchhandleorder BS_ATTACKER, 2
returntoball BS_TARGET, FALSE
getswitchedmondata BS_ATTACKER
switchindataupdate BS_ATTACKER
hpthresholds BS_ATTACKER
printstring STRINGID_SWITCHINMON
switchinanim BS_ATTACKER, FALSE, TRUE
waitstate
switchineffects BS_ATTACKER
BattleScript_EmergencyExitRetEnd2:
end2
BattleScript_EmergencyExitWildEnd2::
pause 5
call BattleScript_AbilityPopUp
pause B_WAIT_TIME_LONG
playanimation BS_ATTACKER, B_ANIM_SLIDE_OFFSCREEN
waitanimation
setoutcomeonteleport BS_ATTACKER
finishaction
end2
BattleScript_TraceActivates::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUpScripting
@ -7650,6 +7681,7 @@ BattleScript_PickupActivates::
call BattleScript_AbilityPopUp
printstring STRINGID_XFOUNDONEY
waitmessage B_WAIT_TIME_LONG
tryhealingitem
BattleScript_PickupActivatesEnd:
end3
@ -7659,6 +7691,7 @@ BattleScript_HarvestActivates::
call BattleScript_AbilityPopUp
printstring STRINGID_HARVESTBERRY
waitmessage B_WAIT_TIME_LONG
tryhealingitem
BattleScript_HarvestActivatesEnd:
end3
@ -9937,7 +9970,7 @@ BattleScript_DynamaxBegins::
BattleScript_DynamaxEnds::
flushtextbox
updatedynamax
playanimation BS_SCRIPTING, B_ANIM_FORM_CHANGE
playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE
waitanimation
end2

23
endturneffect_bak.c Normal file
View File

@ -0,0 +1,23 @@
bool32 HandleWishPerishSongOnTurnEnd(void)
{
gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE);
if ((gBattleTypeFlags & BATTLE_TYPE_ARENA)
&& gBattleStruct->arenaTurnCounter == 2
&& IsBattlerAlive(B_POSITION_PLAYER_LEFT) && IsBattlerAlive(B_POSITION_OPPONENT_LEFT))
{
s32 i;
// This seems to be a bug?
for (i = 0; i < 2; i++)
CancelMultiTurnMoves(i);
gBattlescriptCurrInstr = BattleScript_ArenaDoJudgment;
BattleScriptExecute(BattleScript_ArenaDoJudgment);
return TRUE;
}
gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE);
return FALSE;
}

View File

@ -104,7 +104,7 @@ struct DisableStruct
u8 telekinesisTimer;
u8 healBlockTimer;
u8 laserFocusTimer;
u8 throatChopTimer;
u16 throatChopTimer;
u8 wrapTurns;
u8 syrupBombTimer;
u8 tormentTimer:4; // used for G-Max Meltdown
@ -647,9 +647,9 @@ struct BattlerState
struct BattleStruct
{
struct BattlerState battlerState[MAX_BATTLERS_COUNT];
u8 turnEffectsTracker;
u8 eventBlockCounter;
u8 turnEffectsBattlerId;
u8 turnCountersTracker;
u8 endTurnEventsCounter;
u16 wrappedMove[MAX_BATTLERS_COUNT];
u16 moveTarget[MAX_BATTLERS_COUNT];
u32 expShareExpValue;
@ -721,8 +721,6 @@ struct BattleStruct
struct LinkBattlerHeader linkBattlerHeader;
struct BattleVideo battleVideo;
} multiBuffer;
u8 wishPerishSongState;
u8 wishPerishSongBattlerId;
u8 startingStatus:6; // status to apply at battle start. defined in constants/battle.h
u8 startingStatusDone:1;
u8 terrainDone:1;

View File

@ -0,0 +1,6 @@
#ifndef GUARD_BATTLE_END_TURN
#define GUARD_BATTLE_END_TURN
u32 DoEndTurnEffects(void);
#endif // GUARD_BATTLE_END_TURN

View File

@ -42,7 +42,7 @@ bool32 CanPoisonType(u8 battlerAttacker, u8 battlerTarget);
bool32 CanParalyzeType(u8 battlerAttacker, u8 battlerTarget);
bool32 CanUseLastResort(u8 battlerId);
u32 IsFlowerVeilProtected(u32 battler);
u32 IsLeafGuardProtected(u32 battler);
u32 IsLeafGuardProtected(u32 battler, u32 ability);
bool32 IsShieldsDownProtected(u32 battler);
u32 IsAbilityStatusProtected(u32 battler);
bool32 TryResetBattlerStatChanges(u8 battler);

View File

@ -101,6 +101,7 @@ extern const u8 BattleScript_SelectingTormentedMoveInPalace[];
extern const u8 BattleScript_SelectingNotAllowedMoveTaunt[];
extern const u8 BattleScript_MoveUsedIsTaunted[];
extern const u8 BattleScript_SelectingNotAllowedMoveTauntInPalace[];
extern const u8 BattleScript_WishButFullHp[];
extern const u8 BattleScript_WishComesTrue[];
extern const u8 BattleScript_IngrainTurnHeal[];
extern const u8 BattleScript_AtkDefDown[];
@ -387,6 +388,8 @@ extern const u8 BattleScript_EmergencyExit[];
extern const u8 BattleScript_EmergencyExitNoPopUp[];
extern const u8 BattleScript_EmergencyExitWild[];
extern const u8 BattleScript_EmergencyExitWildNoPopUp[];
extern const u8 BattleScript_EmergencyExitEnd2[];
extern const u8 BattleScript_EmergencyExitWildEnd2[];
extern const u8 BattleScript_CheekPouchActivates[];
extern const u8 BattleScript_TotemVar[];
extern const u8 BattleScript_TotemFlaredToLife[];

View File

@ -73,6 +73,7 @@ enum ItemCaseId
ITEMEFFECT_ON_SWITCH_IN,
ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN,
ITEMEFFECT_NORMAL,
ITEMEFFECT_TRY_HEALING,
ITEMEFFECT_MOVE_END,
ITEMEFFECT_KINGSROCK,
ITEMEFFECT_TARGET,
@ -174,6 +175,8 @@ enum SleepClauseBlock
};
void HandleAction_ThrowBall(void);
u32 GetCurrentBattleWeather(void);
u32 EndOrConinueWeather(void);
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
void HandleAction_UseMove(void);
void HandleAction_Switch(void);
@ -206,10 +209,8 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler);
u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check);
bool32 AreAllMovesUnusable(u32 battler);
u8 GetImprisonedMovesCount(u32 battler, u16 move);
u8 DoFieldEndTurnEffects(void);
s32 GetDrainedBigRootHp(u32 battler, s32 hp);
u8 DoBattlerEndTurnEffects(void);
bool32 HandleWishPerishSongOnTurnEnd(void);
u32 DoEndTurnEffects(void);
bool32 HandleFaintedMonActions(void);
void TryClearRageAndFuryCutter(void);
u32 AtkCanceller_MoveSuccessOrder(void);
@ -327,6 +328,7 @@ bool32 CanBeConfused(u32 battler);
bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag);
u32 GetBattlerAffectionHearts(u32 battler);
void TryToRevertMimicryAndFlags(void);
bool32 BattleArenaTurnEnd(void);
u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc);
bool32 ChangeTypeBasedOnTerrain(u32 battler);
void RemoveConfusionStatus(u32 battler);

View File

@ -6,7 +6,7 @@
// still has them in the ROM. This is because the developers forgot
// to define NDEBUG before release, however this has been changed as
// Ruby's actual debug build does not use the AGBPrint features.
#define NDEBUG
// #define NDEBUG
// To enable printf debugging, comment out "#define NDEBUG". This allows
// the various AGBPrint functions to be used. (See include/gba/isagbprint.h).

View File

@ -533,9 +533,6 @@ enum BattleWeather
#define HANDLE_TYPE_PRIMAL_REVERSION 1
#define HANDLE_TYPE_ULTRA_BURST 2
// Constants for Torment
#define PERMANENT_TORMENT 0xF
// Constants for B_VAR_STARTING_STATUS
// Timer value controlled by B_VAR_STARTING_STATUS_TIMER
enum StartingStatus

View File

@ -1058,7 +1058,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// the following checks apply to any target (including user)
// throat chop check
if (gDisableStructs[battlerAtk].throatChopTimer && IsSoundMove(move))
if (gDisableStructs[battlerAtk].throatChopTimer > gBattleTurnCounter && IsSoundMove(move))
return 0; // Can't even select move at all
// heal block check
if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(battlerAtk, move))
@ -2463,7 +2463,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_EMBARGO:
if (aiData->abilities[battlerDef] == ABILITY_KLUTZ
|| gFieldStatuses & STATUS_FIELD_MAGIC_ROOM
|| gDisableStructs[battlerDef].embargoTimer != 0
|| gStatuses3[battlerDef] & STATUS3_EMBARGO
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;
@ -2481,7 +2481,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_HEAL_BLOCK:
if (gDisableStructs[battlerDef].healBlockTimer != 0
if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;

View File

@ -178,7 +178,7 @@ void ActivateDynamax(u32 battler)
// Set appropriate use flags.
SetActiveGimmick(battler, GIMMICK_DYNAMAX);
SetGimmickAsActivated(battler, GIMMICK_DYNAMAX);
gBattleStruct->dynamax.dynamaxTurns[battler] = DYNAMAX_TURNS_COUNT;
gBattleStruct->dynamax.dynamaxTurns[battler] = gBattleTurnCounter + DYNAMAX_TURNS_COUNT;
// Substitute is removed upon Dynamaxing.
gBattleMons[battler].status2 &= ~STATUS2_SUBSTITUTE;
@ -212,7 +212,6 @@ void UndoDynamax(u32 battler)
// Makes sure there are no Dynamax flags set, including on switch / faint.
SetActiveGimmick(battler, GIMMICK_NONE);
gBattleStruct->dynamax.dynamaxTurns[battler] = 0;
// Undo form change if needed.
if (IsGigantamaxed(battler))
@ -511,13 +510,12 @@ static u32 GetMaxMoveStatusEffect(u32 move)
void BS_UpdateDynamax(void)
{
NATIVE_ARGS();
u32 battler = gBattleScripting.battler;
struct Pokemon *mon = GetPartyBattlerData(battler);
struct Pokemon *mon = GetPartyBattlerData(gBattlerAttacker);
if (!IsGigantamaxed(battler)) // RecalcBattlerStats will get called on form change.
RecalcBattlerStats(battler, mon, GetActiveGimmick(battler) == GIMMICK_DYNAMAX);
if (!IsGigantamaxed(gBattlerAttacker)) // RecalcBattlerStats will get called on form change.
RecalcBattlerStats(gBattlerAttacker, mon, GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL);
UpdateHealthboxAttribute(gHealthboxSpriteIds[gBattlerAttacker], mon, HEALTHBOX_ALL);
gBattlescriptCurrInstr = cmd->nextInstr;
}

1422
src/battle_end_turn.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include "battle_ai_util.h"
#include "battle_arena.h"
#include "battle_controllers.h"
#include "battle_end_turn.h"
#include "battle_interface.h"
#include "battle_main.h"
#include "battle_message.h"
@ -3895,13 +3896,11 @@ static void TryDoEventsBeforeFirstTurn(void)
gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[i];
}
*(&gBattleStruct->turnEffectsTracker) = 0;
*(&gBattleStruct->eventBlockCounter) = 0;
*(&gBattleStruct->turnEffectsBattlerId) = 0;
*(&gBattleStruct->wishPerishSongState) = 0;
*(&gBattleStruct->wishPerishSongBattlerId) = 0;
gBattleScripting.moveendState = 0;
gBattleStruct->faintedActionsState = 0;
gBattleStruct->turnCountersTracker = 0;
gBattleStruct->endTurnEventsCounter = 0;
memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts));
SetShellSideArmCategory();
@ -3935,11 +3934,9 @@ static void HandleEndTurn_ContinueBattle(void)
if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS))
CancelMultiTurnMoves(i);
}
gBattleStruct->turnEffectsTracker = 0;
gBattleStruct->eventBlockCounter = 0;
gBattleStruct->turnEffectsBattlerId = 0;
gBattleStruct->wishPerishSongState = 0;
gBattleStruct->wishPerishSongBattlerId = 0;
gBattleStruct->turnCountersTracker = 0;
gBattleStruct->endTurnEventsCounter = 0;
}
}
@ -3950,18 +3947,14 @@ void BattleTurnPassed(void)
gBattleStruct->speedTieBreaks = RandomUniform(RNG_SPEED_TIE, 0, Factorial(MAX_BATTLERS_COUNT) - 1);
TurnValuesCleanUp(TRUE);
if (gBattleOutcome == 0)
{
if (DoFieldEndTurnEffects())
return;
if (DoBattlerEndTurnEffects())
return;
if (HandleWishPerishSongOnTurnEnd())
return;
}
if (gBattleOutcome == 0 && DoEndTurnEffects())
return;
if (BattleArenaTurnEnd())
return;
if (HandleFaintedMonActions())
return;
gBattleStruct->faintedActionsState = 0;
TurnValuesCleanUp(FALSE);
@ -3995,15 +3988,19 @@ void BattleTurnPassed(void)
gChosenMoveByBattler[i] = MOVE_NONE;
gBattleStruct->battlerState[i].absentBattlerFlags = gAbsentBattlerFlags & (1u << i);
gBattleStruct->monToSwitchIntoId[i] = PARTY_SIZE;
gStatuses4[i] &= ~STATUS4_ELECTRIFIED;
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
gBattleMons[i].status2 &= ~STATUS2_POWDER;
}
for (i = 0; i < NUM_BATTLE_SIDES; i++)
{
if (gSideTimers[i].retaliateTimer > 0)
gSideTimers[i].retaliateTimer--;
}
gFieldStatuses &= ~STATUS_FIELD_ION_DELUGE;
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
AssignUsableGimmicks();
SetShellSideArmCategory();

View File

@ -955,7 +955,8 @@ const u16 gTerrainPreventsStringIds[] =
const u16 gHealingWishStringIds[] =
{
STRINGID_HEALINGWISHCAMETRUE, STRINGID_LUNARDANCECAMETRUE
STRINGID_HEALINGWISHCAMETRUE,
STRINGID_LUNARDANCECAMETRUE
};
const u16 gDmgHazardsStringIds[] =

View File

@ -523,7 +523,7 @@ static void Cmd_presentdamagecalculation(void);
static void Cmd_setsafeguard(void);
static void Cmd_magnitudedamagecalculation(void);
static void Cmd_jumpifnopursuitswitchdmg(void);
static void Cmd_unused_bb(void);
static void Cmd_tryhealingitem(void);
static void Cmd_halvehp(void);
static void Cmd_copyfoestats(void);
static void Cmd_rapidspinfree(void);
@ -782,7 +782,7 @@ void (* const gBattleScriptingCommandsTable[])(void) =
Cmd_setsafeguard, //0xB8
Cmd_magnitudedamagecalculation, //0xB9
Cmd_jumpifnopursuitswitchdmg, //0xBA
Cmd_unused_bb, //0xBB
Cmd_tryhealingitem, //0xBB
Cmd_halvehp, //0xBC
Cmd_copyfoestats, //0xBD
Cmd_rapidspinfree, //0xBE
@ -3935,7 +3935,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
}
break;
case MOVE_EFFECT_THROAT_CHOP:
gDisableStructs[gEffectBattler].throatChopTimer = 2;
gDisableStructs[gEffectBattler].throatChopTimer = gBattleTurnCounter + 2;
gBattlescriptCurrInstr++;
break;
case MOVE_EFFECT_INCINERATE:
@ -4142,7 +4142,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
else if (!(gStatuses3[gEffectBattler] & STATUS3_HEAL_BLOCK))
{
gStatuses3[gEffectBattler] |= STATUS3_HEAL_BLOCK;
gDisableStructs[gEffectBattler].healBlockTimer = 2;
gDisableStructs[gEffectBattler].healBlockTimer = gBattleTurnCounter + 2;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_EffectPsychicNoise;
}
@ -7106,7 +7106,7 @@ static void Cmd_sethealblock(void)
else
{
gStatuses3[gBattlerTarget] |= STATUS3_HEAL_BLOCK;
gDisableStructs[gBattlerTarget].healBlockTimer = 5;
gDisableStructs[gBattlerTarget].healBlockTimer = gBattleTurnCounter + 5;
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
@ -7760,6 +7760,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
else if ((gBattleStruct->battlerState[battler].storedHealingWish || gBattleStruct->battlerState[battler].storedLunarDance)
&& (gBattleMons[battler].hp != gBattleMons[battler].maxHP || gBattleMons[battler].status1 != 0 || B_HEALING_WISH_SWITCH < GEN_8))
{
gBattlerAttacker = battler;
if (gBattleStruct->battlerState[battler].storedHealingWish)
{
BattleScriptPushCursor();
@ -9320,10 +9321,10 @@ u32 IsFlowerVeilProtected(u32 battler)
return 0;
}
u32 IsLeafGuardProtected(u32 battler)
u32 IsLeafGuardProtected(u32 battler, u32 ability)
{
if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
return GetBattlerAbility(battler) == ABILITY_LEAF_GUARD;
return ability == ABILITY_LEAF_GUARD;
else
return 0;
}
@ -9337,7 +9338,7 @@ bool32 IsShieldsDownProtected(u32 battler)
u32 IsAbilityStatusProtected(u32 battler)
{
return IsFlowerVeilProtected(battler)
|| IsLeafGuardProtected(battler)
|| IsLeafGuardProtected(battler, GetBattlerAbility(battler))
|| IsShieldsDownProtected(battler);
}
@ -11169,7 +11170,7 @@ static void Cmd_various(void)
case VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED:
{
VARIOUS_ARGS(const u8 *jumpInstr);
if (IsLeafGuardProtected(battler))
if (IsLeafGuardProtected(battler, GetBattlerAbility(battler)))
{
gBattlerAbility = battler;
gBattlescriptCurrInstr = cmd->jumpInstr;
@ -13896,7 +13897,7 @@ static void Cmd_setembargo(void)
else
{
gStatuses3[gBattlerTarget] |= STATUS3_EMBARGO;
gDisableStructs[gBattlerTarget].embargoTimer = 5;
gDisableStructs[gBattlerTarget].embargoTimer = gBattleTurnCounter + 5;
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
@ -14073,8 +14074,18 @@ static void Cmd_jumpifnopursuitswitchdmg(void)
}
}
static void Cmd_unused_bb(void)
static void Cmd_tryhealingitem(void)
{
CMD_ARGS();
if (gItemsInfo[gBattleMons[gBattlerAttacker].item].pocket == POCKET_BERRIES
|| GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_RESTORE_HP) // Edge case for Berry Juice
{
if (ItemBattleEffects(ITEMEFFECT_TRY_HEALING, gBattlerAttacker, FALSE))
return;
}
gBattlescriptCurrInstr = cmd->nextInstr;
}
// Belly Drum, Fillet Away
@ -14528,7 +14539,6 @@ static void Cmd_settorment(void)
else
{
gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT;
gDisableStructs[gBattlerTarget].tormentTimer = PERMANENT_TORMENT; // permanent
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
@ -14736,43 +14746,17 @@ static void Cmd_trycopyability(void)
static void Cmd_trywish(void)
{
CMD_ARGS(u8 turnNumber, const u8 *failInstr);
CMD_ARGS(const u8 *failInstr);
switch (cmd->turnNumber)
if (gWishFutureKnock.wishCounter[gBattlerAttacker] <= gBattleTurnCounter)
{
case 0: // use wish
if (gWishFutureKnock.wishCounter[gBattlerAttacker] <= gBattleTurnCounter)
{
gWishFutureKnock.wishCounter[gBattlerAttacker] = gBattleTurnCounter + 2;
gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
{
gBattlescriptCurrInstr = cmd->failInstr;
}
break;
case 1: // heal effect
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gWishFutureKnock.wishPartyId[gBattlerTarget])
if (B_WISH_HP_SOURCE >= GEN_5)
{
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
gBattleStruct->moveDamage[gBattlerTarget] = max(1, GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2);
else
gBattleStruct->moveDamage[gBattlerTarget] = max(1, GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[gBattlerTarget]], MON_DATA_MAX_HP) / 2);
}
else
{
gBattleStruct->moveDamage[gBattlerTarget] = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 2);
}
gBattleStruct->moveDamage[gBattlerTarget] *= -1;
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
gBattlescriptCurrInstr = cmd->failInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
break;
gWishFutureKnock.wishCounter[gBattlerAttacker] = gBattleTurnCounter + 2;
gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
{
gBattlescriptCurrInstr = cmd->failInstr;
}
}
@ -15005,9 +14989,9 @@ static void Cmd_setuserstatus3(void)
{
gStatuses3[gBattlerAttacker] |= flags;
if (flags & STATUS3_MAGNET_RISE)
gDisableStructs[gBattlerAttacker].magnetRiseTimer = 5;
gDisableStructs[gBattlerAttacker].magnetRiseTimer = gBattleTurnCounter + 5;
if (flags & STATUS3_LASER_FOCUS)
gDisableStructs[gBattlerAttacker].laserFocusTimer = 2;
gDisableStructs[gBattlerAttacker].laserFocusTimer = gBattleTurnCounter + 2;
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
@ -16144,7 +16128,7 @@ static void Cmd_settelekinesis(void)
else
{
gStatuses3[gBattlerTarget] |= STATUS3_TELEKINESIS;
gDisableStructs[gBattlerTarget].telekinesisTimer = 3;
gDisableStructs[gBattlerTarget].telekinesisTimer = gBattleTurnCounter + 3;
gBattlescriptCurrInstr = cmd->nextInstr;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -47,3 +47,45 @@ SINGLE_BATTLE_TEST("Emergency Exit switches out when going below 50% max-HP but
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}
SINGLE_BATTLE_TEST("Emergency Exit activ out when taking taking residual damage and falling under 50% max-hp damage - Burn")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(134); Status1(STATUS1_BURN); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { SEND_OUT(opponent, 1); }
} SCENE {
HP_BAR(opponent);
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}
SINGLE_BATTLE_TEST("Emergency Exit activ out when taking taking residual damage and falling under 50% max-hp damage - Weather")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(134); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SANDSTORM); SEND_OUT(opponent, 1); }
} SCENE {
HP_BAR(opponent);
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}
SINGLE_BATTLE_TEST("Emergency Exit activ out when taking taking residual damage and falling under 50% max-hp damage - Salt Cure")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(160); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SALT_CURE); SEND_OUT(opponent, 1); }
} SCENE {
HP_BAR(opponent);
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}

View File

@ -107,11 +107,11 @@ DOUBLE_BATTLE_TEST("Court Change used by the player swaps Mist, Safeguard, Auror
MESSAGE("Wynaut used Court Change!");
MESSAGE("Wynaut swapped the battle effects affecting each side of the field!");
// The effects now end for the player side.
MESSAGE("Your team's Mist wore off!");
MESSAGE("Your team is no longer protected by Safeguard!");
MESSAGE("Your team's Mist wore off!");
MESSAGE("Your team's Reflect wore off!");
MESSAGE("Your team's Aurora Veil wore off!");
MESSAGE("Your team's Tailwind petered out!");
MESSAGE("Your team's Aurora Veil wore off!");
MESSAGE("Your team's Light Screen wore off!");
}
}
@ -144,11 +144,12 @@ DOUBLE_BATTLE_TEST("Court Change used by the opponent swaps Mist, Safeguard, Aur
MESSAGE("The opposing Wynaut used Court Change!");
MESSAGE("The opposing Wynaut swapped the battle effects affecting each side of the field!");
// The effects now end for the player side.
MESSAGE("The opposing team's Mist wore off!");
MESSAGE("The snow stopped.");
MESSAGE("The opposing team is no longer protected by Safeguard!");
MESSAGE("The opposing team's Mist wore off!");
MESSAGE("The opposing team's Reflect wore off!");
MESSAGE("The opposing team's Aurora Veil wore off!");
MESSAGE("The opposing team's Tailwind petered out!");
MESSAGE("The opposing team's Aurora Veil wore off!");
MESSAGE("The opposing team's Light Screen wore off!");
}
}

View File

@ -0,0 +1,25 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_WISH) == EFFECT_WISH);
}
SINGLE_BATTLE_TEST("Wish restores 50% of max player HP")
{
GIVEN {
PLAYER(SPECIES_WYNAUT) { HP(50); MaxHP(100); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_WISH); }
TURN { }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WISH, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player);
MESSAGE("Wynaut's wish came true!");
HP_BAR(player, hp: 100);
MESSAGE("Wynaut's HP was restored.");
}
}

View File

@ -24,22 +24,24 @@ SINGLE_BATTLE_TEST("Throat Chop prevents the usage of sound moves")
}
}
SINGLE_BATTLE_TEST("Throat Chop won't work through a substitute")
SINGLE_BATTLE_TEST("Throat Chop prevents sound base moves for 2 turns")
{
GIVEN {
PLAYER(SPECIES_INCINEROAR) { Speed(100); };
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); };
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HYPER_VOICE, MOVE_ALLURING_VOICE, MOVE_OVERDRIVE, MOVE_ROUND); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); }
TURN { MOVE(player, MOVE_THROAT_CHOP); MOVE(opponent, MOVE_HYPER_VOICE); }
TURN {}
TURN { MOVE(opponent, MOVE_HYPER_VOICE); MOVE(player, MOVE_THROAT_CHOP); }
TURN { FORCED_MOVE(opponent); }
TURN { MOVE(opponent, MOVE_HYPER_VOICE); MOVE(player, MOVE_THROAT_CHOP); }
TURN { FORCED_MOVE(opponent); }
TURN { MOVE(opponent, MOVE_HYPER_VOICE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, player);
NONE_OF {
MESSAGE("The effects of Throat Chop prevent the opposing Wobbuffet from using certain moves!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPER_VOICE, opponent);
}
}