Add B_FLAG_SLEEP_CLAUSE (#5566)

Co-authored-by: Isaac Rivera <isaacrivera2020@u.northwestern.edu>
Co-authored-by: iriv24 <40581123+iriv24@users.noreply.github.com>
Co-authored-by: Hedara <hedara90@gmail.com>
This commit is contained in:
Pawkkie 2024-12-02 03:06:03 -05:00 committed by GitHub
parent 0322d51887
commit 2b7905beb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 2012 additions and 21 deletions

View File

@ -1667,6 +1667,11 @@
callnative BS_DamageToQuarterTargetHP
.endm
.macro jumpifsleepclause jumpInstr:req
callnative BS_JumpIfSleepClause
.4byte \jumpInstr
.endm
.macro ficklebeamdamagecalculation
callnative BS_FickleBeamDamageCalculation
.endm
@ -2004,9 +2009,10 @@
.4byte \jumpInstr
.endm
.macro trypsychoshift failInstr:req
.macro trypsychoshift failInstr:req sleepClauseFailInstr:req
various BS_ATTACKER, VARIOUS_PSYCHO_SHIFT
.4byte \failInstr
.4byte \sleepClauseFailInstr
.endm
.macro curestatus battler:req

View File

@ -1639,7 +1639,7 @@ BattleScript_EffectPsychoShift::
BattleScript_EffectPsychoShiftCanWork:
jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed
jumpifsafeguard BattleScript_SafeguardProtected
trypsychoshift BattleScript_ButItFailed
trypsychoshift BattleScript_ButItFailed, BattleScript_SleepClauseBlocked
attackanimation
waitanimation
copybyte gEffectBattler, gBattlerTarget
@ -2892,6 +2892,7 @@ BattleScript_EffectSleep::
jumpifleafguardprotected BS_TARGET, BattleScript_AbilityProtectsDoesntAffect
jumpifshieldsdown BS_TARGET, BattleScript_AbilityProtectsDoesntAffect
jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed
jumpifsleepclause BattleScript_SleepClauseBlocked
jumpifterrainaffected BS_TARGET, STATUS_FIELD_ELECTRIC_TERRAIN, BattleScript_ElectricTerrainPrevents
jumpifterrainaffected BS_TARGET, STATUS_FIELD_MISTY_TERRAIN, BattleScript_MistyTerrainPrevents
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
@ -5154,6 +5155,7 @@ BattleScript_EffectYawn::
jumpifflowerveil BattleScript_FlowerVeilProtects
jumpifleafguardprotected BS_TARGET, BattleScript_AbilityProtectsDoesntAffect
jumpifshieldsdown BS_TARGET, BattleScript_AbilityProtectsDoesntAffect
jumpifsleepclause BattleScript_SleepClauseBlocked
jumpifsubstituteblocks BattleScript_ButItFailed
jumpifsafeguard BattleScript_SafeguardProtected
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
@ -10108,3 +10110,16 @@ BattleScript_EffectSnow::
call BattleScript_CheckPrimalWeather
setfieldweather ENUM_WEATHER_SNOW
goto BattleScript_MoveWeatherChange
BattleScript_SleepClauseBlocked::
pause B_WAIT_TIME_SHORT
orhalfword gMoveResultFlags, MOVE_RESULT_FAILED
printstring STRINGID_BLOCKEDBYSLEEPCLAUSE
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_SleepClausePreventsEnd::
pause B_WAIT_TIME_SHORT
printstring STRINGID_BLOCKEDBYSLEEPCLAUSE
waitmessage B_WAIT_TIME_LONG
end2

View File

@ -832,6 +832,8 @@ struct BattleStruct
u8 padding:7;
u8 usedEjectItem;
u8 usedMicleBerry;
u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party
u8 sleepClauseEffectExempt:4; // Stores whether effect should be exempt from triggering Sleep Clause (Effect Spore)
};
// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,

