diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 8b64d3e0e1..be0ae0adbb 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -27497,9 +27497,9 @@ General_AffectionHangedOn:: createvisualtask AnimTask_SwayMon, 5, 0, 12, 4096, 4, ANIM_ATTACKER delay 15 createvisualtask AnimTask_AffectionHangedOn, 0x5 - jumpargeq 0x0, FRIENDSHIP_100_TO_149, General_AffectionHangedOn_3Hearts - jumpargeq 0x0, FRIENDSHIP_150_TO_199, General_AffectionHangedOn_4Hearts - jumpargeq 0x0, FRIENDSHIP_200_TO_254, General_AffectionHangedOn_5Hearts + jumpargeq 0x0, AFFECTION_THREE_HEARTS, General_AffectionHangedOn_3Hearts + jumpargeq 0x0, AFFECTION_FOUR_HEARTS, General_AffectionHangedOn_4Hearts + jumpargeq 0x0, AFFECTION_FIVE_HEARTS, General_AffectionHangedOn_5Hearts createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, -384, -31 General_AffectionHangedOn_5Hearts: createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, -128, -22 diff --git a/include/battle_util.h b/include/battle_util.h index 0c67352b11..3197778478 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -239,7 +239,7 @@ bool32 CanBeFrozen(u32 battler); bool32 CanGetFrostbite(u32 battler); bool32 CanBeConfused(u32 battler); bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag); -u32 GetBattlerFriendshipScore(u32 battler); +u32 GetBattlerAffectionHearts(u32 battler); u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc); bool32 IsMyceliumMightOnField(void); bool32 ChangeTypeBasedOnTerrain(u32 battler); diff --git a/include/config/battle.h b/include/config/battle.h index ba6dfd0b7a..d1ba9b969a 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -208,7 +208,7 @@ #define B_MULTI_BATTLE_WHITEOUT GEN_LATEST // In Gen4+, multi battles end when the Player and also their Partner don't have any more Pokémon to fight. #define B_EVOLUTION_AFTER_WHITEOUT GEN_LATEST // In Gen6+, Pokemon that qualify for evolution after battle will evolve even if the player loses. #define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper) -#define B_AFFECTION_MECHANICS FALSE // In Gen6+, there's a stat called affection that can trigger different effects in battle. From LGPE onwards, those effects use friendship instead. +#define B_AFFECTION_MECHANICS TRUE // In Gen6+, there's a stat called affection that can trigger different effects in battle. From LGPE onwards, those effects use friendship instead. #define B_TRAINER_CLASS_POKE_BALLS GEN_LATEST // In Gen7+, trainers will use certain types of Poké Balls depending on their trainer class. #define B_OBEDIENCE_MECHANICS GEN_LATEST // In PLA+ (here Gen8+), obedience restrictions also apply to non-outsider Pokémon, albeit based on their level met rather than actual level #define B_USE_FROSTBITE FALSE // In PLA, Frostbite replaces Freeze. Enabling this flag does the same here. Moves can still be cherry-picked to either Freeze or Frostbite. Freeze-Dry, Secret Power & Tri Attack depend on this config. diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index f5b7c96201..e10085b8ba 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -191,6 +191,14 @@ #define FRIENDSHIP_200_TO_254 5 #define FRIENDSHIP_MAX 6 +// Constants for GetBattlerAffectionHearts (based on friendship value) +#define AFFECTION_NO_HEARTS 0 // 0-79 friendship +#define AFFECTION_ONE_HEART 1 // 80-129 friendship +#define AFFECTION_TWO_HEARTS 2 // 130-179 friendship +#define AFFECTION_THREE_HEARTS 3 // 180-219 friendship +#define AFFECTION_FOUR_HEARTS 4 // 220-254 friendship +#define AFFECTION_FIVE_HEARTS 5 // Max friendship + // Friendship value that the majority of species use. #if P_UPDATED_FRIENDSHIP >= GEN_8 #define STANDARD_FRIENDSHIP 50 diff --git a/include/pokemon.h b/include/pokemon.h index 22c32971b2..30abf8a037 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -627,6 +627,7 @@ bool32 SpeciesHasGenderDifferences(u16 species); bool32 TryFormChange(u32 monId, u32 side, u16 method); void TryToSetBattleFormChangeMoves(struct Pokemon *mon, u16 method); u32 GetMonFriendshipScore(struct Pokemon *pokemon); +u32 GetMonAffectionHearts(struct Pokemon *pokemon); void UpdateMonPersonality(struct BoxPokemon *boxMon, u32 personality); u8 CalculatePartyCount(struct Pokemon *party); u16 SanitizeSpeciesId(u16 species); diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 0c99d2a434..99f58d6888 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -8630,7 +8630,7 @@ void AnimTask_TerrainPulse(u8 taskId) void AnimTask_AffectionHangedOn(u8 taskId) { - gBattleAnimArgs[0] = GetBattlerFriendshipScore(gBattleAnimTarget); + gBattleAnimArgs[0] = GetBattlerAffectionHearts(gBattleAnimTarget); DestroyAnimVisualTask(taskId); } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d5bdbaedae..c69e7ab161 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1725,9 +1725,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (gFieldStatuses & STATUS_FIELD_GRAVITY) calc = (calc * 5) / 3; // 1.66 Gravity acc boost - // With high affection/friendship there's a chance to evade a move by substracting 10% of its accuracy. - // I can't find exact information about that chance, so I'm just gonna write it as a 20% chance for now. - if (B_AFFECTION_MECHANICS == TRUE && GetBattlerFriendshipScore(battlerDef) >= FRIENDSHIP_150_TO_199 && (Random() % 100) <= 20) + if (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(battlerDef) == AFFECTION_FIVE_HEARTS) calc = (calc * 90) / 100; return calc; @@ -1907,7 +1905,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec + (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[battlerAtk].species == SPECIES_CHANSEY) + 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk) - + 2 * (B_AFFECTION_MECHANICS == TRUE && GetBattlerFriendshipScore(battlerAtk) >= FRIENDSHIP_200_TO_254) + + 2 * (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(battlerAtk) == AFFECTION_FIVE_HEARTS) + (abilityAtk == ABILITY_SUPER_LUCK) + gBattleStruct->bonusCritStages[gBattlerAttacker]; @@ -1994,7 +1992,7 @@ static void Cmd_adjustdamage(void) u8 holdEffect, param; u32 moveType; - u32 friendshipScore = GetBattlerFriendshipScore(gBattlerTarget); + u32 affectionScore = GetBattlerAffectionHearts(gBattlerTarget); u32 rand = Random() % 100; GET_MOVE_TYPE(gCurrentMove, moveType); @@ -2026,12 +2024,11 @@ static void Cmd_adjustdamage(void) RecordItemEffectBattle(gBattlerTarget, holdEffect); gSpecialStatuses[gBattlerTarget].focusSashed = TRUE; } - else if (B_AFFECTION_MECHANICS == TRUE && GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER && friendshipScore >= FRIENDSHIP_100_TO_149) + else if (B_AFFECTION_MECHANICS == TRUE && GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER && affectionScore >= AFFECTION_THREE_HEARTS) { - if ((friendshipScore == FRIENDSHIP_MAX && rand < 25) - || (friendshipScore == FRIENDSHIP_200_TO_254 && rand < 20) - || (friendshipScore == FRIENDSHIP_150_TO_199 && rand < 15) - || (friendshipScore == FRIENDSHIP_100_TO_149 && rand < 10)) + if ((affectionScore == AFFECTION_FIVE_HEARTS && rand < 20) + || (affectionScore == AFFECTION_FOUR_HEARTS && rand < 15) + || (affectionScore == AFFECTION_THREE_HEARTS && rand < 10)) gSpecialStatuses[gBattlerTarget].affectionEndured = TRUE; } @@ -15847,7 +15844,7 @@ void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBat *expAmount = (*expAmount * 150) / 100; if (B_UNEVOLVED_EXP_MULTIPLIER >= GEN_6 && IsMonPastEvolutionLevel(&gPlayerParty[expGetterMonId])) *expAmount = (*expAmount * 4915) / 4096; - if (B_AFFECTION_MECHANICS == TRUE && GetBattlerFriendshipScore(expGetterMonId) >= FRIENDSHIP_50_TO_99) + if (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(expGetterMonId) >= AFFECTION_FOUR_HEARTS) *expAmount = (*expAmount * 4915) / 4096; if (CheckBagHasItem(ITEM_EXP_CHARM, 1)) //is also for other exp boosting Powers if/when implemented *expAmount = (*expAmount * 150) / 100; diff --git a/src/battle_util.c b/src/battle_util.c index 2be621be55..ab61e63abb 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1862,23 +1862,23 @@ u8 GetImprisonedMovesCount(u32 battler, u16 move) return imprisonedMoves; } -u32 GetBattlerFriendshipScore(u32 battler) +u32 GetBattlerAffectionHearts(u32 battler) { u8 side = GetBattlerSide(battler); struct Pokemon *party = GetSideParty(side); u16 species = GetMonData(&party[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES); if (side != B_SIDE_PLAYER) - return FRIENDSHIP_NONE; + return AFFECTION_NO_HEARTS; else if (gSpeciesInfo[species].flags & SPECIES_FLAG_MEGA_EVOLUTION || (gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_SECRET_BASE))) - return FRIENDSHIP_NONE; + return AFFECTION_NO_HEARTS; - return GetMonFriendshipScore(&party[gBattlerPartyIndexes[battler]]); + return GetMonAffectionHearts(&party[gBattlerPartyIndexes[battler]]); } static void TryToRevertMimicry(void) @@ -2421,7 +2421,7 @@ u8 DoFieldEndTurnEffects(void) { if (B_AFFECTION_MECHANICS == TRUE && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER - && GetBattlerFriendshipScore(gBattlerAttacker) >= FRIENDSHIP_150_TO_199 + && GetBattlerAffectionHearts(gBattlerAttacker) >= AFFECTION_FOUR_HEARTS && (Random() % 100 < 20)) { gBattleCommunication[MULTISTRING_CHOOSER] = 1; diff --git a/src/pokemon.c b/src/pokemon.c index c9b4ef8190..3a48d1d38f 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -9289,6 +9289,24 @@ u32 GetMonFriendshipScore(struct Pokemon *pokemon) return FRIENDSHIP_NONE; } +u32 GetMonAffectionHearts(struct Pokemon *pokemon) +{ + u32 friendship = GetMonData(pokemon, MON_DATA_FRIENDSHIP, NULL); + + if (friendship == MAX_FRIENDSHIP) + return AFFECTION_FIVE_HEARTS; + if (friendship >= 220) + return AFFECTION_FOUR_HEARTS; + if (friendship >= 180) + return AFFECTION_THREE_HEARTS; + if (friendship >= 130) + return AFFECTION_TWO_HEARTS; + if (friendship >= 80) + return AFFECTION_ONE_HEART; + + return AFFECTION_NO_HEARTS; +} + void UpdateMonPersonality(struct BoxPokemon *boxMon, u32 personality) { struct PokemonSubstruct0 *old0, *new0;