diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index dcafffe50c..a7e3f34612 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -868,7 +868,8 @@ gBattleAnims_General:: .4byte General_AquaRingHeal @ B_ANIM_AQUA_RING_HEAL .4byte General_BeakBlastSetUp @ B_ANIM_BEAK_BLAST_SETUP .4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP - .4byte General_ZMoveActivate @ B_ANIM_ZMOVE_ACTIVATE + .4byte General_ZMoveActivate @ B_ANIM_ZMOVE_ACTIVATE + .4byte General_AffectionHangedOn @ B_ANIM_AFFECTION_HANGED_ON .align 2 gBattleAnims_Special:: @@ -24884,6 +24885,27 @@ PrimalReversionParticles: delay 3 return +General_AffectionHangedOn:: + loadspritegfx ANIM_TAG_RED_HEART + loopsewithpan SE_M_CHARM, SOUND_PAN_ATTACKER, 12, 3 + createvisualtask AnimTask_SwayMon, 5, 0, 12, 4096, 4, ANIM_ATTACKER + delay 15 + launchtask AnimTask_AffectionHangedOn 0x5 0x0 + 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 + createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, -384, -31 +General_AffectionHangedOn_5Hearts: + createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, -128, -22 +General_AffectionHangedOn_4Hearts: + createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, 416, -38 +General_AffectionHangedOn_3Hearts: + createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, 160, -32 + createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, -256, -40 + createsprite gRedHeartBurstSpriteTemplate, ANIM_ATTACKER, 3, 128, -16 + waitforvisualfinish + end + SnatchMoveTrySwapFromSubstitute: createvisualtask AnimTask_IsAttackerBehindSubstitute, 2 jumprettrue SnatchMoveSwapSubstituteForMon diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d3ff57492e..9ecc3b179f 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -415,6 +415,41 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectExtremeEvoboost @ EFFECT_EXTREME_EVOBOOST .4byte BattleScript_EffectTerrainHit @ EFFECT_DAMAGE_SET_TERRAIN +BattleScript_AffectionBasedEndurance:: + playanimation BS_TARGET, B_ANIM_AFFECTION_HANGED_ON + printstring STRINGID_TARGETTOUGHEDITOUT + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_AffectionBasedStatusHeal:: + jumpifstatus BS_ATTACKER, STATUS1_POISON | STATUS1_TOXIC_POISON, BattleScript_AffectionBasedStatus_HealPoisonString + jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_AffectionBasedStatus_HealSleepString + jumpifstatus BS_ATTACKER, STATUS1_PARALYSIS, BattleScript_AffectionBasedStatus_HealParalysisString + jumpifstatus BS_ATTACKER, STATUS1_BURN, BattleScript_AffectionBasedStatus_HealBurnString + jumpifstatus BS_ATTACKER, STATUS1_FREEZE, BattleScript_AffectionBasedStatus_HealFreezeString + end2 +BattleScript_AffectionBasedStatus_HealPoisonString: + printstring STRINGID_ATTACKEREXPELLEDTHEPOISON + goto BattleScript_AffectionBasedStatusHeal_Continue +BattleScript_AffectionBasedStatus_HealSleepString: + printstring STRINGID_ATTACKERSHOOKITSELFAWAKE + goto BattleScript_AffectionBasedStatusHeal_Continue +BattleScript_AffectionBasedStatus_HealParalysisString: + printstring STRINGID_ATTACKERBROKETHROUGHPARALYSIS + goto BattleScript_AffectionBasedStatusHeal_Continue +BattleScript_AffectionBasedStatus_HealBurnString: + printstring STRINGID_ATTACKERHEALEDITSBURN + goto BattleScript_AffectionBasedStatusHeal_Continue +BattleScript_AffectionBasedStatus_HealFreezeString: + printstring STRINGID_ATTACKERMELTEDTHEICE +BattleScript_AffectionBasedStatusHeal_Continue: + waitmessage B_WAIT_TIME_LONG + clearstatus BS_ATTACKER + waitstate + updatestatusicon BS_ATTACKER + waitstate + end2 + BattleScript_EffectSteelBeam:: attackcanceler attackstring diff --git a/include/battle.h b/include/battle.h index 931b13b2f4..36ffdb6da0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -178,6 +178,7 @@ struct SpecialStatus u8 dancerOriginalTarget:3; u8 announceNeutralizingGas:1; // See Cmd_switchineffects u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS + u8 affectionEndured:1; s32 dmg; s32 physicalDmg; s32 specialDmg; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 19380932dd..7e2e9a01e6 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -426,6 +426,8 @@ extern const u8 BattleScript_MagicianActivates[]; extern const u8 BattleScript_BeakBlastSetUp[]; extern const u8 BattleScript_BeakBlastBurn[]; extern const u8 BattleScript_DefDownSpeedUp[]; +extern const u8 BattleScript_AffectionBasedStatusHeal[]; +extern const u8 BattleScript_AffectionBasedEndurance[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/battle_util.h b/include/battle_util.h index d26aa24775..5dbefd7e7e 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -201,5 +201,6 @@ bool32 CanBeParalyzed(u8 battlerId); bool32 CanBeFrozen(u8 battlerId); bool32 CanBeConfused(u8 battlerId); bool32 IsBattlerTerrainAffected(u8 battlerId, u32 terrainFlag); +u32 GetMonFriendshipScore(struct Pokemon *pokemon); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/constants/battle.h b/include/constants/battle.h index a4fdc4798f..5cffb74ab3 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -250,16 +250,17 @@ #define STATUS_FIELD_TERRAIN_ANY (STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN) // Flags describing move's result -#define MOVE_RESULT_MISSED (1 << 0) -#define MOVE_RESULT_SUPER_EFFECTIVE (1 << 1) -#define MOVE_RESULT_NOT_VERY_EFFECTIVE (1 << 2) -#define MOVE_RESULT_DOESNT_AFFECT_FOE (1 << 3) -#define MOVE_RESULT_ONE_HIT_KO (1 << 4) -#define MOVE_RESULT_FAILED (1 << 5) -#define MOVE_RESULT_FOE_ENDURED (1 << 6) -#define MOVE_RESULT_FOE_HUNG_ON (1 << 7) -#define MOVE_RESULT_STURDIED (1 << 8) -#define MOVE_RESULT_NO_EFFECT (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED) +#define MOVE_RESULT_MISSED (1 << 0) +#define MOVE_RESULT_SUPER_EFFECTIVE (1 << 1) +#define MOVE_RESULT_NOT_VERY_EFFECTIVE (1 << 2) +#define MOVE_RESULT_DOESNT_AFFECT_FOE (1 << 3) +#define MOVE_RESULT_ONE_HIT_KO (1 << 4) +#define MOVE_RESULT_FAILED (1 << 5) +#define MOVE_RESULT_FOE_ENDURED (1 << 6) +#define MOVE_RESULT_FOE_HUNG_ON (1 << 7) +#define MOVE_RESULT_STURDIED (1 << 8) +#define MOVE_RESULT_FOE_ENDURED_AFFECTION (1 << 9) +#define MOVE_RESULT_NO_EFFECT (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED) // Battle Weather flags #define B_WEATHER_RAIN_TEMPORARY (1 << 0) diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index d15b6876e3..28bcb283d4 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -536,6 +536,7 @@ #define B_ANIM_BEAK_BLAST_SETUP 33 #define B_ANIM_SHELL_TRAP_SETUP 34 #define B_ANIM_ZMOVE_ACTIVATE 35 // Using Z Moves +#define B_ANIM_AFFECTION_HANGED_ON 36 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index fce87bd43d..89134daf91 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -175,6 +175,7 @@ #define B_MULTI_BATTLE_WHITEOUT GEN_8 // 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_6 // 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. // Animation Settings #define B_NEW_SWORD_PARTICLE FALSE // If set to TRUE, it updates Swords Dance's particle. diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 39092410a1..4ef2a3a82d 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -624,8 +624,14 @@ #define STRINGID_ZMOVESTATUP 622 #define STRINGID_ZMOVEHPTRAP 623 #define STRINGID_TERRAINREMOVED 624 +#define STRINGID_ATTACKEREXPELLEDTHEPOISON 625 +#define STRINGID_ATTACKERSHOOKITSELFAWAKE 626 +#define STRINGID_ATTACKERBROKETHROUGHPARALYSIS 627 +#define STRINGID_ATTACKERHEALEDITSBURN 628 +#define STRINGID_ATTACKERMELTEDTHEICE 629 +#define STRINGID_TARGETTOUGHEDITOUT 630 -#define BATTLESTRINGS_COUNT 625 +#define BATTLESTRINGS_COUNT 631 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 14a037f9f3..98075a9425 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -182,6 +182,15 @@ #define FRIENDSHIP_EVENT_FAINT_FIELD_PSN 7 #define FRIENDSHIP_EVENT_FAINT_LARGE 8 // If opponent was >= 30 levels higher. See AdjustFriendshipOnBattleFaint +// Constants for GetLeadMonFriendshipScore +#define FRIENDSHIP_NONE 0 +#define FRIENDSHIP_1_TO_49 1 +#define FRIENDSHIP_50_TO_99 2 +#define FRIENDSHIP_100_TO_149 3 +#define FRIENDSHIP_150_TO_199 4 +#define FRIENDSHIP_200_TO_254 5 +#define FRIENDSHIP_MAX 6 + #define MAX_FRIENDSHIP 255 #define MAX_SHEEN 255 #define MAX_CONDITION 255 diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index b8304f124f..35c1244670 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -18,6 +18,7 @@ #include "constants/moves.h" #include "constants/hold_effects.h" #include "constants/items.h" +#include "constants/pokemon.h" // function declarations static void SpriteCB_SpriteToCentreOfSide(struct Sprite *sprite); @@ -7892,3 +7893,12 @@ void AnimTask_TerrainPulse(u8 taskId) } DestroyAnimVisualTask(taskId); } + +void AnimTask_AffectionHangedOn(u8 taskId) +{ + int side = GetBattlerSide(gBattleAnimTarget); + struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; + + gBattleAnimArgs[0] = GetMonFriendshipScore(&party[gBattlerPartyIndexes[gBattleAnimTarget]]); + DestroyAnimVisualTask(taskId); +} diff --git a/src/battle_message.c b/src/battle_message.c index 688a48f256..3c67675888 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -753,10 +753,22 @@ static const u8 sText_TargetTooHeavy[] = _("But the target\nwas too heavy!"); static const u8 sText_MeteorBeamCharging[] = _("{B_ATK_NAME_WITH_PREFIX} is overflowing\nwith space energy!"); static const u8 sText_HeatingUpBeak[] = _("{B_ATK_NAME_WITH_PREFIX} started\nheating up its beak!"); static const u8 sText_CourtChange[] = _("{B_ATK_NAME_WITH_PREFIX} swapped the battle\neffects affecting each side!"); +static const u8 sText_AttackerExpelledThePoison[] = _("{B_ATK_NAME_WITH_PREFIX} managed to\nexpel the poison!"); +static const u8 sText_AttackerShookItselfAwake[] = _("{B_ATK_NAME_WITH_PREFIX} shook itself awake!"); +static const u8 sText_AttackerBrokeThroughParalysis[] = _("{B_ATK_NAME_WITH_PREFIX} gathered all its energy\nto overcome its paralysis!"); +static const u8 sText_AttackerHealedItsBurn[] = _("{B_ATK_NAME_WITH_PREFIX} healed its burn with\nits sheer determination!"); +static const u8 sText_AttackerMeltedTheIce[] = _("{B_ATK_NAME_WITH_PREFIX} melted the ice with\nits fiery determination!"); +static const u8 sText_TargetToughedItOut[] = _("{B_DEF_NAME_WITH_PREFIX} toughed it out\nto show you its best side!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_TARGETTOUGHEDITOUT - BATTLESTRINGS_TABLE_START] = sText_TargetToughedItOut, + [STRINGID_ATTACKERMELTEDTHEICE - BATTLESTRINGS_TABLE_START] = sText_AttackerMeltedTheIce, + [STRINGID_ATTACKERHEALEDITSBURN - BATTLESTRINGS_TABLE_START] = sText_AttackerHealedItsBurn, + [STRINGID_ATTACKERBROKETHROUGHPARALYSIS - BATTLESTRINGS_TABLE_START] = sText_AttackerBrokeThroughParalysis, + [STRINGID_ATTACKERSHOOKITSELFAWAKE - BATTLESTRINGS_TABLE_START] = sText_AttackerShookItselfAwake, + [STRINGID_ATTACKEREXPELLEDTHEPOISON - BATTLESTRINGS_TABLE_START] = sText_AttackerExpelledThePoison, [STRINGID_ZPOWERSURROUNDS - BATTLESTRINGS_TABLE_START] = sText_ZPowerSurrounds, [STRINGID_ZMOVEUNLEASHED - BATTLESTRINGS_TABLE_START] = sText_ZPowerUnleashed, [STRINGID_ZMOVERESETSSTATS - BATTLESTRINGS_TABLE_START] = sText_ZMoveResetsStats, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index cdf0e30ea7..a5a822546c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -59,6 +59,7 @@ #include "constants/songs.h" #include "constants/trainers.h" #include "battle_util.h" +#include "constants/pokemon.h" extern struct Evolution gEvolutionTable[][EVOS_PER_MON]; @@ -1730,6 +1731,13 @@ 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 +#if B_AFFECTION_MECHANICS == TRUE + // 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 (GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[battlerDef]]) >= FRIENDSHIP_150_TO_199 && (Random() % 100) <= 20) + calc = (calc * 90) / 100; +#endif + return calc; } @@ -1898,6 +1906,9 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi + (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) + 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk) + #if B_AFFECTION_MECHANICS == TRUE + + 2 * (GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]) >= FRIENDSHIP_200_TO_254) + #endif + (abilityAtk == ABILITY_SUPER_LUCK); if (critChance >= ARRAY_COUNT(sCriticalHitChance)) @@ -1966,6 +1977,8 @@ static void Cmd_adjustdamage(void) { u8 holdEffect, param; u32 moveType; + u32 friendshipScore = GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]); + u32 rand = Random() % 100; GET_MOVE_TYPE(gCurrentMove, moveType); @@ -1981,7 +1994,7 @@ static void Cmd_adjustdamage(void) gPotentialItemEffectBattler = gBattlerTarget; - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < param) + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && rand < param) { RecordItemEffectBattle(gBattlerTarget, holdEffect); gSpecialStatuses[gBattlerTarget].focusBanded = TRUE; @@ -1998,11 +2011,24 @@ static void Cmd_adjustdamage(void) RecordItemEffectBattle(gBattlerTarget, holdEffect); gSpecialStatuses[gBattlerTarget].focusSashed = TRUE; } +#if B_AFFECTION_MECHANICS == TRUE + else if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER && friendshipScore >= FRIENDSHIP_100_TO_149) + { + 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)) + gSpecialStatuses[gBattlerTarget].affectionEndured = TRUE; + } +#endif if (gBattleMoves[gCurrentMove].effect != EFFECT_FALSE_SWIPE && !gProtectStructs[gBattlerTarget].endured && !gSpecialStatuses[gBattlerTarget].focusBanded && !gSpecialStatuses[gBattlerTarget].focusSashed +#if B_AFFECTION_MECHANICS == TRUE + && !gSpecialStatuses[gBattlerTarget].affectionEndured +#endif && !gSpecialStatuses[gBattlerTarget].sturdied) goto END; @@ -2023,6 +2049,12 @@ static void Cmd_adjustdamage(void) gMoveResultFlags |= MOVE_RESULT_STURDIED; gLastUsedAbility = ABILITY_STURDY; } +#if B_AFFECTION_MECHANICS == TRUE + else if (gSpecialStatuses[gBattlerTarget].affectionEndured) + { + gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED_AFFECTION; + } +#endif END: gBattlescriptCurrInstr++; @@ -2478,6 +2510,16 @@ static void Cmd_resultmessage(void) { stringId = STRINGID_BUTITFAILED; } + #if B_AFFECTION_MECHANICS == TRUE + else if (gMoveResultFlags & MOVE_RESULT_FOE_ENDURED_AFFECTION) + { + gSpecialStatuses[gBattlerTarget].affectionEndured = FALSE; + gMoveResultFlags &= ~MOVE_RESULT_FOE_ENDURED_AFFECTION; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AffectionBasedEndurance; + return; + } + #endif else { gBattleCommunication[MSG_DISPLAY] = 0; @@ -4020,6 +4062,10 @@ static void Cmd_getexp(void) gBattleMoveDamage = value + 1; } #endif + #if B_AFFECTION_MECHANICS == TRUE + if (GetMonFriendshipScore(&gPlayerParty[gBattleStruct->expGetterMonId]) >= FRIENDSHIP_50_TO_99) + gBattleMoveDamage = (gBattleMoveDamage * 120) / 100; + #endif if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId])) { @@ -11009,6 +11055,13 @@ static void Cmd_tryKO(void) gMoveResultFlags |= MOVE_RESULT_FOE_HUNG_ON; gLastUsedItem = gBattleMons[gBattlerTarget].item; } + #if B_AFFECTION_MECHANICS == TRUE + else if (gSpecialStatuses[gBattlerTarget].affectionEndured) + { + gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - 1; + gMoveResultFlags |= MOVE_RESULT_FOE_ENDURED_AFFECTION; + } + #endif else { gBattleMoveDamage = gBattleMons[gBattlerTarget].hp; diff --git a/src/battle_util.c b/src/battle_util.c index 8656d0c33a..f38d80a69c 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -45,6 +45,7 @@ #include "constants/species.h" #include "constants/trainers.h" #include "constants/weather.h" +#include "constants/pokemon.h" extern struct Evolution gEvolutionTable[][EVOS_PER_MON]; @@ -2103,6 +2104,26 @@ void TryToRevertMimicry(void) } } +u32 GetMonFriendshipScore(struct Pokemon *pokemon) +{ + u32 friendshipScore = GetMonData(pokemon, MON_DATA_FRIENDSHIP); + + if (friendshipScore == MAX_FRIENDSHIP) + return FRIENDSHIP_MAX; + if (friendshipScore >= 200) + return FRIENDSHIP_200_TO_254; + if (friendshipScore >= 150) + return FRIENDSHIP_150_TO_199; + if (friendshipScore >= 100) + return FRIENDSHIP_100_TO_149; + if (friendshipScore >= 50) + return FRIENDSHIP_50_TO_99; + if (friendshipScore >= 1) + return FRIENDSHIP_1_TO_49; + + return FRIENDSHIP_NONE; +} + enum { ENDTURN_ORDER, @@ -2131,6 +2152,7 @@ enum ENDTURN_ION_DELUGE, ENDTURN_FAIRY_LOCK, ENDTURN_RETALIATE, + ENDTURN_STATUS_HEAL, ENDTURN_FIELD_COUNT, }; @@ -2578,6 +2600,22 @@ u8 DoFieldEndTurnEffects(void) gSideTimers[B_SIDE_OPPONENT].retaliateTimer--; gBattleStruct->turnCountersTracker++; break; + case ENDTURN_STATUS_HEAL: + for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++) + { + #if B_AFFECTION_MECHANICS == TRUE + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER + && GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]) >= FRIENDSHIP_150_TO_199 + && (Random() % 100 < 20)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + BattleScriptExecute(BattleScript_AffectionBasedStatusHeal); + break; + } + #endif + } + gBattleStruct->turnCountersTracker++; + break; case ENDTURN_FIELD_COUNT: effect++; break; diff --git a/src/field_specials.c b/src/field_specials.c index 7c226e7a39..7931a5029a 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -65,6 +65,7 @@ #include "constants/weather.h" #include "constants/metatile_labels.h" #include "palette.h" +#include "battle_util.h" EWRAM_DATA bool8 gBikeCyclingChallenge = FALSE; EWRAM_DATA u8 gBikeCollisions = 0; @@ -939,21 +940,7 @@ u16 GetWeekCount(void) u8 GetLeadMonFriendshipScore(void) { - struct Pokemon *pokemon = &gPlayerParty[GetLeadMonIndex()]; - if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) == MAX_FRIENDSHIP) - return 6; - if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) >= 200) - return 5; - if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) >= 150) - return 4; - if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) >= 100) - return 3; - if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) >= 50) - return 2; - if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) >= 1) - return 1; - - return 0; + return GetMonFriendshipScore(&gPlayerParty[GetLeadMonIndex()]); } static void CB2_FieldShowRegionMap(void)