View File

@ -185,6 +185,7 @@ bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove);
bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck);
bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 PartnerMoveActivatesSleepClause(u32 move);
bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move);
// party logic

View File

@ -520,6 +520,7 @@ extern const u8 BattleScript_Terastallization[];
extern const u8 BattleScript_BoosterEnergyEnd2[];
extern const u8 BattleScript_TeraShellDistortingTypeMatchups[];
extern const u8 BattleScript_TeraFormChange[];
extern const u8 BattleScript_SleepClausePreventsEnd[];
// zmoves
extern const u8 BattleScript_ZMoveActivateDamaging[];

View File

@ -291,7 +291,7 @@ bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef);
bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef);
bool32 CanBeSlept(u32 battler, u32 ability);
bool32 CanBeSlept(u32 battler, u32 ability, u32 isBlockedBySleepClause);
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 CanBeBurned(u32 battler, u32 ability);
bool32 CanBeParalyzed(u32 battler, u32 ability);
@ -314,5 +314,8 @@ bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon);
bool8 IsMonBannedFromSkyBattles(u16 species);
void RemoveBattlerType(u32 battler, u8 type);
u32 GetMoveType(u32 move);
void TryActivateSleepClause(u32 battler, u32 indexInParty);
void TryDeactivateSleepClause(u32 battlerSide, u32 indexInParty);
bool8 IsSleepClauseActiveForSide(u32 battlerSide);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -192,6 +192,7 @@
#define B_FLAG_DYNAMAX_BATTLE 0 // If this flag is set, the ability to Dynamax in battle is enabled for all trainers.
#define B_FLAG_TERA_ORB_CHARGED 0 // If this flag is set, the Tera Orb is charged. It is automatically set upon healing and cleared upon Terastallizing once configured.
#define B_FLAG_TERA_ORB_NO_COST 0 // If this flag is set, the Tera Orb does not use up its charge upon Terastallization. In S/V, this occurs after an event with Terapagos.
#define B_FLAG_SLEEP_CLAUSE 0 // If this flag is set, sleep clause is enabled; if the player / AI has already put a Pokémon on the opponent's side to sleep and it is still sleeping, another one can't be put to sleep. AI requires AI_FLAG_CHECK_BAD_MOVE to understand.
// Var Settings
// To use the following features in scripting, replace the 0s with the var ID you're assigning it to.

View File

@ -1129,4 +1129,8 @@
#undef P_FAMILY_PECHARUNT
#define P_FAMILY_PECHARUNT TRUE
// Flags
#undef B_FLAG_SLEEP_CLAUSE
#define B_FLAG_SLEEP_CLAUSE FLAG_SPECIAL_FLAG_UNUSED_0x4003
#endif // GUARD_CONFIG_TEST_H

View File

@ -724,8 +724,9 @@
#define STRINGID_ELECTRICCURRENTISRUNNING 722
#define STRINGID_SEEMSWEIRD 723
#define STRINGID_WAGGLINGAFINGER 724
#define STRINGID_BLOCKEDBYSLEEPCLAUSE 725
#define BATTLESTRINGS_COUNT 725
#define BATTLESTRINGS_COUNT 726
// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,

View File

