diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 28648814d8..5dd00b2b6a 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -8022,7 +8022,7 @@ BattleScript_QuarkDriveActivates:: BattleScript_RuinAbilityActivates:: call BattleScript_AbilityPopUp - printstring STRINGID_ABILITYWEAKENEDFSURROUNDINGMONSSTAT + printstring STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT waitmessage B_WAIT_TIME_LONG end3 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 4167522f18..b337d5f92a 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -635,7 +635,7 @@ #define STRINGID_SUNLIGHTACTIVATEDABILITY 633 #define STRINGID_STATWASHEIGHTENED 634 #define STRINGID_ELECTRICTERRAINACTIVATEDABILITY 635 -#define STRINGID_ABILITYWEAKENEDFSURROUNDINGMONSSTAT 636 +#define STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT 636 #define STRINGID_ATTACKERGAINEDSTRENGTHFROMTHEFALLEN 637 #define STRINGID_PKMNSABILITYPREVENTSABILITY 638 #define STRINGID_PREPARESHELLTRAP 639 diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 28ae094c08..18dd3fc0c7 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -439,9 +439,9 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef) return TRUE; break; case EFFECT_HIT_SET_REMOVE_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) - return TRUE; - break; + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && gMovesInfo[move].argument == ARG_TRY_REMOVE_TERRAIN_FAIL) + return TRUE; + break; } return FALSE; diff --git a/src/battle_main.c b/src/battle_main.c index 8385572bc4..42dfbbee00 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3536,6 +3536,7 @@ void SwitchInClearSetData(u32 battler) // Reset damage to prevent things like red card activating if the switched-in mon is holding it gSpecialStatuses[battler].physicalDmg = 0; gSpecialStatuses[battler].specialDmg = 0; + gBattleStruct->enduredDamage &= ~gBitTable[battler]; // Reset G-Max Chi Strike boosts. gBattleStruct->bonusCritStages[battler] = 0; diff --git a/src/battle_message.c b/src/battle_message.c index d630520953..7b9faea10f 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -797,8 +797,8 @@ static const u8 sText_SunlightActivatedAbility[] = _("The harsh sunlight activat static const u8 sText_StatWasHeightened[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1} was heightened!"); static const u8 sText_BoosterEnergyActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used its Booster Energy\nto activate {B_SCR_ACTIVE_ABILITY}!"); static const u8 sText_ElectricTerrainActivatedAbility[] = _("The Electric Terrain activated\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ABILITY}!"); -static const u8 sText_AbilityWeakenedSurroundingMonsStat[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY}\nweakened the {B_BUFF1} of\lall surrounding Pokémon!\p"); -static const u8 sText_AttackerGainedStrengthFromTheFallen[] = _("{B_ATK_NAME_WITH_PREFIX} gained strength\nfrom the fallen!"); +static const u8 sText_AbilityWeakenedSurroundingMonsStat[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nweakened the {B_BUFF1} of\lall surrounding Pokémon!\p"); +static const u8 sText_AttackerGainedStrengthFromTheFallen[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} gained strength\nfrom the fallen!"); static const u8 sText_PrepareShellTrap[] = _("{B_ATK_NAME_WITH_PREFIX} set a shell trap!"); static const u8 sText_ShellTrapDidntWork[] = _("{B_ATK_NAME_WITH_PREFIX}'s shell trap didn't work!"); static const u8 sText_SharpSteelFloats[] = _("Sharp-pointed steel floats\naround {B_DEF_TEAM2} team!"); @@ -896,7 +896,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_SHARPSTEELDMG - BATTLESTRINGS_TABLE_START] = sText_SharpSteelDmg, [STRINGID_SHARPSTEELFLOATS - BATTLESTRINGS_TABLE_START] = sText_SharpSteelFloats, [STRINGID_ATTACKERGAINEDSTRENGTHFROMTHEFALLEN - BATTLESTRINGS_TABLE_START] = sText_AttackerGainedStrengthFromTheFallen, - [STRINGID_ABILITYWEAKENEDFSURROUNDINGMONSSTAT - BATTLESTRINGS_TABLE_START] = sText_AbilityWeakenedSurroundingMonsStat, + [STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT - BATTLESTRINGS_TABLE_START] = sText_AbilityWeakenedSurroundingMonsStat, [STRINGID_ELECTRICTERRAINACTIVATEDABILITY - BATTLESTRINGS_TABLE_START] = sText_ElectricTerrainActivatedAbility, [STRINGID_STATWASHEIGHTENED - BATTLESTRINGS_TABLE_START] = sText_StatWasHeightened, [STRINGID_BOOSTERENERGYACTIVATES - BATTLESTRINGS_TABLE_START] = sText_BoosterEnergyActivates, diff --git a/src/battle_util.c b/src/battle_util.c index 7446c05a23..8044c33a2b 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4748,6 +4748,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && CountBattlerStatIncreases(BATTLE_PARTNER(battler), FALSE)) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattlerAttacker = battler; for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[battler].statStages[i] = gBattleMons[BATTLE_PARTNER(battler)].statStages[i]; gBattlerTarget = BATTLE_PARTNER(battler); @@ -4764,6 +4765,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !(gBattleStruct->transformZeroToHero[side] & gBitTable[gBattlerPartyIndexes[battler]])) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattlerAttacker = battler; gBattleStruct->transformZeroToHero[side] |= gBitTable[gBattlerPartyIndexes[battler]]; BattleScriptPushCursorAndCallback(BattleScript_ZeroToHeroActivates); effect++; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 0899e55a86..dca295f851 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -132,6 +132,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .metronomeBanned = TRUE, .mirrorMoveBanned = TRUE, .sketchBanned = TRUE, + .assistBanned = TRUE, }, [MOVE_POUND] = @@ -14114,6 +14115,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Whips up a storm of\n" "diamonds. May up Defense."), + .effect = EFFECT_HIT, .power = 100, .type = TYPE_ROCK, .accuracy = 95, @@ -18726,7 +18728,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .name = COMPOUND_STRING("Mortal Spin"), .description = COMPOUND_STRING( "Erases trap moves and Leech\n" - "Seed. Poisons adjecent foes."), + "Seed. Poisons adjacent foes."), .effect = EFFECT_HIT, .power = 30, .type = TYPE_POISON, diff --git a/src/party_menu.c b/src/party_menu.c index 5fa741385d..f5782a1346 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -4600,7 +4600,8 @@ void ItemUseCB_BattleScript(u8 taskId, TaskFunc task) gBattleStruct->itemPartyIndex[gBattlerInMenuId] = GetPartyIdFromBattleSlot(gPartyMenu.slotId); gPartyMenuUseExitCallback = TRUE; PlaySE(SE_SELECT); - RemoveBagItem(gSpecialVar_ItemId, 1); + if (!IsItemFlute(gSpecialVar_ItemId)) + RemoveBagItem(gSpecialVar_ItemId, 1); ScheduleBgCopyTilemapToVram(2); gTasks[taskId].func = task; } diff --git a/test/battle/hold_effect/eject_pack.c b/test/battle/hold_effect/eject_pack.c index 6757b11db9..7640292079 100644 --- a/test/battle/hold_effect/eject_pack.c +++ b/test/battle/hold_effect/eject_pack.c @@ -6,7 +6,7 @@ ASSUMPTIONS ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK); } -SINGLE_BATTLE_TEST("Eject Pack does not cause the new pokemon to lose hp due to it's held Life Orb") +SINGLE_BATTLE_TEST("Eject Pack does not cause the new Pokémon to lose HP due to it's held Life Orb") { GIVEN { ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); @@ -26,7 +26,7 @@ SINGLE_BATTLE_TEST("Eject Pack does not cause the new pokemon to lose hp due to } } -SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no pokemon left to battle") +SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no Pokémon left to battle") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); } @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no pokemon left to } } -SINGLE_BATTLE_TEST("Eject Pack triggers on the correct pokemon") +SINGLE_BATTLE_TEST("Eject Pack is triggered by self-inflicting stat decreases") { GIVEN { ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index ce4ac80b96..8d7e175cea 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -447,4 +447,25 @@ SINGLE_BATTLE_TEST("Red Card does not cause the dragged out mon to lose hp due t } } +SINGLE_BATTLE_TEST("Red Card does not activate if holder is switched in mid-turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_ENDURE); MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet is switched out with the Eject Button!"); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); + } + } +} + // SINGLE_BATTLE_TEST("Red Card activates but fails if the attacker has Dynamaxed") diff --git a/test/battle/move_effect/hit_set_remove_terrain.c b/test/battle/move_effect/hit_set_remove_terrain.c index 834b2dc223..549b6bf04f 100644 --- a/test/battle/move_effect/hit_set_remove_terrain.c +++ b/test/battle/move_effect/hit_set_remove_terrain.c @@ -82,3 +82,45 @@ SINGLE_BATTLE_TEST("Ice Spinner doesn't fail if there is no terrain on the field NOT MESSAGE("But it failed!"); } } + +AI_SINGLE_BATTLE_TEST("Steel Roller will not be chosen by the AI if it might fail") +{ + u32 move; + + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_NONE; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STEEL_ROLLER, MOVE_ICE_SHARD); } + } WHEN { + if (move == MOVE_ELECTRIC_TERRAIN) { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } + TURN { EXPECT_MOVE(opponent, MOVE_STEEL_ROLLER); } + } else { + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } + } + } +} + +AI_SINGLE_BATTLE_TEST("Ice Spinner can be chosen by the AI regardless if there is a terrain or not") +{ + u32 move; + + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_NONE; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_ICE_SPINNER, MOVE_ICE_SHARD); } + } WHEN { + if (move == MOVE_ELECTRIC_TERRAIN) { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + } else { + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + } + } +}