Converted Relic Song into a proper form change (#7139)

This commit is contained in:
Eduardo Quezada 2025-06-16 18:02:25 -04:00 committed by GitHub
parent 221ff8ed47
commit 651e87af5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 88 additions and 113 deletions

View File

@ -1447,10 +1447,6 @@
callnative BS_SetGlaiveRush
.endm
.macro tryrelicsong
callnative BS_TryRelicSong
.endm
.macro setpledge jumpInstr:req
callnative BS_SetPledge
.4byte \jumpInstr

View File

@ -1094,13 +1094,6 @@ BattleScript_JungleHealingTryRestoreAlly:
setallytonexttarget JungleHealing_RestoreTargetHealth
goto BattleScript_MoveEnd
BattleScript_EffectRelicSong::
call BattleScript_EffectHit_Ret
tryfaintmon BS_TARGET
moveendall
tryrelicsong
end
BattleScript_EffectAllySwitch::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE

View File

@ -819,7 +819,6 @@ extern const u8 BattleScript_EffectShoreUp[];
extern const u8 BattleScript_EffectGeomancy[];
extern const u8 BattleScript_EffectFairyLock[];
extern const u8 BattleScript_EffectAllySwitch[];
extern const u8 BattleScript_EffectRelicSong[];
extern const u8 BattleScript_MoveEffectEerieSpell[];
extern const u8 BattleScript_EffectJungleHealing[];
extern const u8 BattleScript_EffectCoaching[];

View File

@ -281,7 +281,6 @@ enum BattleMoveEffects
EFFECT_GEOMANCY,
EFFECT_FAIRY_LOCK,
EFFECT_ALLY_SWITCH,
EFFECT_RELIC_SONG,
EFFECT_BODY_PRESS,
EFFECT_JUNGLE_HEALING,
EFFECT_COACHING,

View File

@ -277,6 +277,7 @@ enum MoveEndEffects
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
MOVEEND_EJECT_BUTTON,
MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc
MOVEEND_FORM_CHANGE,
MOVEEND_EMERGENCY_EXIT,
MOVEEND_EJECT_PACK,
MOVEEND_HIT_ESCAPE,

View File

@ -126,6 +126,9 @@ enum FormChanges
// param1: move to check
// param2: ability to check, optional
FORM_CHANGE_BATTLE_BEFORE_MOVE,
// Form change that activates after using a move.
// param1: move to check
FORM_CHANGE_BATTLE_AFTER_MOVE,
// Form change that activates before using a specific move category.
// param1: move category to check
// param2: ability to check, optional

View File

@ -7247,6 +7247,14 @@ static void Cmd_moveend(void)
}
gBattleScripting.moveendState++;
break;
case MOVEEND_FORM_CHANGE:
if (TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_AFTER_MOVE))
{
effect = TRUE;
BattleScriptCall(BattleScript_AttackerFormChangeMoveEffect);
}
gBattleScripting.moveendState++;
break;
case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out
{
// Because sorting the battlers by speed takes lots of cycles,
@ -17358,28 +17366,6 @@ void BS_SetGlaiveRush(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
// TODO: Convert this to a proper FORM_CHANGE type.
void BS_TryRelicSong(void)
{
NATIVE_ARGS();
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SHEER_FORCE && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED)
&& (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_ARIA || gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_PIROUETTE))
{
if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_ARIA)
gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_PIROUETTE;
else if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_PIROUETTE)
gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_ARIA;
BattleScriptPush(cmd->nextInstr);
gBattlescriptCurrInstr = BattleScript_AttackerFormChangeMoveEffect;
}
else
{
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
void BS_SetPledge(void)
{
NATIVE_ARGS(const u8 *jumpInstr);

View File

@ -10052,6 +10052,7 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_BEFORE_MOVE:
case FORM_CHANGE_BATTLE_AFTER_MOVE:
if (formChanges[i].param1 == gCurrentMove
&& (formChanges[i].param2 == ABILITY_NONE || formChanges[i].param2 == GetBattlerAbility(battler)))
targetSpecies = formChanges[i].targetSpecies;

View File

@ -1798,12 +1798,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_RELIC_SONG] =
{
.battleScript = BattleScript_EffectRelicSong,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_BODY_PRESS] =
{
.battleScript = BattleScript_EffectHit,

View File

@ -13993,7 +13993,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"Attacks with an ancient\n"
"song. May induce sleep."),
.effect = EFFECT_RELIC_SONG,
.effect = EFFECT_HIT,
.power = 75,
.type = TYPE_NORMAL,
.accuracy = 100,

View File

@ -771,15 +771,17 @@ static const struct FormChange sKeldeoFormChangeTable[] = {
#if P_FAMILY_MELOETTA
static const struct FormChange sMeloettaFormChangeTable[] = {
{FORM_CHANGE_FAINT, SPECIES_MELOETTA_ARIA},
{FORM_CHANGE_END_BATTLE, SPECIES_MELOETTA_ARIA},
{FORM_CHANGE_BATTLE_AFTER_MOVE, SPECIES_MELOETTA_PIROUETTE, MOVE_RELIC_SONG},
{FORM_CHANGE_BATTLE_AFTER_MOVE, SPECIES_MELOETTA_ARIA, MOVE_RELIC_SONG},
{FORM_CHANGE_FAINT, SPECIES_MELOETTA_ARIA},
{FORM_CHANGE_END_BATTLE, SPECIES_MELOETTA_ARIA},
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_MELOETTA
#if P_FAMILY_GENESECT
static const struct FormChange sGenesectFormChangeTable[] = {
{FORM_CHANGE_ITEM_HOLD, SPECIES_GENESECT, ITEM_NONE},
{FORM_CHANGE_ITEM_HOLD, SPECIES_GENESECT, ITEM_NONE},
{FORM_CHANGE_ITEM_HOLD, SPECIES_GENESECT_DOUSE, ITEM_DOUSE_DRIVE},
{FORM_CHANGE_ITEM_HOLD, SPECIES_GENESECT_SHOCK, ITEM_SHOCK_DRIVE},
{FORM_CHANGE_ITEM_HOLD, SPECIES_GENESECT_BURN, ITEM_BURN_DRIVE},

View File

@ -1,74 +1,6 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_RELIC_SONG) == EFFECT_RELIC_SONG);
ASSUME(MoveHasAdditionalEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP) == TRUE);
}
SINGLE_BATTLE_TEST("Relic Song has a 10% chance to put the target to sleep")
{
PASSES_RANDOMLY(10, 100, RNG_SECONDARY_EFFECT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent);
STATUS_ICON(opponent, sleep: TRUE);
}
}
SINGLE_BATTLE_TEST("Relic Song is prevented by Soundproof")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VOLTORB) { Ability(ABILITY_SOUNDPROOF); }
} WHEN {
TURN { MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_SOUNDPROOF);
MESSAGE("The opposing Voltorb's Soundproof blocks Relic Song!");
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
HP_BAR(opponent);
}
}
}
SINGLE_BATTLE_TEST("Relic Song will become a Water-type move when used by a Pokémon with the Ability Liquid Voice")
{
GIVEN {
PLAYER(SPECIES_VULPIX);
OPPONENT(SPECIES_POPPLIO) { Ability(ABILITY_LIQUID_VOICE); }
} WHEN {
TURN { MOVE(opponent, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, opponent);
HP_BAR(player);
MESSAGE("It's super effective!");
}
}
SINGLE_BATTLE_TEST("Relic Song is blocked by Throat Chop")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_THROAT_CHOP); MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, opponent);
HP_BAR(player);
MESSAGE("The effects of Throat Chop prevent Wobbuffet from using certain moves!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
}
}
SINGLE_BATTLE_TEST("Relic Song transforms Meloetta if used successfully")
{
GIVEN {

View File

@ -0,0 +1,69 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(MoveHasAdditionalEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP) == TRUE);
}
SINGLE_BATTLE_TEST("Relic Song has a 10% chance to put the target to sleep")
{
PASSES_RANDOMLY(10, 100, RNG_SECONDARY_EFFECT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent);
STATUS_ICON(opponent, sleep: TRUE);
}
}
SINGLE_BATTLE_TEST("Relic Song is prevented by Soundproof")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_VOLTORB) { Ability(ABILITY_SOUNDPROOF); }
} WHEN {
TURN { MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_SOUNDPROOF);
MESSAGE("The opposing Voltorb's Soundproof blocks Relic Song!");
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
HP_BAR(opponent);
}
}
}
SINGLE_BATTLE_TEST("Relic Song will become a Water-type move when used by a Pokémon with the Ability Liquid Voice")
{
GIVEN {
PLAYER(SPECIES_VULPIX);
OPPONENT(SPECIES_POPPLIO) { Ability(ABILITY_LIQUID_VOICE); }
} WHEN {
TURN { MOVE(opponent, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, opponent);
HP_BAR(player);
MESSAGE("It's super effective!");
}
}
SINGLE_BATTLE_TEST("Relic Song is blocked by Throat Chop")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_THROAT_CHOP); MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, opponent);
HP_BAR(player);
MESSAGE("The effects of Throat Chop prevent Wobbuffet from using certain moves!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
}
}