@ -982,6 +982,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_SLEEP:
if (!AI_CanPutToSleep(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove))
ADJUST_SCORE(-10);
if (PartnerMoveActivatesSleepClause(aiData->partnerMove))
ADJUST_SCORE(-20);
break;
case EFFECT_EXPLOSION:
if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE))
@ -1794,7 +1796,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_REST:
if (!CanBeSlept(battlerAtk, aiData->abilities[battlerAtk]))
if (!CanBeSlept(battlerAtk, aiData->abilities[battlerAtk], FALSE))
ADJUST_SCORE(-10);
//fallthrough
case EFFECT_RESTORE_HP:
@ -2077,6 +2079,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
else if (!AI_CanPutToSleep(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove))
ADJUST_SCORE(-10);
if (PartnerMoveActivatesSleepClause(aiData->partnerMove))
ADJUST_SCORE(-20);
break;
case EFFECT_SKILL_SWAP:
if (aiData->abilities[battlerAtk] == ABILITY_NONE || aiData->abilities[battlerDef] == ABILITY_NONE
@ -2676,7 +2680,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IsMoveEffectWeather(move))
ADJUST_SCORE(-10);
break;
}
}
} // check partner move effect
// Adjust for always crit moves
@ -3454,7 +3458,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
}
break;
case EFFECT_REST:
if (!(CanBeSlept(battlerAtk, aiData->abilities[battlerAtk])))
if (!(CanBeSlept(battlerAtk, aiData->abilities[battlerAtk], FALSE)))
{
break;
}

View File

@ -502,7 +502,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
{
//Yawn
if (gStatuses3[battler] & STATUS3_YAWN
&& CanBeSlept(battler, monAbility)
&& CanBeSlept(battler, monAbility, TRUE)
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / 3)
{
switchMon = TRUE;

View File

@ -2902,7 +2902,7 @@ bool32 IsBattlerIncapacitated(u32 battler, u32 ability)
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
{
if (!CanBeSlept(battlerDef, defAbility)
if (!CanBeSlept(battlerDef, defAbility, TRUE)
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|| PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) // shouldn't try to sleep mon that partner is trying to make sleep
return FALSE;
@ -3392,6 +3392,17 @@ bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMov
return FALSE;
}
bool32 PartnerMoveActivatesSleepClause(u32 partnerMove)
{
u32 effect = gMovesInfo[partnerMove].effect;
if (!IsDoubleBattle() || !FlagGet(B_FLAG_SLEEP_CLAUSE))
return FALSE;
if (effect == EFFECT_SLEEP
|| effect == EFFECT_YAWN)
return TRUE;
return FALSE;
}
bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move)
{
u32 i;

View File

@ -759,7 +759,7 @@ void BS_SetMaxMoveEffect(void)
{
static const u8 sSnoozeEffects[] = {TRUE, FALSE};
if (!(gStatuses3[gBattlerTarget] & STATUS3_YAWN)
&& CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget))
&& CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE)
&& RandomElement(RNG_G_MAX_SNOOZE, sSnoozeEffects)) // 50% chance of success
{
gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2);
@ -881,12 +881,14 @@ void BS_TrySetStatus1(void)
}
break;
case STATUS1_SLEEP:
if (CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
if (CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE))
{
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);
TryActivateSleepClause(gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget]);
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
effect++;
}

View File

@ -3121,6 +3121,13 @@ static void BattleStartClearSetData(void)
gSelectedMonPartyId = PARTY_SIZE; // Revival Blessing
gCategoryIconSpriteId = 0xFF;
if(FlagGet(B_FLAG_SLEEP_CLAUSE))
{
// If monCausingSleepClause[side] equals PARTY_SIZE, Sleep Clause is not active for the given side.
gBattleStruct->monCausingSleepClause[B_SIDE_PLAYER] = PARTY_SIZE;
gBattleStruct->monCausingSleepClause[B_SIDE_OPPONENT] = PARTY_SIZE;
}
}
void SwitchInClearSetData(u32 battler)

View File

@ -890,6 +890,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
[STRINGID_ELECTRICCURRENTISRUNNING] = COMPOUND_STRING("An electric current is running across the battlefield!"),
[STRINGID_SEEMSWEIRD] = COMPOUND_STRING("The battlefield seems weird!"),
[STRINGID_WAGGLINGAFINGER] = COMPOUND_STRING("Waggling a finger let it use {B_CURRENT_MOVE}!"),
[STRINGID_BLOCKEDBYSLEEPCLAUSE] = COMPOUND_STRING("Sleep Clause kept {B_DEF_NAME_WITH_PREFIX2} awake!"),
};
const u16 gTrainerUsedItemStringIds[] =

