Clean up ability effect hitmarker (#8138)

This commit is contained in:
Alex 2025-11-04 22:44:57 +01:00 committed by GitHub
parent 473a0aa44d
commit 0f14a4db57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 53 additions and 32 deletions

View File

@ -48,7 +48,7 @@ u32 GetBattlerTurnOrderNum(u32 battler);
bool32 NoAliveMonsForBattlerSide(u32 battler);
bool32 NoAliveMonsForPlayer(void);
bool32 NoAliveMonsForEitherParty(void);
void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, bool32 primary, bool32 certain);
void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags);
bool32 CanBattlerSwitch(u32 battlerId);
void BattleDestroyYesNoCursorAt(u8 cursorPosition);
void BattleCreateYesNoCursorAt(u8 cursorPosition);

View File

@ -252,7 +252,7 @@ enum SemiInvulnerableExclusion
#define HITMARKER_UNUSED_10 (1 << 10)
#define HITMARKER_UNUSED_11 (1 << 11)
#define HITMARKER_UNUSED_12 (1 << 12)
#define HITMARKER_STATUS_ABILITY_EFFECT (1 << 13)
#define HITMARKER_UNUSED_13 (1 << 13)
#define HITMARKER_UNUSED_14 (1 << 14)
#define HITMARKER_RUN (1 << 15)
#define HITMARKER_UNUSED_16 (1 << 16)

View File

@ -125,6 +125,13 @@ enum CmdVarious
#define PARTY_SCREEN_OPTIONAL (1 << 7) // Flag for first argument to openpartyscreen
enum SetMoveEffectFlags
{
NO_FLAGS = 0,
EFFECT_PRIMARY = (1 << 0),
EFFECT_CERTAIN = (1 << 1),
};
// cases for Cmd_moveend - Order matters!
enum MoveEndEffects
{

View File

@ -369,7 +369,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleMons[battler].volatiles.multipleTurns = FALSE;
if (!gBattleMons[battler].volatiles.confusionTurns)
{
SetMoveEffect(battler, battler, MOVE_EFFECT_CONFUSION, gBattlescriptCurrInstr, TRUE, FALSE);
SetMoveEffect(battler, battler, MOVE_EFFECT_CONFUSION, gBattlescriptCurrInstr, EFFECT_PRIMARY);
if (gBattleMons[battler].volatiles.confusionTurns)
BattleScriptExecute(BattleScript_ThrashConfuses);
effect = TRUE;

View File

@ -218,7 +218,7 @@ static enum ItemEffect TryKingsRock(u32 battlerAtk, u32 battlerDef, u32 item)
&& RandomPercentage(RNG_HOLD_EFFECT_FLINCH, holdEffectParam)
&& ability != ABILITY_STENCH)
{
SetMoveEffect(battlerAtk, battlerDef, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, FALSE, FALSE);
SetMoveEffect(battlerAtk, battlerDef, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, NO_FLAGS);
effect = ITEM_EFFECT_OTHER;
}

View File

@ -2931,9 +2931,11 @@ static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, cons
}
// To avoid confusion the arguments are naned battler/effectBattler since they can be different from gBattlerAttacker/gBattlerTarget
void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, bool32 primary, bool32 certain)
void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags)
{
s32 i;
bool32 primary = effectFlags & EFFECT_PRIMARY;
bool32 certain = effectFlags & EFFECT_CERTAIN;
bool32 affectsUser = (battler == effectBattler);
bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR);
union StatChangeFlags flags = {0};
@ -2967,14 +2969,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
gEffectBattler = effectBattler;
battlerAbility = GetBattlerAbility(gEffectBattler);
if (!primary && !affectsUser
&& !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT)
&& IsMoveEffectBlockedByTarget(battlerAbility))
if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility))
moveEffect = MOVE_EFFECT_NONE;
else if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT)
else if (!primary
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE)
&& !primary)
&& !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
moveEffect = MOVE_EFFECT_NONE;
else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
moveEffect = MOVE_EFFECT_NONE;
@ -2982,7 +2981,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
moveEffect = MOVE_EFFECT_NONE;
gBattleScripting.moveEffect = moveEffect; // ChangeStatBuffs still needs the global moveEffect
switch (moveEffect)
{
case MOVE_EFFECT_NONE:
@ -2995,7 +2994,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
case MOVE_EFFECT_PARALYSIS:
case MOVE_EFFECT_TOXIC:
case MOVE_EFFECT_FROSTBITE:
if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary)
if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary)
gBattlescriptCurrInstr = battleScript;
else if (CanSetNonVolatileStatus(
gBattlerAttacker,
@ -3009,7 +3008,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
case MOVE_EFFECT_CONFUSION:
if (!CanBeConfused(gEffectBattler)
|| gBattleMons[gEffectBattler].volatiles.confusionTurns
|| (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary))
|| (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary))
{
gBattlescriptCurrInstr = battleScript;
}
@ -3126,7 +3125,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
MOVE_EFFECT_FREEZE_OR_FROSTBITE,
MOVE_EFFECT_PARALYSIS
};
SetMoveEffect(battler, effectBattler, RandomElement(RNG_TRI_ATTACK, sTriAttackEffects), battleScript, primary, certain);
SetMoveEffect(battler, effectBattler, RandomElement(RNG_TRI_ATTACK, sTriAttackEffects), battleScript, effectFlags);
}
break;
case MOVE_EFFECT_WRAP:
@ -3477,7 +3476,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
if (!gBattleMons[gEffectBattler].status1)
{
static const u8 sDireClawEffects[] = { MOVE_EFFECT_POISON, MOVE_EFFECT_PARALYSIS, MOVE_EFFECT_SLEEP };
SetMoveEffect(battler, effectBattler, RandomElement(RNG_DIRE_CLAW, sDireClawEffects), battleScript, primary, certain);
SetMoveEffect(battler, effectBattler, RandomElement(RNG_DIRE_CLAW, sDireClawEffects), battleScript, effectFlags);
}
break;
case MOVE_EFFECT_STEALTH_ROCK:
@ -3524,7 +3523,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
}
}
else
SetMoveEffect(battler, effectBattler, gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect, battleScript, primary, certain);
SetMoveEffect(battler, effectBattler, gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect, battleScript, effectFlags);
break;
case MOVE_EFFECT_PSYCHIC_NOISE:
battlerAbility = IsAbilityOnSide(gEffectBattler, ABILITY_AROMA_VEIL);
@ -4103,13 +4102,16 @@ static void Cmd_setadditionaleffects(void)
{
gBattleCommunication[MULTISTRING_CHOOSER] = *((u8 *) &additionalEffect->multistring);
enum SetMoveEffectFlags flags = NO_FLAGS;
if (percentChance == 0) flags |= EFFECT_PRIMARY;
if (percentChance >= 100) flags |= EFFECT_CERTAIN;
SetMoveEffect(
gBattlerAttacker,
additionalEffect->self ? gBattlerAttacker : gBattlerTarget,
additionalEffect->moveEffect,
cmd->nextInstr,
percentChance == 0, // a primary effect
percentChance >= 100 // certain to happen
flags
);
}
}
@ -4144,7 +4146,7 @@ static void Cmd_seteffectprimary(void)
u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler);
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, TRUE, FALSE);
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY);
}
static void Cmd_seteffectsecondary(void)
@ -4153,7 +4155,7 @@ static void Cmd_seteffectsecondary(void)
u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler);
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY);
}
static void Cmd_clearvolatile(void)
@ -14331,7 +14333,7 @@ static void Cmd_setnonvolatilestatus(void)
{
case TRIGGER_ON_ABILITY:
if (gBattleScripting.moveEffect >= MOVE_EFFECT_CONFUSION)
SetMoveEffect(gBattleScripting.battler, gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(gBattleScripting.battler, gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY);
else
SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_ABILITY);
break;
@ -16356,22 +16358,22 @@ void BS_TryFlingHoldEffect(void)
switch (holdEffect)
{
case HOLD_EFFECT_FLAME_ORB:
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_BURN, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_BURN, cmd->nextInstr, NO_FLAGS);
break;
case HOLD_EFFECT_TOXIC_ORB:
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_TOXIC, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_TOXIC, cmd->nextInstr, NO_FLAGS);
break;
case HOLD_EFFECT_LIGHT_BALL:
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_PARALYSIS, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_PARALYSIS, cmd->nextInstr, NO_FLAGS);
break;
case HOLD_EFFECT_TYPE_POWER:
if (GetItemSecondaryId(gLastUsedItem) != TYPE_POISON)
gBattlescriptCurrInstr = cmd->nextInstr;
else
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_POISON, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_POISON, cmd->nextInstr, NO_FLAGS);
break;
case HOLD_EFFECT_FLINCH:
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, cmd->nextInstr, FALSE, FALSE);
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, cmd->nextInstr, NO_FLAGS);
break;
case HOLD_EFFECT_MENTAL_HERB:
if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation))

View File

@ -914,7 +914,7 @@ void HandleAction_NothingIsFainted(void)
gCurrentTurnActionNumber++;
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE;
gHitMarker &= ~(HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_OBEYS);
gHitMarker &= ~(HITMARKER_OBEYS);
}
void HandleAction_ActionFinished(void)
@ -925,7 +925,7 @@ void HandleAction_ActionFinished(void)
gCurrentTurnActionNumber++;
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses));
gHitMarker &= ~(HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_OBEYS);
gHitMarker &= ~(HITMARKER_OBEYS);
ClearDamageCalcResults();
gCurrentMove = 0;
@ -4969,7 +4969,6 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptCall(BattleScript_GooeyActivates);
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
effect++;
}
break;
@ -5326,7 +5325,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH))
{
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, FALSE, FALSE);
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, EFFECT_PRIMARY);
effect++;
}
break;
@ -5349,7 +5348,6 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptCall(BattleScript_AbilityStatusEffect);
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
effect++;
}
break;

View File

@ -97,3 +97,17 @@ SINGLE_BATTLE_TEST("Tangling Hair does not trigger on Clear Body")
NOT ABILITY_POPUP(player, ABILITY_TANGLING_HAIR);
}
}
SINGLE_BATTLE_TEST("Tangling Hair will trigger if move is boosted by Sheer Force")
{
ASSUME(MoveIsAffectedBySheerForce(MOVE_POISON_JAB));
GIVEN {
PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); }
OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); };
} WHEN {
TURN { MOVE(opponent, MOVE_POISON_JAB); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_JAB, opponent);
ABILITY_POPUP(player, ABILITY_TANGLING_HAIR);
}
}