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 NoAliveMonsForBattlerSide(u32 battler);
bool32 NoAliveMonsForPlayer(void); bool32 NoAliveMonsForPlayer(void);
bool32 NoAliveMonsForEitherParty(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); bool32 CanBattlerSwitch(u32 battlerId);
void BattleDestroyYesNoCursorAt(u8 cursorPosition); void BattleDestroyYesNoCursorAt(u8 cursorPosition);
void BattleCreateYesNoCursorAt(u8 cursorPosition); void BattleCreateYesNoCursorAt(u8 cursorPosition);

View File

@ -252,7 +252,7 @@ enum SemiInvulnerableExclusion
#define HITMARKER_UNUSED_10 (1 << 10) #define HITMARKER_UNUSED_10 (1 << 10)
#define HITMARKER_UNUSED_11 (1 << 11) #define HITMARKER_UNUSED_11 (1 << 11)
#define HITMARKER_UNUSED_12 (1 << 12) #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_UNUSED_14 (1 << 14)
#define HITMARKER_RUN (1 << 15) #define HITMARKER_RUN (1 << 15)
#define HITMARKER_UNUSED_16 (1 << 16) #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 #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! // cases for Cmd_moveend - Order matters!
enum MoveEndEffects enum MoveEndEffects
{ {

View File

@ -369,7 +369,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleMons[battler].volatiles.multipleTurns = FALSE; gBattleMons[battler].volatiles.multipleTurns = FALSE;
if (!gBattleMons[battler].volatiles.confusionTurns) 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) if (gBattleMons[battler].volatiles.confusionTurns)
BattleScriptExecute(BattleScript_ThrashConfuses); BattleScriptExecute(BattleScript_ThrashConfuses);
effect = TRUE; effect = TRUE;

View File

@ -218,7 +218,7 @@ static enum ItemEffect TryKingsRock(u32 battlerAtk, u32 battlerDef, u32 item)
&& RandomPercentage(RNG_HOLD_EFFECT_FLINCH, holdEffectParam) && RandomPercentage(RNG_HOLD_EFFECT_FLINCH, holdEffectParam)
&& ability != ABILITY_STENCH) && 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; 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 // 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; s32 i;
bool32 primary = effectFlags & EFFECT_PRIMARY;
bool32 certain = effectFlags & EFFECT_CERTAIN;
bool32 affectsUser = (battler == effectBattler); bool32 affectsUser = (battler == effectBattler);
bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR);
union StatChangeFlags flags = {0}; union StatChangeFlags flags = {0};
@ -2967,14 +2969,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
gEffectBattler = effectBattler; gEffectBattler = effectBattler;
battlerAbility = GetBattlerAbility(gEffectBattler); battlerAbility = GetBattlerAbility(gEffectBattler);
if (!primary && !affectsUser if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility))
&& !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT)
&& IsMoveEffectBlockedByTarget(battlerAbility))
moveEffect = MOVE_EFFECT_NONE; moveEffect = MOVE_EFFECT_NONE;
else if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) else if (!primary
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) && TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE) && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
&& !primary)
moveEffect = MOVE_EFFECT_NONE; moveEffect = MOVE_EFFECT_NONE;
else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint) else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
moveEffect = MOVE_EFFECT_NONE; moveEffect = MOVE_EFFECT_NONE;
@ -2982,7 +2981,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
moveEffect = MOVE_EFFECT_NONE; moveEffect = MOVE_EFFECT_NONE;
gBattleScripting.moveEffect = moveEffect; // ChangeStatBuffs still needs the global moveEffect gBattleScripting.moveEffect = moveEffect; // ChangeStatBuffs still needs the global moveEffect
switch (moveEffect) switch (moveEffect)
{ {
case MOVE_EFFECT_NONE: 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_PARALYSIS:
case MOVE_EFFECT_TOXIC: case MOVE_EFFECT_TOXIC:
case MOVE_EFFECT_FROSTBITE: 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; gBattlescriptCurrInstr = battleScript;
else if (CanSetNonVolatileStatus( else if (CanSetNonVolatileStatus(
gBattlerAttacker, gBattlerAttacker,
@ -3009,7 +3008,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
case MOVE_EFFECT_CONFUSION: case MOVE_EFFECT_CONFUSION:
if (!CanBeConfused(gEffectBattler) if (!CanBeConfused(gEffectBattler)
|| gBattleMons[gEffectBattler].volatiles.confusionTurns || 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; gBattlescriptCurrInstr = battleScript;
} }
@ -3126,7 +3125,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
MOVE_EFFECT_FREEZE_OR_FROSTBITE, MOVE_EFFECT_FREEZE_OR_FROSTBITE,
MOVE_EFFECT_PARALYSIS 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; break;
case MOVE_EFFECT_WRAP: case MOVE_EFFECT_WRAP:
@ -3477,7 +3476,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
if (!gBattleMons[gEffectBattler].status1) if (!gBattleMons[gEffectBattler].status1)
{ {
static const u8 sDireClawEffects[] = { MOVE_EFFECT_POISON, MOVE_EFFECT_PARALYSIS, MOVE_EFFECT_SLEEP }; 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; break;
case MOVE_EFFECT_STEALTH_ROCK: case MOVE_EFFECT_STEALTH_ROCK:
@ -3524,7 +3523,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
} }
} }
else else
SetMoveEffect(battler, effectBattler, gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect, battleScript, primary, certain); SetMoveEffect(battler, effectBattler, gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect, battleScript, effectFlags);
break; break;
case MOVE_EFFECT_PSYCHIC_NOISE: case MOVE_EFFECT_PSYCHIC_NOISE:
battlerAbility = IsAbilityOnSide(gEffectBattler, ABILITY_AROMA_VEIL); battlerAbility = IsAbilityOnSide(gEffectBattler, ABILITY_AROMA_VEIL);
@ -4103,13 +4102,16 @@ static void Cmd_setadditionaleffects(void)
{ {
gBattleCommunication[MULTISTRING_CHOOSER] = *((u8 *) &additionalEffect->multistring); gBattleCommunication[MULTISTRING_CHOOSER] = *((u8 *) &additionalEffect->multistring);
enum SetMoveEffectFlags flags = NO_FLAGS;
if (percentChance == 0) flags |= EFFECT_PRIMARY;
if (percentChance >= 100) flags |= EFFECT_CERTAIN;
SetMoveEffect( SetMoveEffect(
gBattlerAttacker, gBattlerAttacker,
additionalEffect->self ? gBattlerAttacker : gBattlerTarget, additionalEffect->self ? gBattlerAttacker : gBattlerTarget,
additionalEffect->moveEffect, additionalEffect->moveEffect,
cmd->nextInstr, cmd->nextInstr,
percentChance == 0, // a primary effect flags
percentChance >= 100 // certain to happen
); );
} }
} }
@ -4144,7 +4146,7 @@ static void Cmd_seteffectprimary(void)
u32 battler = GetBattlerForBattleScript(cmd->battler); u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler); 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) static void Cmd_seteffectsecondary(void)
@ -4153,7 +4155,7 @@ static void Cmd_seteffectsecondary(void)
u32 battler = GetBattlerForBattleScript(cmd->battler); u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler); 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) static void Cmd_clearvolatile(void)
@ -14331,7 +14333,7 @@ static void Cmd_setnonvolatilestatus(void)
{ {
case TRIGGER_ON_ABILITY: case TRIGGER_ON_ABILITY:
if (gBattleScripting.moveEffect >= MOVE_EFFECT_CONFUSION) 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 else
SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_ABILITY); SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_ABILITY);
break; break;
@ -16356,22 +16358,22 @@ void BS_TryFlingHoldEffect(void)
switch (holdEffect) switch (holdEffect)
{ {
case HOLD_EFFECT_FLAME_ORB: 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; break;
case HOLD_EFFECT_TOXIC_ORB: 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; break;
case HOLD_EFFECT_LIGHT_BALL: 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; break;
case HOLD_EFFECT_TYPE_POWER: case HOLD_EFFECT_TYPE_POWER:
if (GetItemSecondaryId(gLastUsedItem) != TYPE_POISON) if (GetItemSecondaryId(gLastUsedItem) != TYPE_POISON)
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
else else
SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_POISON, cmd->nextInstr, FALSE, FALSE); SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_POISON, cmd->nextInstr, NO_FLAGS);
break; break;
case HOLD_EFFECT_FLINCH: 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; break;
case HOLD_EFFECT_MENTAL_HERB: case HOLD_EFFECT_MENTAL_HERB:
if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation)) if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation))

View File

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