diff --git a/README.md b/README.md index 5e83f9793b..cc978678c6 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Also, *please follow the Pull Request template and feel free to discuss how the - Fairy Type (configurable). - Physical/Special/Status Category (configurable). - New moves and abilities up to Scarlet and Violet. - - Custom Contest data up to SwSh, newer moves are WIP. ([source](https://pokemonurpg.com/info/contests/rse-move-list/)) + - Custom Contest data up to SwSh, newer moves are WIP. ([source](https://web.archive.org/web/20240910012333/https://pokemonurpg.com/info/contests/rse-move-list/)) - Battle gimmick support: - Mega Evolution - Primal Reversion diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a169b3580b..e50cbcbe43 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2376,6 +2376,10 @@ callnative BS_SwapStats .byte \stat .endm + + .macro restoresavedmove + callnative BS_RestoreSavedMove + .endm @ helpful macros .macro setstatchanger stat:req, stages:req, down:req diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 748fa2c5be..aaa03f0ac6 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6045,6 +6045,8 @@ BattleScript_RoarSuccessSwitch:: BattleScript_RoarSuccessSwitch_Ret: swapattackerwithtarget @ continuation of RedCardActivates restoretarget + restoreattacker + restoresavedmove setbyte sSWITCH_CASE, B_SWITCH_NORMAL return @@ -9519,6 +9521,8 @@ BattleScript_RedCardActivationNoSwitch:: waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING restoretarget + restoreattacker + restoresavedmove return BattleScript_RedCardActivates:: @@ -9537,22 +9541,17 @@ BattleScript_RedCardEnd: return BattleScript_RedCardIngrain: printstring STRINGID_PKMNANCHOREDITSELF +BattleScript_RedCardIngrainContinue: waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING restoretarget return BattleScript_RedCardSuctionCups: - printstring STRINGID_PKMNANCHORSITSELFWITH - waitmessage B_WAIT_TIME_LONG - removeitem BS_SCRIPTING - restoretarget - return + printstring STRINGID_PKMNANCHORSITSELFWITH + goto BattleScript_RedCardIngrainContinue BattleScript_RedCardDynamaxed: printstring STRINGID_MOVEBLOCKEDBYDYNAMAX - waitmessage B_WAIT_TIME_LONG - removeitem BS_SCRIPTING - restoretarget - return + goto BattleScript_RedCardIngrainContinue BattleScript_EjectButtonActivates:: makevisible BS_ATTACKER diff --git a/include/battle.h b/include/battle.h index 27227544d9..c9517b9b71 100644 --- a/include/battle.h +++ b/include/battle.h @@ -836,6 +836,7 @@ struct BattleStruct struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; u8 embodyAspectBoost[NUM_BATTLE_SIDES]; + u16 savedMove; // backup current move for mid-turn switching, e.g. Red Card }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 2cbc25b003..2aa5799a9e 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -293,13 +293,13 @@ enum MoveEndEffects MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc MOVEEND_CHANGED_ITEMS, MOVEEND_PICKPOCKET, - MOVEEND_DANCER, MOVEEND_EMERGENCY_EXIT, MOVEEND_SYMBIOSIS, MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts MOVEEND_SAME_MOVE_TURNS, MOVEEND_SET_EVOLUTION_TRACKER, MOVEEND_CLEAR_BITS, + MOVEEND_DANCER, MOVEEND_PURSUIT_NEXT_ACTION, MOVEEND_COUNT, }; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 6244245d82..e04ca63e68 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -5072,7 +5072,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } -// Adds score bonus to best powered move +// Adds score bonus to OHKOs and 2HKOs static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 5bac769eb6..b84b87d0ed 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -1719,9 +1719,9 @@ static void MoveSelectionDisplayMoveType(u32 battler) { if (speciesId == SPECIES_OGERPON_WELLSPRING || speciesId == SPECIES_OGERPON_WELLSPRING_TERA - || speciesId == SPECIES_OGERPON_HEARTHFLAME || speciesId == SPECIES_OGERPON_HEARTHFLAME_TERA - || speciesId == SPECIES_OGERPON_CORNERSTONE || speciesId == SPECIES_OGERPON_CORNERSTONE_TERA) - type = gBattleMons[battler].types[1]; + || speciesId == SPECIES_OGERPON_HEARTHFLAME || speciesId == SPECIES_OGERPON_HEARTHFLAME_TERA + || speciesId == SPECIES_OGERPON_CORNERSTONE || speciesId == SPECIES_OGERPON_CORNERSTONE_TERA) + type = gSpeciesInfo[speciesId].types[1]; } else if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS && (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX))) diff --git a/src/battle_main.c b/src/battle_main.c index 3045632af3..d7b90bd76d 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5668,7 +5668,7 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) { // To account for Battle Factory and Slateport Battle Tent, enemy parties are zeroed out in the facilitites respective src/xxx.c files // The ZeroEnemyPartyMons() call happens in SaveXXXChallenge function (eg. SaveFactoryChallenge) - if (!(gBattleTypeFlags & BATTLE_TYPE_FRONTIER)) + if (!(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_ROAMER))) { ZeroEnemyPartyMons(); } @@ -5741,6 +5741,7 @@ static void ReturnFromBattleToOverworld(void) if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) { UpdateRoamerHPStatus(&gEnemyParty[0]); + ZeroEnemyPartyMons(); #ifndef BUGFIX if ((gBattleOutcome & B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) @@ -5962,19 +5963,19 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost) case SPECIES_TAUROS_PALDEA_COMBAT: case SPECIES_TAUROS_PALDEA_BLAZE: case SPECIES_TAUROS_PALDEA_AQUA: - return type2; + return gSpeciesInfo[species].types[1]; } break; case EFFECT_IVY_CUDGEL: switch (species) { case SPECIES_OGERPON_WELLSPRING: - case SPECIES_OGERPON_HEARTHFLAME: - case SPECIES_OGERPON_CORNERSTONE: case SPECIES_OGERPON_WELLSPRING_TERA: + case SPECIES_OGERPON_HEARTHFLAME: case SPECIES_OGERPON_HEARTHFLAME_TERA: + case SPECIES_OGERPON_CORNERSTONE: case SPECIES_OGERPON_CORNERSTONE_TERA: - return type2; + return gSpeciesInfo[species].types[1]; } break; case EFFECT_NATURAL_GIFT: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 1154660af2..cfceeb9845 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7075,6 +7075,8 @@ static void Cmd_moveend(void) { gLastUsedItem = gBattleMons[battler].item; SaveBattlerTarget(battler); // save battler with red card + SaveBattlerAttacker(gBattlerAttacker); + gBattleStruct->savedMove = gCurrentMove; gBattleScripting.battler = battler; gEffectBattler = gBattlerAttacker; gBattleStruct->redCardActivates = TRUE; @@ -7141,49 +7143,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_DANCER: // Special case because it's so annoying - if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) - { - u32 battler, nextDancer = 0; - bool32 hasDancerTriggered = FALSE; - - for (battler = 0; battler < gBattlersCount; battler++) - { - if (gSpecialStatuses[battler].dancerUsedMove) - { - // in case a battler fails to act on a Dancer-called move - hasDancerTriggered = TRUE; - break; - } - } - - if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE) - || (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE && !hasDancerTriggered) - || (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove && gBattleStruct->bouncedMoveIsUsed))) - { // Dance move succeeds - // Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move - if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) - { - gBattleScripting.savedBattler = gBattlerTarget | 0x4; - gBattleScripting.savedBattler |= (gBattlerAttacker << 4); - gSpecialStatuses[gBattlerAttacker].dancerUsedMove = TRUE; - } - for (battler = 0; battler < gBattlersCount; battler++) - { - if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove) - { - if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed)) - nextDancer = battler | 0x4; - } - } - if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, 0)) - effect = TRUE; - - ClearDamageCalcResults(); - } - } - gBattleScripting.moveendState++; - break; case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out for (i = 0; i < gBattlersCount; i++) { @@ -7289,8 +7248,6 @@ static void Cmd_moveend(void) gBattleStruct->isAtkCancelerForCalledMove = FALSE; gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->categoryOverride = FALSE; - gBattleStruct->bouncedMoveIsUsed = FALSE; - gBattleStruct->snatchedMoveIsUsed = FALSE; gBattleStruct->additionalEffectsCounter = 0; gBattleStruct->poisonPuppeteerConfusion = FALSE; gBattleStruct->fickleBeamBoosted = FALSE; @@ -7303,7 +7260,6 @@ static void Cmd_moveend(void) if (B_CHARGE >= GEN_9 && moveType == TYPE_ELECTRIC && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) gStatuses3[gBattlerAttacker] &= ~(STATUS3_CHARGED_UP); memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); - ClearDamageCalcResults(); for (i = 0; i < gBattlersCount; i++) { @@ -7318,6 +7274,47 @@ static void Cmd_moveend(void) } } + gBattleScripting.moveendState++; + break; + case MOVEEND_DANCER: // Special case because it's so annoying + if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) + { + u32 battler, nextDancer = 0; + bool32 hasDancerTriggered = FALSE; + + for (battler = 0; battler < gBattlersCount; battler++) + { + if (gSpecialStatuses[battler].dancerUsedMove) + { + // in case a battler fails to act on a Dancer-called move + hasDancerTriggered = TRUE; + break; + } + } + + if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE) + || (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE && !hasDancerTriggered) + || (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove && gBattleStruct->bouncedMoveIsUsed))) + { // Dance move succeeds + // Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + { + gBattleScripting.savedBattler = gBattlerTarget | 0x4; + gBattleScripting.savedBattler |= (gBattlerAttacker << 4); + gSpecialStatuses[gBattlerAttacker].dancerUsedMove = TRUE; + } + for (battler = 0; battler < gBattlersCount; battler++) + { + if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove) + { + if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed)) + nextDancer = battler | 0x4; + } + } + if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, 0)) + effect = TRUE; + } + } gBattleScripting.moveendState++; break; case MOVEEND_PURSUIT_NEXT_ACTION: @@ -8743,6 +8740,7 @@ static void ResetValuesForCalledMove(void) gBattleScripting.animTargetsHit = 0; SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker); HandleMoveTargetRedirection(); + ClearDamageCalcResults(); } static void Cmd_jumptocalledmove(void) @@ -18644,3 +18642,16 @@ void BS_SetSteelsurge(void) gBattlescriptCurrInstr = cmd->nextInstr; } } + +void BS_RestoreSavedMove(void) +{ + NATIVE_ARGS(); + + if (gBattleStruct->savedMove == MOVE_NONE) + DebugPrintfLevel(MGBA_LOG_WARN, "restoresavedmove was called with no move saved!"); + + gCurrentMove = gBattleStruct->savedMove; + gBattleStruct->savedMove = MOVE_NONE; + gBattlescriptCurrInstr = cmd->nextInstr; +} + diff --git a/src/battle_util.c b/src/battle_util.c index dd6360cbd0..44a0b678b4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -811,6 +811,8 @@ void HandleAction_ActionFinished(void) gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; gBattleStruct->dynamicMoveType = 0; + gBattleStruct->bouncedMoveIsUsed = FALSE; + gBattleStruct->snatchedMoveIsUsed = FALSE; gBattleScripting.moveendState = 0; gBattleCommunication[3] = 0; gBattleCommunication[4] = 0; diff --git a/src/berry.c b/src/berry.c index 4730799e0c..fd6cac9679 100644 --- a/src/berry.c +++ b/src/berry.c @@ -2174,6 +2174,11 @@ void ObjectEventInteractionGetBerryCountString(void) u8 berry = GetBerryTypeByBerryTreeId(treeId); u8 count = GetBerryCountByBerryTreeId(treeId); + // The strings for growing Berries all refer to a singular berry plant. + // This ensures that text about planting a Berry and the growing Berry reads correctly. + if (GetStageByBerryTreeId(treeId) != BERRY_STAGE_BERRIES) + count = 1; + gSpecialVar_0x8006 = BerryTypeToItemId(berry); CopyItemNameHandlePlural(BerryTypeToItemId(berry), gStringVar1, count); berry = GetTreeMutationValue(treeId); diff --git a/src/data/pokemon/species_info/gen_7_families.h b/src/data/pokemon/species_info/gen_7_families.h index 3fcd15848f..8b1e4d369b 100644 --- a/src/data/pokemon/species_info/gen_7_families.h +++ b/src/data/pokemon/species_info/gen_7_families.h @@ -7508,7 +7508,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .natDexNum = NATIONAL_DEX_MELMETAL, .categoryName = _("Hex Nut"), .height = 25, - .weight = 800, + .weight = 8000, .description = COMPOUND_STRING( "Revered long ago for its capacity to\n" "create iron from nothing, for some reason\n" diff --git a/src/data/trainers.party b/src/data/trainers.party index 14304518b6..f1a8f3e84e 100644 --- a/src/data/trainers.party +++ b/src/data/trainers.party @@ -46,7 +46,7 @@ Optional fields for Pokemon: (Order does not matter) - EVs (252 HP / 128 Spe / 48 Def, defaults to all 0, is not capped at 512 total) (Order does not matter) - - Ball (Poke Ball or ITEM_POKE_BALL, defaults to Poke Ball + - Ball (Poke Ball or ITEM_POKE_BALL, defaults to Poke Ball) - Happiness (Number between 1 and 255) - Nature (Rash or NATURE_RASH, defaults to Hardy) - Shiny (Yes/No, defaults to No) diff --git a/src/pokemon.c b/src/pokemon.c index 6bec95c307..5340691b46 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2002,6 +2002,19 @@ u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove) } } + // Handler for if Zacian or Zamazenta should learn Iron Head + // since it transforms in the Behemoth Blade/Bash move in + // battle in the Crowned forms. + if (learnset[sLearningMoveTableID].move == MOVE_IRON_HEAD && (species == SPECIES_ZAMAZENTA_CROWNED || species == SPECIES_ZACIAN_CROWNED)) + { + for (u32 accessor = MON_DATA_MOVE1; accessor <= MON_DATA_MOVE4; accessor++) + { + u32 move = GetMonData(mon, accessor); + if (move == MOVE_BEHEMOTH_BLADE || move == MOVE_BEHEMOTH_BASH) + return MOVE_NONE; + } + } + if (learnset[sLearningMoveTableID].level == level) { gMoveToLearn = learnset[sLearningMoveTableID].move; diff --git a/test/battle/ability/dancer.c b/test/battle/ability/dancer.c index 657a126470..de33121e13 100644 --- a/test/battle/ability/dancer.c +++ b/test/battle/ability/dancer.c @@ -39,7 +39,7 @@ DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targe GIVEN { ASSUME(IsDanceMove(MOVE_TEETER_DANCE)); ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); - PLAYER(SPECIES_WOBBUFFET) + PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT) { Item(ITEM_LUM_BERRY); } OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Item(ITEM_LUM_BERRY); } OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); } @@ -58,10 +58,10 @@ DOUBLE_BATTLE_TEST("Dancer triggers from slowest to fastest") { GIVEN { ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); - PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); } + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } PLAYER(SPECIES_WYNAUT) { Speed(50); } OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } - OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(3); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(3); } } WHEN { TURN { MOVE(playerRight, MOVE_DRAGON_DANCE); } } SCENE { @@ -103,7 +103,7 @@ DOUBLE_BATTLE_TEST("Dancer still triggers if another dancer flinches") GIVEN { ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); - PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); } + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } PLAYER(SPECIES_WYNAUT) { Speed(5); } OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } @@ -114,9 +114,9 @@ DOUBLE_BATTLE_TEST("Dancer still triggers if another dancer flinches") ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); ABILITY_POPUP(playerLeft, ABILITY_DANCER); - MESSAGE("Wobbuffet flinched and couldn't move!"); + MESSAGE("Oricorio flinched and couldn't move!"); NONE_OF { - MESSAGE("Wobbuffet used Dragon Dance!"); + MESSAGE("Oricorio used Dragon Dance!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); } @@ -246,3 +246,91 @@ DOUBLE_BATTLE_TEST("Dancer doesn't call a move that didn't execute due to Powder } } } + + +DOUBLE_BATTLE_TEST("Dancer still activates after Red Card") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) ; + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } + PLAYER(SPECIES_CHANSEY); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_BULBASAUR); + OPPONENT(SPECIES_SHUCKLE); + } WHEN { + TURN { MOVE(playerLeft, MOVE_FIERY_DANCE, target: opponentLeft); } + } SCENE { + MESSAGE("Wobbuffet used Fiery Dance!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerLeft); + HP_BAR(opponentLeft); + // Red card trigger + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); + MESSAGE("The opposing Wobbuffet held up its Red Card against Wobbuffet!"); + MESSAGE("Chansey was dragged out!"); + // Dancer + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerRight); + HP_BAR(opponentLeft); + } +} + +DOUBLE_BATTLE_TEST("Dancer still activate after Red Card even if blocked by Suction Cups") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SUCTION_CUPS); } + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } + PLAYER(SPECIES_CHANSEY); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_BULBASAUR); + OPPONENT(SPECIES_SHUCKLE); + } WHEN { + TURN { MOVE(playerLeft, MOVE_FIERY_DANCE, target: opponentLeft); } + } SCENE { + MESSAGE("Wobbuffet used Fiery Dance!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerLeft); + HP_BAR(opponentLeft); + // red card trigger + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); + MESSAGE("The opposing Wobbuffet held up its Red Card against Wobbuffet!"); + MESSAGE("Wobbuffet anchors itself with Suction Cups!"); + NOT MESSAGE("Chansey was dragged out!"); + // Dancer + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerRight); + HP_BAR(opponentLeft); + } +} + +DOUBLE_BATTLE_TEST("Dancer correctly restores move targets") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_REVELATION_DANCE)); + PLAYER(SPECIES_ORICORIO) { Speed(10); } + PLAYER(SPECIES_ORICORIO) { Speed(3); } + OPPONENT(SPECIES_ORICORIO) { Speed(1); } + OPPONENT(SPECIES_ORICORIO) { Speed(5); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_REVELATION_DANCE, target: opponentLeft); + MOVE(opponentRight, MOVE_TACKLE, target: playerRight); + MOVE(playerRight, MOVE_TACKLE, target: opponentRight); + MOVE(opponentLeft, MOVE_TACKLE, target: playerRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, playerLeft); + HP_BAR(opponentLeft); + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, opponentLeft); + HP_BAR(playerLeft); + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, playerRight); + HP_BAR(opponentLeft); + ABILITY_POPUP(opponentRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, opponentRight); + HP_BAR(playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight); + HP_BAR(playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); + HP_BAR(opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft); + HP_BAR(playerRight); + } +} diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index 88b208cf50..8513e795b9 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -520,3 +520,4 @@ SINGLE_BATTLE_TEST("Red Card activates before Eject Pack") ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); } } +