Refactor move Synchronise (#7271)

This commit is contained in:
Alex 2025-07-07 19:36:21 +02:00 committed by GitHub
parent 0422a013c4
commit 7ae97ab6e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 147 additions and 55 deletions

View File

@ -2461,6 +2461,11 @@
.byte \battler
.endm
.macro trysynchronoise jumpInstr:req
callnative BS_TrySynchronoise
.4byte \jumpInstr
.endm
.macro setallytonexttarget jumpInstr:req
jumpifbyte CMP_GREATER_THAN, gBattlerTarget, 0x1, 1f
addbyte gBattlerTarget, 0x2

View File

@ -1622,42 +1622,20 @@ BattleScript_EffectPsychoShiftCanWork:
BattleScript_EffectSynchronoise::
attackcanceler
attackstring
pause B_WAIT_TIME_MED
ppreduce
selectfirstvalidtarget
BattleScript_SynchronoiseLoop:
movevaluescleanup
jumpifcantusesynchronoise BattleScript_SynchronoiseNoEffect
accuracycheck BattleScript_SynchronoiseMissed, ACC_CURR_MOVE
critcalc
damagecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
trysynchronoise BattleScript_MoveEnd
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
goto BattleScript_HitFromCritCalc
BattleScript_ItDoesntAffectFoe::
savetarget
copybyte gBattlerTarget, sBATTLER
printstring STRINGID_ITDOESNTAFFECT
waitmessage B_WAIT_TIME_SHORT
flushtextbox
tryfaintmon BS_TARGET
BattleScript_SynchronoiseMoveTargetEnd:
moveendto MOVEEND_NEXT_TARGET
jumpifnexttargetvalid BattleScript_SynchronoiseLoop
end
BattleScript_SynchronoiseMissed:
pause B_WAIT_TIME_SHORT
resultmessage
waitmessage B_WAIT_TIME_LONG
goto BattleScript_SynchronoiseMoveTargetEnd
BattleScript_SynchronoiseNoEffect:
pause B_WAIT_TIME_SHORT
printstring STRINGID_NOEFFECTONTARGET
waitmessage B_WAIT_TIME_LONG
goto BattleScript_SynchronoiseMoveTargetEnd
restoretarget
return
BattleScript_MoveEffectSmackDown::
printstring STRINGID_FELLSTRAIGHTDOWN

View File

@ -526,7 +526,6 @@ extern const u8 BattleScript_TeraShellDistortingTypeMatchups[];
extern const u8 BattleScript_TeraFormChange[];
extern const u8 BattleScript_SleepClausePreventsEnd[];
extern const u8 BattleScript_PowerConstruct[];
extern const u8 BattleScript_AbilityProtectsDoesntAffect[];
extern const u8 BattleScript_ImmunityProtected[];
extern const u8 BattleScript_SafeguardProtected[];
@ -538,6 +537,7 @@ extern const u8 BattleScript_AlreadyPoisoned[];
extern const u8 BattleScript_AlreadyParalyzed[];
extern const u8 BattleScript_AlreadyBurned[];
extern const u8 BattleScript_PrintAbilityMadeIneffective[];
extern const u8 BattleScript_ItDoesntAffectFoe[];
// zmoves
extern const u8 BattleScript_ZMoveActivateDamaging[];

View File

@ -345,6 +345,7 @@ enum TypeSideHazard
#define MOVE_RESULT_FOE_HUNG_ON (1 << 7)
#define MOVE_RESULT_STURDIED (1 << 8)
#define MOVE_RESULT_FOE_ENDURED_AFFECTION (1 << 9)
#define MOVE_RESULT_SYNCHRONOISE_AFFECTED (1 << 10)
#define MOVE_RESULT_NO_EFFECT (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED)
enum BattleWeather

View File

@ -1242,7 +1242,8 @@ static void Cmd_attackcanceler(void)
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
if (CanAbilityBlockMove(gBattlerAttacker,
if (CanAbilityBlockMove(
gBattlerAttacker,
gBattlerTarget,
GetBattlerAbility(gBattlerAttacker),
abilityDef,
@ -1252,7 +1253,8 @@ static void Cmd_attackcanceler(void)
if (GetMoveNonVolatileStatus(gCurrentMove) == MOVE_EFFECT_PARALYSIS)
{
if (CanAbilityAbsorbMove(gBattlerAttacker,
if (CanAbilityAbsorbMove(
gBattlerAttacker,
gBattlerTarget,
abilityDef,
gCurrentMove,
@ -2418,6 +2420,7 @@ static bool32 ProcessPreAttackAnimationFuncs(void)
if (IsDoubleSpreadMove())
{
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
if (!gBattleStruct->printedStrongWindsWeakenedAttack)
{
for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++)
@ -5957,9 +5960,10 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent)
u32 battler;
for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++)
{
if (battler != gBattlerAttacker
&& !(excludeCurrent && battler == gBattlerTarget)
&& IsBattlerAlive(battler)
if (battler == gBattlerAttacker || !IsBattlerAlive(battler))
continue;
if (!(excludeCurrent && battler == gBattlerTarget)
&& !gBattleStruct->battlerState[gBattlerAttacker].targetsDone[battler]
&& (!IsBattlerAlly(battler, gBattlerAttacker) || moveTarget == MOVE_TARGET_FOES_AND_ALLY))
break;
@ -6665,8 +6669,9 @@ static void Cmd_moveend(void)
MoveValuesCleanUp();
gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect;
if (moveEffect == EFFECT_EXPLOSION || moveEffect == EFFECT_MISTY_EXPLOSION)
BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript); // Edge case for Explosion not changing targets
if (moveEffect == EFFECT_EXPLOSION || moveEffect == EFFECT_MISTY_EXPLOSION // Edge case for Explosion not changing targets
|| moveEffect == EFFECT_SYNCHRONOISE) // So we don't go back to the Synchronoise script
BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript);
else
BattleScriptPush(GetMoveBattleScript(gCurrentMove));
gBattlescriptCurrInstr = BattleScript_FlushMessageBox;
@ -17907,7 +17912,6 @@ void BS_JumpIfSleepClause(void)
void BS_FickleBeamDamageCalculation(void)
{
NATIVE_ARGS();
gBattleStruct->fickleBeamBoosted = FALSE;
if (RandomPercentage(RNG_FICKLE_BEAM, 30))
{
@ -18671,3 +18675,36 @@ void BS_TryActivateAbilityShield(void)
BattleScriptCall(BattleScript_AbilityShieldProtects);
}
}
void BS_TrySynchronoise(void)
{
NATIVE_ARGS(const u8 *jumpInstr);
bool32 atleastOneSharedType = FALSE;
for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++)
{
if (gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_SYNCHRONOISE_AFFECTED
|| gBattlerAttacker == battlerDef
|| !IsBattlerAlive(battlerDef))
continue;
if (DoBattlersShareType(gBattlerAttacker, battlerDef))
{
atleastOneSharedType = TRUE;
continue;
}
if (!DoBattlersShareType(gBattlerAttacker, battlerDef))
{
gBattleScripting.battler = battlerDef;
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_NO_EFFECT | MOVE_RESULT_SYNCHRONOISE_AFFECTED;
BattleScriptCall(BattleScript_ItDoesntAffectFoe);
return;
}
}
if (atleastOneSharedType)
gBattlescriptCurrInstr = cmd->nextInstr;
else
gBattlescriptCurrInstr = cmd->jumpInstr;
}

View File

@ -2513,6 +2513,7 @@ static enum MoveCanceller CancellerMultiTargetMoves(void)
if (gBattlerAttacker == battlerDef
|| !IsBattlerAlive(battlerDef)
|| (GetMoveEffect(gCurrentMove) == EFFECT_SYNCHRONOISE && !DoBattlersShareType(gBattlerAttacker, battlerDef))
|| (moveTarget == MOVE_TARGET_BOTH && gBattlerAttacker == BATTLE_PARTNER(battlerDef))
|| IsBattlerProtected(gBattlerAttacker, battlerDef, gCurrentMove)) // Missing Invulnerable check
{

View File

@ -385,7 +385,7 @@ SINGLE_BATTLE_TEST("(TERA) Synchronoise uses a Terastallized Pokemon's Tera Type
} SCENE {
// turn 1
MESSAGE("The opposing Wobbuffet used Synchronoise!");
MESSAGE("It won't have any effect on Wobbuffet!");
MESSAGE("It doesn't affect Wobbuffet…");
// turn 2
MESSAGE("The opposing Wobbuffet used Synchronoise!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, opponent);

View File

@ -1,4 +1,74 @@
#include "global.h"
#include "test/battle.h"
DOUBLE_BATTLE_TEST("Synchronoise hits all Pokemon that share a type with the attacker")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_SYNCHRONOISE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, playerLeft);
HP_BAR(opponentLeft);
HP_BAR(playerRight);
HP_BAR(opponentRight);
}
}
DOUBLE_BATTLE_TEST("Synchronoise will fail if there is no corresponding typing on the field")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_BULBASAUR);
OPPONENT(SPECIES_BULBASAUR);
OPPONENT(SPECIES_BULBASAUR);
} WHEN {
TURN { MOVE(playerLeft, MOVE_SYNCHRONOISE); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, playerLeft);
MESSAGE("Wobbuffet used Synchronoise!");
MESSAGE("It doesn't affect the opposing Bulbasaur…");
MESSAGE("It doesn't affect Bulbasaur…");
MESSAGE("It doesn't affect the opposing Bulbasaur…");
NOT MESSAGE("But it failed!");
}
}
DOUBLE_BATTLE_TEST("Synchronoise will hit if there is at least one target")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_BULBASAUR);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BULBASAUR);
} WHEN {
TURN { MOVE(playerLeft, MOVE_SYNCHRONOISE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, playerLeft);
HP_BAR(opponentLeft);
NONE_OF {
HP_BAR(playerRight);
HP_BAR(opponentRight);
MESSAGE("But it failed!");
}
}
}
DOUBLE_BATTLE_TEST("Synchronoise will fail if the corresponding typing mon protects")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_BULBASAUR);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BULBASAUR);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_PROTECT); MOVE(playerLeft, MOVE_SYNCHRONOISE); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, playerLeft);
}
}
TO_DO_BATTLE_TEST("TODO: Write Synchronoise (Move Effect) test titles")