Better implementation of the obedience fix (#5245)
Co-authored-by: Hedara <hedara90@gmail.com>
This commit is contained in:
parent
36a5c6ed4f
commit
51a127fcb5
4 changed files with 93 additions and 92 deletions
|
@ -221,7 +221,7 @@ struct SpecialStatus
|
|||
u8 faintedHasReplacement:1;
|
||||
u8 focusBanded:1;
|
||||
u8 focusSashed:1;
|
||||
u8 unused:1;
|
||||
u8 unused:2;
|
||||
// End of byte
|
||||
u8 sturdied:1;
|
||||
u8 stormDrainRedirected:1;
|
||||
|
@ -801,6 +801,7 @@ struct BattleStruct
|
|||
u8 categoryOverride; // for Z-Moves and Max Moves
|
||||
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
|
||||
u8 fickleBeamBoosted:1;
|
||||
u8 obedienceResult:3;
|
||||
};
|
||||
|
||||
// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,
|
||||
|
|
|
@ -106,6 +106,15 @@ enum
|
|||
CANCELLER_END2,
|
||||
};
|
||||
|
||||
enum {
|
||||
OBEYS,
|
||||
DISOBEYS_LOAFS,
|
||||
DISOBEYS_HITS_SELF,
|
||||
DISOBEYS_FALL_ASLEEP,
|
||||
DISOBEYS_WHILE_ASLEEP,
|
||||
DISOBEYS_RANDOM_MOVE,
|
||||
};
|
||||
|
||||
extern const struct TypePower gNaturalGiftTable[];
|
||||
|
||||
void HandleAction_ThrowBall(void);
|
||||
|
@ -171,7 +180,7 @@ void ClearVariousBattlerFlags(u32 battler);
|
|||
void HandleAction_RunBattleScript(void);
|
||||
u32 SetRandomTarget(u32 battler);
|
||||
u32 GetMoveTarget(u16 move, u8 setTarget);
|
||||
u8 IsMonDisobedient(void);
|
||||
u8 GetAttackerObedienceForAction();
|
||||
u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating);
|
||||
u32 GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating);
|
||||
u32 GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility);
|
||||
|
|
|
@ -1284,16 +1284,40 @@ static void Cmd_attackcanceler(void)
|
|||
|
||||
if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
||||
{
|
||||
switch (IsMonDisobedient())
|
||||
switch (gBattleStruct->obedienceResult)
|
||||
{
|
||||
case 0:
|
||||
case OBEYS:
|
||||
break;
|
||||
case 2:
|
||||
case DISOBEYS_LOAFS:
|
||||
// Randomly select, then print a disobedient string
|
||||
// B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
case DISOBEYS_HITS_SELF:
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE, FALSE, TRUE);
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
return;
|
||||
default:
|
||||
case DISOBEYS_FALL_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
case DISOBEYS_WHILE_ASLEEP:
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
|
||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
||||
return;
|
||||
case DISOBEYS_RANDOM_MOVE:
|
||||
gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
|
||||
gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gHitMarker |= HITMARKER_DISOBEDIENT_MOVE;
|
||||
gHitMarker |= HITMARKER_OBEYS;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ void HandleAction_UseMove(void)
|
|||
gBattleScripting.savedMoveEffect = 0;
|
||||
gCurrMovePos = gChosenMovePos = *(gBattleStruct->chosenMovePositions + gBattlerAttacker);
|
||||
|
||||
gBattleStruct->obedienceResult = GetAttackerObedienceForAction();
|
||||
|
||||
// choose move
|
||||
if (gProtectStructs[gBattlerAttacker].noValidMoves)
|
||||
{
|
||||
|
@ -3566,7 +3568,8 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
|||
gBattleStruct->atkCancellerTracker++;
|
||||
break;
|
||||
case CANCELLER_Z_MOVES:
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE
|
||||
&& gBattleStruct->obedienceResult == OBEYS)
|
||||
{
|
||||
// For Z-Mirror Move, so it doesn't play the animation twice.
|
||||
bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE);
|
||||
|
@ -8331,12 +8334,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget)
|
|||
return targetBattler;
|
||||
}
|
||||
|
||||
static bool32 IsBattlerModernFatefulEncounter(u32 battler)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u8 IsMonDisobedient(void)
|
||||
u8 GetAttackerObedienceForAction()
|
||||
{
|
||||
s32 rnd;
|
||||
s32 calc;
|
||||
|
@ -8344,40 +8342,37 @@ u8 IsMonDisobedient(void)
|
|||
u8 levelReferenced;
|
||||
|
||||
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK))
|
||||
return 0;
|
||||
return OBEYS;
|
||||
if (BattlerHasAi(gBattlerAttacker))
|
||||
return 0;
|
||||
return OBEYS;
|
||||
|
||||
if (IsBattlerModernFatefulEncounter(gBattlerAttacker)) // only false if illegal Mew or Deoxys
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(gBattlerAttacker) == B_POSITION_PLAYER_RIGHT)
|
||||
return 0;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
||||
return 0;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
return 0;
|
||||
if (B_OBEDIENCE_MECHANICS < GEN_8 && !IsOtherTrainer(gBattleMons[gBattlerAttacker].otId, gBattleMons[gBattlerAttacker].otName))
|
||||
return 0;
|
||||
if (FlagGet(FLAG_BADGE08_GET)) // Rain Badge, ignore obedience altogether
|
||||
return 0;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(gBattlerAttacker) == B_POSITION_PLAYER_RIGHT)
|
||||
return OBEYS;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
||||
return OBEYS;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
|
||||
return OBEYS;
|
||||
if (B_OBEDIENCE_MECHANICS < GEN_8 && !IsOtherTrainer(gBattleMons[gBattlerAttacker].otId, gBattleMons[gBattlerAttacker].otName))
|
||||
return OBEYS;
|
||||
if (FlagGet(FLAG_BADGE08_GET)) // Rain Badge, ignore obedience altogether
|
||||
return OBEYS;
|
||||
|
||||
obedienceLevel = 10;
|
||||
obedienceLevel = 10;
|
||||
|
||||
if (FlagGet(FLAG_BADGE01_GET)) // Stone Badge
|
||||
obedienceLevel = 20;
|
||||
if (FlagGet(FLAG_BADGE02_GET)) // Knuckle Badge
|
||||
obedienceLevel = 30;
|
||||
if (FlagGet(FLAG_BADGE03_GET)) // Dynamo Badge
|
||||
obedienceLevel = 40;
|
||||
if (FlagGet(FLAG_BADGE04_GET)) // Heat Badge
|
||||
obedienceLevel = 50;
|
||||
if (FlagGet(FLAG_BADGE05_GET)) // Balance Badge
|
||||
obedienceLevel = 60;
|
||||
if (FlagGet(FLAG_BADGE06_GET)) // Feather Badge
|
||||
obedienceLevel = 70;
|
||||
if (FlagGet(FLAG_BADGE07_GET)) // Mind Badge
|
||||
obedienceLevel = 80;
|
||||
}
|
||||
if (FlagGet(FLAG_BADGE01_GET)) // Stone Badge
|
||||
obedienceLevel = 20;
|
||||
if (FlagGet(FLAG_BADGE02_GET)) // Knuckle Badge
|
||||
obedienceLevel = 30;
|
||||
if (FlagGet(FLAG_BADGE03_GET)) // Dynamo Badge
|
||||
obedienceLevel = 40;
|
||||
if (FlagGet(FLAG_BADGE04_GET)) // Heat Badge
|
||||
obedienceLevel = 50;
|
||||
if (FlagGet(FLAG_BADGE05_GET)) // Balance Badge
|
||||
obedienceLevel = 60;
|
||||
if (FlagGet(FLAG_BADGE06_GET)) // Feather Badge
|
||||
obedienceLevel = 70;
|
||||
if (FlagGet(FLAG_BADGE07_GET)) // Mind Badge
|
||||
obedienceLevel = 80;
|
||||
|
||||
if (B_OBEDIENCE_MECHANICS >= GEN_8
|
||||
&& !IsOtherTrainer(gBattleMons[gBattlerAttacker].otId, gBattleMons[gBattlerAttacker].otName))
|
||||
|
@ -8386,86 +8381,58 @@ u8 IsMonDisobedient(void)
|
|||
levelReferenced = gBattleMons[gBattlerAttacker].level;
|
||||
|
||||
if (levelReferenced <= obedienceLevel)
|
||||
return 0;
|
||||
rnd = (Random() & 255);
|
||||
calc = (levelReferenced + obedienceLevel) * rnd >> 8;
|
||||
return OBEYS;
|
||||
|
||||
rnd = Random();
|
||||
calc = (levelReferenced + obedienceLevel) * (rnd & 255) >> 8;
|
||||
if (calc < obedienceLevel)
|
||||
return 0;
|
||||
return OBEYS;
|
||||
|
||||
// Clear the Z-Move flags if the battler is disobedient as to not waste the Z-Move
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
|
||||
{
|
||||
gBattleStruct->gimmick.activated[gBattlerAttacker][GIMMICK_Z_MOVE] = FALSE;
|
||||
gBattleStruct->gimmick.activeGimmick[GetBattlerSide(gBattlerAttacker)][gBattlerPartyIndexes[gBattlerAttacker]] = GIMMICK_NONE;
|
||||
}
|
||||
|
||||
// is not obedient
|
||||
if (gCurrentMove == MOVE_RAGE)
|
||||
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RAGE;
|
||||
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (gCurrentMove == MOVE_SNORE || gCurrentMove == MOVE_SLEEP_TALK))
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
|
||||
return 1;
|
||||
}
|
||||
return DISOBEYS_WHILE_ASLEEP;
|
||||
|
||||
rnd = (Random() & 255);
|
||||
calc = (levelReferenced + obedienceLevel) * rnd >> 8;
|
||||
calc = (levelReferenced + obedienceLevel) * ((rnd >> 8) & 255) >> 8;
|
||||
if (calc < obedienceLevel)
|
||||
{
|
||||
calc = CheckMoveLimitations(gBattlerAttacker, gBitTable[gCurrMovePos], MOVE_LIMITATIONS_ALL);
|
||||
if (calc == ALL_MOVES_MASK) // all moves cannot be used
|
||||
{
|
||||
// Randomly select, then print a disobedient string
|
||||
// B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
||||
return 1;
|
||||
}
|
||||
return DISOBEYS_LOAFS;
|
||||
else // use a random move
|
||||
{
|
||||
do
|
||||
{
|
||||
gCurrMovePos = gChosenMovePos = MOD(Random(), MAX_MON_MOVES);
|
||||
} while (gBitTable[gCurrMovePos] & calc);
|
||||
|
||||
gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
|
||||
SetAtkCancellerForCalledMove();
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
|
||||
gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
|
||||
gHitMarker |= HITMARKER_DISOBEDIENT_MOVE;
|
||||
return 2;
|
||||
}
|
||||
while (gBitTable[gCurrMovePos] & calc);
|
||||
return DISOBEYS_RANDOM_MOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
obedienceLevel = levelReferenced - obedienceLevel;
|
||||
|
||||
calc = (Random() & 255);
|
||||
calc = ((rnd >> 16) & 255);
|
||||
if (calc < obedienceLevel && CanBeSlept(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)))
|
||||
{
|
||||
// try putting asleep
|
||||
int i;
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattleMons[i].status2 & STATUS2_UPROAR)
|
||||
break;
|
||||
}
|
||||
if (i == gBattlersCount)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
|
||||
return 1;
|
||||
}
|
||||
return DISOBEYS_FALL_ASLEEP;
|
||||
}
|
||||
calc -= obedienceLevel;
|
||||
if (calc < obedienceLevel)
|
||||
{
|
||||
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE, FALSE, TRUE);
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
return 2;
|
||||
}
|
||||
return DISOBEYS_HITS_SELF;
|
||||
else
|
||||
{
|
||||
// Randomly select, then print a disobedient string
|
||||
// B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
|
||||
return 1;
|
||||
}
|
||||
return DISOBEYS_LOAFS;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue