Restore X item friendship increase (#7583)

This commit is contained in:
RavePossum 2025-08-26 16:17:30 -04:00 committed by GitHub
parent a45d36d90f
commit 2fbf45d057
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 107 additions and 43 deletions

View File

@ -277,6 +277,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);

View File

@ -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

View File

@ -830,5 +830,6 @@ 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);
#endif // GUARD_POKEMON_H

View File

@ -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"
@ -3260,3 +3263,46 @@ bool32 SwitchIn_TryShinyAnimUtil(u32 battler)
return TRUE;
}
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]);
}
}

View File

@ -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"
@ -580,6 +581,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;
}

View File

@ -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] = {

View File

@ -80,7 +80,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;
@ -6385,7 +6384,7 @@ bool8 HasTwoFramesAnimation(u16 species)
&& !gTestRunnerHeadless;
}
static bool8 ShouldSkipFriendshipChange(void)
bool8 ShouldSkipFriendshipChange(void)
{
if (gMain.inBattle && gBattleTypeFlags & (BATTLE_TYPE_FRONTIER))
return TRUE;

View File

@ -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);
}
}

View File

@ -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)
{