diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 7942adf3ab..f066f52ae8 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -199,12 +199,13 @@ BattleScript_EffectDoodle:: attackstring ppreduce trycopyability BS_ATTACKER, BattleScript_ButItFailed + saveattacker attackanimation waitanimation setbyte gBattleCommunication, 0 goto BattleScript_EffectDoodle_AfterCopy BattleScript_EffectDoodle_CopyAbility: - trycopyability BS_ATTACKER, BattleScript_MoveEnd + trycopyability BS_ATTACKER, BattleScript_EffectDoodleMoveEnd BattleScript_EffectDoodle_AfterCopy: .if B_ABILITY_POP_UP == TRUE copybyte gBattlerAbility, gBattlerAttacker @@ -216,8 +217,10 @@ BattleScript_EffectDoodle_AfterCopy: switchinabilities BS_ATTACKER jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_MoveEnd addbyte gBattleCommunication, 1 - jumpifnoally BS_ATTACKER, BattleScript_MoveEnd + jumpifnoally BS_ATTACKER, BattleScript_EffectDoodleMoveEnd setallytonextattacker BattleScript_EffectDoodle_CopyAbility +BattleScript_EffectDoodleMoveEnd: + restoreattacker goto BattleScript_MoveEnd BattleScript_EffectGlaiveRush:: diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 4db4aea969..4728c17a84 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -279,6 +279,7 @@ void InitBattleControllers(void); bool32 IsValidForBattle(struct Pokemon *mon); void TryReceiveLinkBattleData(void); void PrepareBufferDataTransferLink(u32 battler, u32 bufferId, u16 size, u8 *data); +void UpdateFriendshipFromXItem(u32 battler); // emitters void BtlController_EmitGetMonData(u32 battler, u32 bufferId, u8 requestId, u8 monToCheck); diff --git a/include/constants/item_effects.h b/include/constants/item_effects.h index ac1c7d5c5b..dbe322beac 100644 --- a/include/constants/item_effects.h +++ b/include/constants/item_effects.h @@ -93,4 +93,8 @@ #define ITEM_EFFECT_HEAL_PP 21 #define ITEM_EFFECT_NONE 22 +// Since X item stat increases are now handled by battle scripts, the friendship increase effect is now handled by the battle controller in HandleAction_UseItem. +#define X_ITEM_FRIENDSHIP_INCREASE 1 // The amount of friendship gained by using an X item on a Pokémon in battle. +#define X_ITEM_MAX_FRIENDSHIP 200 // Friendship threshold at which Pokémon stop receiving a friendship increase from using X items on them in battle. + #endif // GUARD_CONSTANTS_ITEM_EFFECTS_H diff --git a/include/pokemon.h b/include/pokemon.h index cd7925cf14..ba459480e1 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -881,6 +881,7 @@ uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier) u32 GetRegionalFormByRegion(u32 species, u32 region); bool32 IsSpeciesForeignRegionalForm(u32 species, u32 currentRegion); u32 GetTeraTypeFromPersonality(struct Pokemon *mon); +bool8 ShouldSkipFriendshipChange(void); struct Pokemon *GetSavedPlayerPartyMon(u32 index); u8 *GetSavedPlayerPartyCount(void); void SavePlayerPartyMon(u32 index, struct Pokemon *mon); diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index e49c9f2003..128862994b 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6863,6 +6863,32 @@ static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner) SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp); } +static void TrySwapAttractBattlerIds(u32 battlerAtk, u32 battlerPartner) +{ + u32 attractedTo; + + // our own infatuation handled with gBattleMons struct data swapping + + // if another battler is infatuated with one of us, change to other battler + for (u32 i = 0; i < gBattlersCount; i++) + { + if (i == battlerAtk || i == battlerPartner || !gBattleMons[i].volatiles.infatuation) + continue; + + attractedTo = INFATUATED_WITH(i); + if (attractedTo == battlerAtk) + { + gBattleMons[i].volatiles.infatuation = INFATUATED_WITH(battlerPartner); + break; + } + else if (attractedTo == battlerPartner) + { + gBattleMons[i].volatiles.infatuation = INFATUATED_WITH(battlerAtk); + break; + } + } +} + static void SwapBattlerMoveData(u32 battler1, u32 battler2) { u32 temp; @@ -6933,6 +6959,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) TrySwapSkyDropTargets(battlerAtk, battlerPartner); TrySwapStickyWebBattlerId(battlerAtk, battlerPartner); TrySwapWishBattlerIds(battlerAtk, battlerPartner); + TrySwapAttractBattlerIds(battlerAtk, battlerPartner); // For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target. for (i = 0; i < gBattlersCount; i++) diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 81b6035f23..f2880d31af 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -12,9 +12,11 @@ #include "battle_tv.h" #include "cable_club.h" #include "event_object_movement.h" +#include "item.h" #include "link.h" #include "link_rfu.h" #include "m4a.h" +#include "overworld.h" #include "palette.h" #include "party_menu.h" #include "recorded_battle.h" @@ -25,6 +27,7 @@ #include "util.h" #include "text.h" #include "constants/abilities.h" +#include "constants/item_effects.h" #include "constants/songs.h" #include "pokemon_animation.h" @@ -3078,3 +3081,46 @@ void BtlController_HandleSwitchInTryShinyAnim(u32 battler) } } } + +void UpdateFriendshipFromXItem(u32 battler) +{ + struct Pokemon *party = GetBattlerParty(battler); + + u8 friendship; + gBattleResources->bufferA[battler][1] = REQUEST_FRIENDSHIP_BATTLE; + GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], &friendship); + + u16 heldItem; + gBattleResources->bufferA[battler][1] = REQUEST_HELDITEM_BATTLE; + GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], (u8*)&heldItem); + + if (friendship < X_ITEM_MAX_FRIENDSHIP) + { + if (GetItemHoldEffect(heldItem) == HOLD_EFFECT_FRIENDSHIP_UP) + friendship += 150 * X_ITEM_FRIENDSHIP_INCREASE / 100; + else + friendship += X_ITEM_FRIENDSHIP_INCREASE; + + u8 pokeball; + gBattleResources->bufferA[battler][1] = REQUEST_POKEBALL_BATTLE; + GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], &pokeball); + + if (pokeball == BALL_LUXURY) + friendship++; + + u8 metLocation; + gBattleResources->bufferA[battler][1] = REQUEST_MET_LOCATION_BATTLE; + GetBattlerMonData(battler, party, gBattlerPartyIndexes[battler], &metLocation); + + if (metLocation == GetCurrentRegionMapSectionId()) + friendship++; + + if (friendship > MAX_FRIENDSHIP) + friendship = MAX_FRIENDSHIP; + + gBattleMons[battler].friendship = friendship; + gBattleResources->bufferA[battler][3] = friendship; + gBattleResources->bufferA[battler][1] = REQUEST_FRIENDSHIP_BATTLE; + SetBattlerMonData(battler, GetBattlerParty(battler), gBattlerPartyIndexes[battler]); + } +} diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e0e268af5d..c08324b6e8 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5524,28 +5524,6 @@ static inline bool32 IsProtectivePadsProtected(u32 battler, enum ItemHoldEffect return TRUE; } -static inline bool32 IsProtectEffectAffected(u32 battler, u32 move) -{ - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - if (IsProtectivePadsProtected(battler, holdEffect)) - return TRUE; - - if (holdEffect == HOLD_EFFECT_CLEAR_AMULET) - { - RecordItemEffectBattle(battler, holdEffect); - return TRUE; - } - - u32 ability = GetBattlerAbility(gBattlerAttacker); - if (CanAbilityPreventStatLoss(ability)) - { - RecordAbilityBattle(battler, ability); - return TRUE; - } - - return FALSE; -} - static inline bool32 CanEjectButtonTrigger(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect) { if (GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_EJECT_BUTTON diff --git a/src/battle_util.c b/src/battle_util.c index 4232634a5f..de7cec8d58 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -44,6 +44,7 @@ #include "constants/battle_string_ids.h" #include "constants/hold_effects.h" #include "constants/items.h" +#include "constants/item_effects.h" #include "constants/moves.h" #include "constants/songs.h" #include "constants/species.h" @@ -598,6 +599,11 @@ void HandleAction_UseItem(void) ClearVariousBattlerFlags(gBattlerAttacker); gLastUsedItem = gBattleResources->bufferB[gBattlerAttacker][1] | (gBattleResources->bufferB[gBattlerAttacker][2] << 8); + if (X_ITEM_FRIENDSHIP_INCREASE > 0 + && GetItemEffectType(gLastUsedItem) == ITEM_EFFECT_X_ITEM + && !ShouldSkipFriendshipChange()) + UpdateFriendshipFromXItem(gBattlerAttacker); + gBattlescriptCurrInstr = gBattlescriptsForUsingItem[GetItemBattleUsage(gLastUsedItem) - 1]; gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; } @@ -873,11 +879,11 @@ void HandleAction_NothingIsFainted(void) gCurrentTurnActionNumber++; gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE; - gHitMarker &= ~(HITMARKER_DESTINYBOND - | HITMARKER_IGNORE_SUBSTITUTE + gHitMarker &= ~(HITMARKER_DESTINYBOND + | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_NO_PPDEDUCT - | HITMARKER_STATUS_ABILITY_EFFECT + | HITMARKER_NO_PPDEDUCT + | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_OBEYS); } @@ -890,13 +896,13 @@ void HandleAction_ActionFinished(void) gCurrentTurnActionNumber++; gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; SpecialStatusesClear(); - gHitMarker &= ~(HITMARKER_DESTINYBOND - | HITMARKER_IGNORE_SUBSTITUTE + gHitMarker &= ~(HITMARKER_DESTINYBOND + | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_NO_PPDEDUCT - | HITMARKER_STATUS_ABILITY_EFFECT + | HITMARKER_NO_PPDEDUCT + | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_HP_UPDATE - | HITMARKER_OBEYS + | HITMARKER_OBEYS | HITMARKER_IGNORE_DISGUISE); ClearDamageCalcResults(); @@ -8776,6 +8782,14 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) RecordAbilityBattle(battlerDef, ABILITY_THICK_FAT); } break; + case ABILITY_PURIFYING_SALT: + if (moveType == TYPE_GHOST) + { + modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5)); + if (ctx->updateFlags) + RecordAbilityBattle(battlerDef, ABILITY_PURIFYING_SALT); + } + break; } // ally's abilities @@ -8858,31 +8872,38 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) uq4_12_t modifier; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; enum BattleMoveEffects moveEffect = GetMoveEffect(move); - if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM) // the defense stats are swapped - { - def = gBattleMons[battlerDef].spDefense; - spDef = gBattleMons[battlerDef].defense; - } - else - { - def = gBattleMons[battlerDef].defense; - spDef = gBattleMons[battlerDef].spDefense; - } + def = gBattleMons[battlerDef].defense; + spDef = gBattleMons[battlerDef].spDefense; if (moveEffect == EFFECT_PSYSHOCK || IsBattleMovePhysical(move)) // uses defense stat instead of sp.def { - defStat = def; + if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM) // the defense stats are swapped + { + defStat = spDef; + usesDefStat = FALSE; + } + else + { + defStat = def; + usesDefStat = TRUE; + } defStage = gBattleMons[battlerDef].statStages[STAT_DEF]; - usesDefStat = TRUE; } else // is special { - defStat = spDef; + if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM) // the defense stats are swapped + { + defStat = def; + usesDefStat = TRUE; + } + else + { + defStat = spDef; + usesDefStat = FALSE; + } defStage = gBattleMons[battlerDef].statStages[STAT_SPDEF]; - usesDefStat = FALSE; } // Self-destruct / Explosion cut defense in half @@ -8937,10 +8958,6 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) if (gBattleMons[battlerDef].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && !usesDefStat) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; - case ABILITY_PURIFYING_SALT: - if (moveType == TYPE_GHOST) - modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); - break; } // ally's abilities diff --git a/src/data/pokemon/item_effects.h b/src/data/pokemon/item_effects.h index 93ff78ad7c..851424021f 100644 --- a/src/data/pokemon/item_effects.h +++ b/src/data/pokemon/item_effects.h @@ -334,14 +334,8 @@ const u8 gItemEffect_PPMax[9] = { VITAMIN_FRIENDSHIP_CHANGE(6), }; -#define STAT_BOOST_FRIENDSHIP_CHANGE \ - [6] = 1, /* Friendship change, low */ \ - [7] = 1 /* Friendship change, mid */ - const u8 gItemEffect_GuardSpec[8] = { [3] = ITEM3_GUARD_SPEC, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; // The first item effect value for the stat boost items @@ -350,44 +344,30 @@ const u8 gItemEffect_GuardSpec[8] = { const u8 gItemEffect_DireHit[8] = { [0] = 1 << 5, // ITEM0_DIRE_HIT - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_XAttack[8] = { [1] = ITEM1_X_ATTACK, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_XDefense[8] = { [1] = ITEM1_X_DEFENSE, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_XSpeed[8] = { [1] = ITEM1_X_SPEED, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_XAccuracy[8] = { [1] = ITEM1_X_ACCURACY, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_XSpecialAttack[8] = { [1] = ITEM1_X_SPATK, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_XSpecialDefense[8] = { [1] = ITEM1_X_SPDEF, - [5] = ITEM5_FRIENDSHIP_LOW | ITEM5_FRIENDSHIP_MID, - STAT_BOOST_FRIENDSHIP_CHANGE, }; const u8 gItemEffect_EvoItem[6] = { diff --git a/src/pokemon.c b/src/pokemon.c index b76683254e..745c761356 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -82,7 +82,6 @@ static union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u32 perso static void EncryptBoxMon(struct BoxPokemon *boxMon); static void DecryptBoxMon(struct BoxPokemon *boxMon); static void Task_PlayMapChosenOrBattleBGM(u8 taskId); -static bool8 ShouldSkipFriendshipChange(void); void TrySpecialOverworldEvo(); EWRAM_DATA static u8 sLearningMoveTableID = 0; @@ -6358,7 +6357,7 @@ bool8 HasTwoFramesAnimation(u16 species) && !gTestRunnerHeadless; } -static bool8 ShouldSkipFriendshipChange(void) +bool8 ShouldSkipFriendshipChange(void) { if (gMain.inBattle && gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) return TRUE; diff --git a/src/vs_seeker.c b/src/vs_seeker.c index 15829c3bd5..1a7dc68c72 100644 --- a/src/vs_seeker.c +++ b/src/vs_seeker.c @@ -529,7 +529,6 @@ void ClearRematchMovementByTrainerId(void) TryGetObjectEventIdByLocalIdAndMap(objectEventTemplates[i].localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objEventId); objectEvent = &gObjectEvents[objEventId]; - GetRandomFaceDirectionMovementType(&objectEventTemplates[i]); TryOverrideTemplateCoordsForObjectEvent(objectEvent, sFaceDirectionMovementTypeByFacingDirection[objectEvent->facingDirection]); if (gSelectedObjectEvent == objEventId) @@ -705,22 +704,11 @@ static u8 GetResponseMovementTypeFromTrainerGraphicsId(u8 graphicsId) #endif //FREE_MATCH_CALL static u16 GetTrainerFlagFromScript(const u8 *script) - /* - * The trainer flag is a little-endian short located +2 from - * the script pointer, assuming the trainerbattle command is - * first in the script. Because scripts are unaligned, and - * because the ARM processor requires shorts to be 16-bit - * aligned, this function needs to perform explicit bitwise - * operations to get the correct flag. - * - * 5c XX YY ZZ ... - * -- -- - */ { - u16 trainerFlag; - - script += 2; - trainerFlag = script[0]; + // The trainer flag is located 3 bytes (command + flags + localIdA) from the script pointer, assuming the trainerbattle command is first in the script. + // Because scripts are unaligned, and because the ARM processor requires shorts to be 16-bit aligned, this function needs to perform explicit bitwise operations to get the correct flag. + script += 3; + u16 trainerFlag = script[0]; trainerFlag |= script[1] << 8; return trainerFlag; } diff --git a/test/battle/item_effect/increase_stat.c b/test/battle/item_effect/increase_stat.c index 3f162ea828..b56f1a2b84 100644 --- a/test/battle/item_effect/increase_stat.c +++ b/test/battle/item_effect/increase_stat.c @@ -1,5 +1,6 @@ #include "global.h" #include "test/battle.h" +#include "constants/item_effects.h" SINGLE_BATTLE_TEST("X Attack sharply raises battler's Attack stat", s16 damage) { @@ -257,3 +258,25 @@ SINGLE_BATTLE_TEST("Max Mushrooms raises battler's Speed stat", s16 damage) } } } + +SINGLE_BATTLE_TEST("Using X items in battle raises Friendship", s16 damage) +{ + u32 startingFriendship; + u8 metLocation = MAPSEC_NONE; + PARAMETRIZE { startingFriendship = 0; } + PARAMETRIZE { startingFriendship = X_ITEM_MAX_FRIENDSHIP; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Friendship(startingFriendship); }; + // Set met location to MAPSEC_NONE to avoid getting the friendship boost + // from being met in the current map section + SetMonData(&PLAYER_PARTY[0], MON_DATA_MET_LOCATION, &metLocation); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_X_ACCURACY); MOVE(opponent, MOVE_CELEBRATE); } + } THEN { + if (startingFriendship == X_ITEM_MAX_FRIENDSHIP) + EXPECT_EQ(player->friendship, X_ITEM_MAX_FRIENDSHIP); + else + EXPECT_EQ(player->friendship, X_ITEM_FRIENDSHIP_INCREASE); + } +} diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index b808183fbd..e3f99cb73b 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -348,5 +348,63 @@ DOUBLE_BATTLE_TEST("Ally switch updates last used moves for Mimic") } } +DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed battler") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_SOLOSIS); + OPPONENT(SPECIES_BULBASAUR) { HP(50); MaxHP(100); } + OPPONENT(SPECIES_RALTS) { HP(50); MaxHP(100); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_LEECH_SEED, target: playerLeft); } + TURN { MOVE(opponentRight, MOVE_ALLY_SWITCH); } + TURN { ; } + } SCENE { + // turn 1 + MESSAGE("The opposing Bulbasaur used Leech Seed!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_LEECH_SEED, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_LEECH_SEED_DRAIN, playerLeft); + HP_BAR(playerLeft); + HP_BAR(opponentLeft); + + MESSAGE("The opposing Ralts used Ally Switch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); + MESSAGE("The opposing Ralts and the opposing Bulbasaur switched places!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_LEECH_SEED_DRAIN, playerLeft); + HP_BAR(playerLeft); + HP_BAR(opponentLeft); // Ralts now gets hp gain + } THEN { + EXPECT_GT(opponentLeft->hp, 50); + EXPECT_GT(opponentRight->hp, 50); + } +} + +DOUBLE_BATTLE_TEST("Ally Switch updates attract battler") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(100); Gender(MON_MALE); } + PLAYER(SPECIES_SOLOSIS) { Speed(50); } + OPPONENT(SPECIES_CLEFAIRY) { Speed(20); Gender(MON_FEMALE); Ability(ABILITY_CUTE_CHARM); } + OPPONENT(SPECIES_RALTS) { Speed(30); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + TURN { MOVE(opponentRight, MOVE_ALLY_SWITCH); } + TURN { ; } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Tackle!"); + HP_BAR(opponentLeft); + ABILITY_POPUP(opponentLeft, ABILITY_CUTE_CHARM); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_INFATUATION, playerLeft); + MESSAGE("The opposing Clefairy's Cute Charm infatuated Wobbuffet!"); + // turn 2 + MESSAGE("The opposing Ralts used Ally Switch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); + MESSAGE("The opposing Ralts and the opposing Clefairy switched places!"); + // turn 3 + MESSAGE("Wobbuffet is in love with the opposing Clefairy!"); // tracks attract battler + } +} + // Triple Battles required to test //TO_DO_BATTLE_TEST("Ally Switch fails if the user is in the middle of the field in a Triple Battle"); diff --git a/test/battle/move_effect/embargo.c b/test/battle/move_effect/embargo.c index 3e86b60b0b..4b06b92fc1 100644 --- a/test/battle/move_effect/embargo.c +++ b/test/battle/move_effect/embargo.c @@ -114,28 +114,32 @@ SINGLE_BATTLE_TEST("Embargo negates a held item's Speed reduction") } } -WILD_BATTLE_TEST("Embargo doesn't block held item effects that affect friendship") -{ - u32 initialFriendship; - u32 finalFriendship; +// This is a useful test, but under the current circumstances, we can't actually test this without modifying +// X_ITEM_FRIENDSHIP_INCREASE. Since HOLD_EFFECT_FRIENDSHIP_UP applies a 1.5x modifier, and the stock +// Friendship increase is 1, the held item effect actually does not affect the Friendship gained. +// +// WILD_BATTLE_TEST("Embargo doesn't block held item effects that affect friendship") +// { +// u32 initialFriendship; +// u32 finalFriendship; - KNOWN_FAILING; // Pokémon are currently not obtaining Friendship for using items in battle. - GIVEN { - ASSUME(gItemsInfo[ITEM_X_ACCURACY].battleUsage == EFFECT_ITEM_INCREASE_STAT); - PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SOOTHE_BELL); }; - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { USE_ITEM(player, ITEM_X_ACCURACY); } - TURN { MOVE(player, MOVE_SING); } - } SCENE { - MESSAGE("Wobbuffet used Sing!"); - MESSAGE("Wild Wobbuffet fell asleep!"); - } THEN { - initialFriendship = GetMonData(&PLAYER_PARTY[0], MON_DATA_FRIENDSHIP); - finalFriendship = GetMonData(&gPlayerParty[0], MON_DATA_FRIENDSHIP); - EXPECT_EQ(finalFriendship, initialFriendship + 2); - } -} +// KNOWN_FAILING; // Pokémon are currently not obtaining Friendship for using items in battle. +// GIVEN { +// ASSUME(gItemsInfo[ITEM_X_ACCURACY].battleUsage == EFFECT_ITEM_INCREASE_STAT); +// PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SOOTHE_BELL); }; +// OPPONENT(SPECIES_WOBBUFFET); +// } WHEN { +// TURN { USE_ITEM(player, ITEM_X_ACCURACY); } +// TURN { MOVE(player, MOVE_SING); } +// } SCENE { +// MESSAGE("Wobbuffet used Sing!"); +// MESSAGE("Wild Wobbuffet fell asleep!"); +// } THEN { +// initialFriendship = GetMonData(&PLAYER_PARTY[0], MON_DATA_FRIENDSHIP); +// finalFriendship = GetMonData(&gPlayerParty[0], MON_DATA_FRIENDSHIP); +// EXPECT_EQ(finalFriendship, initialFriendship + 2); +// } +// } SINGLE_BATTLE_TEST("Embargo doesn't block a held item's form-changing effect, but it does block its other effects", s16 damage) {