View File

@ -3004,7 +3004,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
if (i != gBattlersCount)
break;
if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler)))
if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler), TRUE) && !(gBattleStruct->sleepClauseEffectExempt & (1u << gEffectBattler)))
break;
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler);
@ -3223,6 +3223,8 @@ void SetMoveEffect(bool32 primary, bool32 certain)
gBattleMons[gEffectBattler].status1 |= STATUS1_SLEEP_TURN(1 + RandomUniform(RNG_SLEEP_TURNS, 1, 3));
else
gBattleMons[gEffectBattler].status1 |= STATUS1_SLEEP_TURN(1 + RandomUniform(RNG_SLEEP_TURNS, 2, 5));
TryActivateSleepClause(gEffectBattler, gBattlerPartyIndexes[gEffectBattler]);
}
else
{
@ -4188,6 +4190,8 @@ static void Cmd_tryfaintmon(void)
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex])
}
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
else
{
@ -5931,6 +5935,7 @@ static void Cmd_moveend(void)
gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal;
break;
case STATUS1_SLEEP:
TryDeactivateSleepClause(GetBattlerSide(gBattlerTarget), gBattlerPartyIndexes[gBattlerTarget]);
gBattlescriptCurrInstr = BattleScript_TargetWokeUp;
break;
case STATUS1_BURN:
@ -10171,7 +10176,7 @@ static void Cmd_various(void)
}
case VARIOUS_PSYCHO_SHIFT:
{
VARIOUS_ARGS(const u8 *failInstr);
VARIOUS_ARGS(const u8 *failInstr, const u8 *sleepClauseFailInstr);
u32 targetAbility = GetBattlerAbility(gBattlerTarget);
// Psycho shift works
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget, targetAbility))
@ -10182,10 +10187,15 @@ static void Cmd_various(void)
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && CanBeParalyzed(gBattlerTarget, targetAbility))
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanBeSlept(gBattlerTarget, targetAbility))
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanBeSlept(gBattlerTarget, targetAbility, TRUE))
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE) && CanGetFrostbite(gBattlerTarget))
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
else if (IsSleepClauseActiveForSide(GetBattlerSide(battler)))
{
gBattlescriptCurrInstr = cmd->sleepClauseFailInstr;
return;
}
else
{
gBattlescriptCurrInstr = cmd->failInstr;
@ -10196,11 +10206,16 @@ static void Cmd_various(void)
BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
gBattlescriptCurrInstr = cmd->nextInstr;
TryActivateSleepClause(battler, gBattlerPartyIndexes[battler]);
return;
}
case VARIOUS_CURE_STATUS:
{
VARIOUS_ARGS();
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
gBattleMons[battler].status1 = 0;
BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
@ -13269,12 +13284,11 @@ static void Cmd_healpartystatus(void)
u32 zero = 0;
u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker)));
u8 toHeal = 0;
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
s32 i;
if (gCurrentMove == MOVE_HEAL_BELL)
{
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
s32 i;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_BELL;
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF
@ -13340,7 +13354,10 @@ static void Cmd_healpartystatus(void)
}
if (ability != ABILITY_SOUNDPROOF)
{
toHeal |= (1 << i);
TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), i);
}
}
}
}
@ -13349,6 +13366,11 @@ static void Cmd_healpartystatus(void)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SOOTHING_AROMA;
toHeal = (1 << PARTY_SIZE) - 1;
for (i = 0; i < PARTY_SIZE; i++)
{
TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), i);
}
gBattleMons[gBattlerAttacker].status1 = 0;
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
@ -14123,6 +14145,9 @@ static void Cmd_curestatuswithmove(void)
if (shouldHeal)
{
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]);
gBattleMons[gBattlerAttacker].status1 = 0;
gBattlescriptCurrInstr = cmd->nextInstr;
BtlController_EmitSetMonData(gBattlerAttacker, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerAttacker].status1), &gBattleMons[gBattlerAttacker].status1);
@ -14731,6 +14756,9 @@ static void Cmd_switchoutabilities(void)
switch (GetBattlerAbility(battler))
{
case ABILITY_NATURAL_CURE:
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
gBattleMons[battler].status1 = 0;
BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_STATUS_BATTLE,
1u << *(gBattleStruct->battlerPartyIndexes + battler),
@ -17250,6 +17278,25 @@ void BS_DamageToQuarterTargetHP(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_JumpIfSleepClause(void)
{
NATIVE_ARGS(const u8 *jumpInstr);
// Can freely sleep own partner
if (IsDoubleBattle() && B_FLAG_SLEEP_CLAUSE && GetBattlerSide(gBattlerAttacker) == GetBattlerSide(gBattlerTarget))
{
gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerTarget);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
gBattleStruct->sleepClauseEffectExempt &= ~(1u << gBattlerTarget);
// Can't sleep if clause is active otherwise
if (IsSleepClauseActiveForSide(GetBattlerSide(gBattlerTarget)))
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_FickleBeamDamageCalculation(void)
{
NATIVE_ARGS();

View File

@ -2785,6 +2785,10 @@ u8 DoBattlerEndTurnEffects(void)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_MISTY;
BattleScriptExecute(BattleScript_TerrainPreventsEnd2);
}
else if (IsSleepClauseActiveForSide(GetBattlerSide(battler)))
{
BattleScriptExecute(BattleScript_SleepClausePreventsEnd);
}
else
{
if (B_SLEEP_TURNS >= GEN_5)
@ -2792,6 +2796,7 @@ u8 DoBattlerEndTurnEffects(void)
else
gBattleMons[battler].status1 |= ((Random() % 4) + 3);
TryActivateSleepClause(battler, gBattlerPartyIndexes[battler]);
BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
BattleScriptExecute(BattleScript_YawnMakesAsleep);
@ -3239,6 +3244,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
{
if (UproarWakeUpCheck(gBattlerAttacker))
{
TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]);
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP;
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
BattleScriptPushCursor();
@ -3268,6 +3274,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
}
else
{
TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]);
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
BattleScriptPushCursor();
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP;
@ -3327,6 +3334,8 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
gHitMarker |= HITMARKER_OBEYS;
break;
case DISOBEYS_FALL_ASLEEP:
if (FlagGet(B_FLAG_SLEEP_CLAUSE))
gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker);
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
gMoveResultFlags |= MOVE_RESULT_MISSED;
break;
@ -5212,7 +5221,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON))
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
if (gBattleMons[battler].status1 & STATUS1_BURN)
@ -5816,10 +5829,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& IsBattlerAlive(gBattlerAttacker)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& CanBeSlept(gBattlerAttacker, ability)
&& CanBeSlept(gBattlerAttacker, ability, FALSE)
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
&& IsMoveMakingContact(move, gBattlerAttacker))
{
if (FlagGet(B_FLAG_SLEEP_CLAUSE))
gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker);
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_SLEEP;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptPushCursor();
@ -6252,6 +6267,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_VITAL_SPIRIT:
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
{
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
effect = 1;
@ -6674,8 +6690,11 @@ bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag)
return IsBattlerGrounded(battler);
}
bool32 CanBeSlept(u32 battler, u32 ability)
bool32 CanBeSlept(u32 battler, u32 ability, u32 isBlockedBySleepClause)
{
if(IsSleepClauseActiveForSide(GetBattlerSide(battler)) && isBlockedBySleepClause)
return FALSE;
if (ability == ABILITY_INSOMNIA
|| ability == ABILITY_VITAL_SPIRIT
|| ability == ABILITY_COMATOSE
@ -7345,6 +7364,7 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect)
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet;
effect = ITEM_STATUS_CHANGE;
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
break;
case HOLD_EFFECT_CURE_CONFUSION:
@ -7376,6 +7396,7 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect)
{
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
@ -7586,6 +7607,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
BattleScriptExecute(BattleScript_BerryCureSlpEnd2);
effect = ITEM_STATUS_CHANGE;
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
break;
case HOLD_EFFECT_CURE_STATUS:
@ -7604,6 +7626,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
i++;
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
{
@ -7883,6 +7906,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
BattleScriptExecute(BattleScript_BerryCureSlpEnd2);
effect = ITEM_STATUS_CHANGE;
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
break;
case HOLD_EFFECT_CURE_CONFUSION:
@ -7907,6 +7931,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
i++;
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
}
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
{
@ -8547,7 +8572,7 @@ u8 GetAttackerObedienceForAction()
obedienceLevel = levelReferenced - obedienceLevel;
calc = ((rnd >> 16) & 255);
if (calc < obedienceLevel && CanBeSlept(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)))
if (calc < obedienceLevel && CanBeSlept(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), FALSE))
{
// try putting asleep
int i;
@ -11972,3 +11997,31 @@ u32 GetMoveType(u32 move)
return TYPE_MYSTERY;
return gMovesInfo[move].type;
}
void TryActivateSleepClause(u32 battler, u32 indexInParty)
{
if (gBattleStruct->sleepClauseEffectExempt & (1u << battler))
{
gBattleStruct->sleepClauseEffectExempt &= ~(1u << battler);
return;
}
if (FlagGet(B_FLAG_SLEEP_CLAUSE))
gBattleStruct->monCausingSleepClause[GetBattlerSide(battler)] = indexInParty;
}
void TryDeactivateSleepClause(u32 battlerSide, u32 indexInParty)
{
// If the pokemon on the given side at the given index in the party is the one causing Sleep Clause to be active,
// set monCausingSleepClause[battlerSide] = PARTY_SIZE, which means Sleep Clause is not active for the given side
if (FlagGet(B_FLAG_SLEEP_CLAUSE) && gBattleStruct->monCausingSleepClause[battlerSide] == indexInParty)
gBattleStruct->monCausingSleepClause[battlerSide] = PARTY_SIZE;
}
bool8 IsSleepClauseActiveForSide(u32 battlerSide)
{
// If monCausingSleepClause[battlerSide] == PARTY_SIZE, Sleep Clause is not active for the given side.
// If monCausingSleepClause[battlerSide] < PARTY_SIZE, it means it is storing the index of the mon that is causing Sleep Clause to be active,
// from which it follows that Sleep Clause is active.
return (FlagGet(B_FLAG_SLEEP_CLAUSE) && (gBattleStruct->monCausingSleepClause[battlerSide] < PARTY_SIZE));
}

View File

@ -4199,7 +4199,24 @@ bool8 HealStatusConditions(struct Pokemon *mon, u32 healMask, u8 battlerId)
status &= ~healMask;
SetMonData(mon, MON_DATA_STATUS, &status);
if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT)
{
gBattleMons[battlerId].status1 &= ~healMask;
if((healMask & STATUS1_SLEEP))
{
u32 i = 0;
u32 battlerSide = GetBattlerSide(battlerId);
struct Pokemon *party = GetSideParty(battlerSide);
for (i = 0; i < PARTY_SIZE; i++)
{
if (&party[i] == mon)
{
TryDeactivateSleepClause(battlerSide, i);
break;
}
}
}
}
return FALSE;
}
else

1816
test/battle/sleep_clause.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1371,7 +1371,6 @@ static inline rng_value_t MakeRngValue(const u16 seed)
static void CB2_BattleTest_NextTrial(void)
{
ClearFlagAfterTest();
TearDownBattle();
SetMainCallback2(CB2_BattleTest_NextParameter);