mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-27 04:04:17 +01:00
Implemented affection-now-friendship mechanics
This commit is contained in:
parent
15fe85902f
commit
aa5c6a3f01
@ -831,6 +831,7 @@ 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_AffectionHangedOn @ B_ANIM_AFFECTION_HANGED_ON
|
||||
|
||||
.align 2
|
||||
gBattleAnims_Special::
|
||||
@ -24774,6 +24775,17 @@ PrimalReversionParticles:
|
||||
delay 3
|
||||
return
|
||||
|
||||
General_AffectionHangedOn:: @ Shameless copy of General_HangedOn
|
||||
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 0, 2, 7, 0, 9, RGB_RED
|
||||
playsewithpan SE_M_DRAGON_RAGE, SOUND_PAN_ATTACKER
|
||||
createvisualtask AnimTask_SlideMonForFocusBand, 5, 30, 128, 0, 1, 2, 0, 1
|
||||
waitforvisualfinish
|
||||
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 0, 2, 4, 9, 0, RGB_RED
|
||||
waitforvisualfinish
|
||||
delay 6
|
||||
createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 0, 0, 0, 15
|
||||
end
|
||||
|
||||
SnatchMoveTrySwapFromSubstitute:
|
||||
createvisualtask AnimTask_IsAttackerBehindSubstitute, 2
|
||||
jumprettrue SnatchMoveSwapSubstituteForMon
|
||||
|
@ -412,6 +412,61 @@ gBattleScriptsForMoveEffects::
|
||||
.4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE
|
||||
.4byte BattleScript_EffectSteelBeam @ EFFECT_STEEL_BEAM
|
||||
|
||||
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, BattleScript_AffectionBasedStatusHeal_Poison
|
||||
jumpifstatus BS_ATTACKER, STATUS1_TOXIC_POISON, BattleScript_AffectionBasedStatusHeal_Poison
|
||||
jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_AffectionBasedStatusHeal_Sleep
|
||||
jumpifstatus BS_ATTACKER, STATUS1_PARALYSIS, BattleScript_AffectionBasedStatusHeal_Paralysis
|
||||
jumpifstatus BS_ATTACKER, STATUS1_BURN, BattleScript_AffectionBasedStatusHeal_Burn
|
||||
jumpifstatus BS_ATTACKER, STATUS1_FREEZE, BattleScript_AffectionBasedStatusHeal_Freeze
|
||||
end2
|
||||
BattleScript_AffectionBasedStatusHeal_Poison:
|
||||
printstring STRINGID_ATTACKEREXPELLEDTHEPOISON
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
clearstatus BS_ATTACKER
|
||||
waitstate
|
||||
updatestatusicon BS_ATTACKER
|
||||
waitstate
|
||||
end2
|
||||
BattleScript_AffectionBasedStatusHeal_Sleep:
|
||||
printstring STRINGID_ATTACKERSHOOKITSELFAWAKE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
clearstatus BS_ATTACKER
|
||||
waitstate
|
||||
updatestatusicon BS_ATTACKER
|
||||
waitstate
|
||||
end2
|
||||
BattleScript_AffectionBasedStatusHeal_Paralysis:
|
||||
printstring STRINGID_ATTACKERBROKETHROUGHPARALYSIS
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
clearstatus BS_ATTACKER
|
||||
waitstate
|
||||
updatestatusicon BS_ATTACKER
|
||||
waitstate
|
||||
end2
|
||||
BattleScript_AffectionBasedStatusHeal_Burn:
|
||||
printstring STRINGID_ATTACKERHEALEDITSBURN
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
clearstatus BS_ATTACKER
|
||||
waitstate
|
||||
updatestatusicon BS_ATTACKER
|
||||
waitstate
|
||||
end2
|
||||
BattleScript_AffectionBasedStatusHeal_Freeze:
|
||||
printstring STRINGID_ATTACKERMELTEDTHEICE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
clearstatus BS_ATTACKER
|
||||
waitstate
|
||||
updatestatusicon BS_ATTACKER
|
||||
waitstate
|
||||
end2
|
||||
|
||||
BattleScript_EffectSteelBeam::
|
||||
attackcanceler
|
||||
attackstring
|
||||
|
@ -184,6 +184,7 @@ struct SpecialStatus
|
||||
u8 physicalBattlerId;
|
||||
u8 specialBattlerId;
|
||||
u8 changedStatsBattlerId; // Battler that was responsible for the latest stat change. Can be self.
|
||||
bool8 affectionEndured:1;
|
||||
};
|
||||
|
||||
struct SideTimer
|
||||
|
@ -420,5 +420,7 @@ 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[];
|
||||
|
||||
#endif // GUARD_BATTLE_SCRIPTS_H
|
||||
|
@ -189,5 +189,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
|
||||
|
@ -258,6 +258,7 @@
|
||||
#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_FOE_ENDURED_AFFECTION (1 << 9)
|
||||
|
||||
// Battle Weather flags
|
||||
#define B_WEATHER_RAIN_TEMPORARY (1 << 0)
|
||||
|
@ -534,6 +534,7 @@
|
||||
#define B_ANIM_AQUA_RING_HEAL 32
|
||||
#define B_ANIM_BEAK_BLAST_SETUP 33
|
||||
#define B_ANIM_SHELL_TRAP_SETUP 34
|
||||
#define B_ANIM_AFFECTION_HANGED_ON 35
|
||||
|
||||
// special animations table (gBattleAnims_Special)
|
||||
#define B_ANIM_LVL_UP 0
|
||||
|
@ -254,6 +254,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.
|
||||
|
@ -613,8 +613,14 @@
|
||||
#define STRINGID_METEORBEAMCHARGING 611
|
||||
#define STRINGID_HEATUPBEAK 612
|
||||
#define STRINGID_COURTCHANGE 613
|
||||
#define STRINGID_ATTACKEREXPELLEDTHEPOISON 614
|
||||
#define STRINGID_ATTACKERSHOOKITSELFAWAKE 615
|
||||
#define STRINGID_ATTACKERBROKETHROUGHPARALYSIS 616
|
||||
#define STRINGID_ATTACKERHEALEDITSBURN 617
|
||||
#define STRINGID_ATTACKERMELTEDTHEICE 618
|
||||
#define STRINGID_TARGETTOUGHEDITOUT 619
|
||||
|
||||
#define BATTLESTRINGS_COUNT 614
|
||||
#define BATTLESTRINGS_COUNT 620
|
||||
|
||||
// This is the string id that gBattleStringsTable starts with.
|
||||
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
|
||||
|
@ -738,9 +738,21 @@ 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_COURTCHANGE - BATTLESTRINGS_TABLE_START] = sText_CourtChange,
|
||||
[STRINGID_HEATUPBEAK - BATTLESTRINGS_TABLE_START] = sText_HeatingUpBeak,
|
||||
[STRINGID_METEORBEAMCHARGING - BATTLESTRINGS_TABLE_START] = sText_MeteorBeamCharging,
|
||||
|
@ -1719,6 +1719,13 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
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]]) >= 4 && (Random() % 100) <= 20)
|
||||
calc = (calc * 90) / 100;
|
||||
#endif
|
||||
|
||||
return calc;
|
||||
}
|
||||
|
||||
@ -1885,7 +1892,10 @@ 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)
|
||||
+ (abilityAtk == ABILITY_SUPER_LUCK);
|
||||
+ (abilityAtk == ABILITY_SUPER_LUCK)
|
||||
#if B_AFFECTION_MECHANICS == TRUE
|
||||
*= 2 (GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]) >= 5);
|
||||
#endif
|
||||
|
||||
if (critChance >= ARRAY_COUNT(sCriticalHitChance))
|
||||
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
|
||||
@ -1983,12 +1993,27 @@ static void Cmd_adjustdamage(void)
|
||||
RecordAbilityBattle(gBattlerTarget, ABILITY_STURDY);
|
||||
gSpecialStatuses[gBattlerTarget].sturdied = TRUE;
|
||||
}
|
||||
#if B_AFFECTION_MECHANICS == TRUE
|
||||
else if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER && GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]) >= 3)
|
||||
{
|
||||
if ((GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]) == 6 && (Random() % 100) < 25)
|
||||
|| (GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]) == 5 && (Random() % 100) < 20)
|
||||
|| (GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]) == 4 && (Random() % 100) < 15)
|
||||
|| (GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]]) == 3 && (Random() % 100) < 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].sturdied
|
||||
&& !gSpecialStatuses[gBattlerTarget].affectionEndured)
|
||||
#else
|
||||
&& !gSpecialStatuses[gBattlerTarget].sturdied)
|
||||
#endif
|
||||
goto END;
|
||||
|
||||
// Handle reducing the dmg to 1 hp.
|
||||
@ -2008,6 +2033,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++;
|
||||
@ -2463,6 +2494,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;
|
||||
@ -4008,6 +4049,10 @@ static void Cmd_getexp(void)
|
||||
gBattleMoveDamage = value + 1;
|
||||
}
|
||||
#endif
|
||||
#if B_AFFECTION_MECHANICS == TRUE
|
||||
if (GetMonFriendshipScore(&gPlayerParty[gBattleStruct->expGetterMonId]) >= 2)
|
||||
gBattleMoveDamage = (gBattleMoveDamage * 120) / 100;
|
||||
#endif
|
||||
|
||||
if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId]))
|
||||
{
|
||||
@ -10932,6 +10977,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;
|
||||
|
@ -2077,6 +2077,24 @@ void TryToRevertMimicry(void)
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetMonFriendshipScore(struct Pokemon *pokemon) // Based on GetLeadMonFriendshipScore
|
||||
{
|
||||
if (GetMonData(pokemon, MON_DATA_FRIENDSHIP) == 255)
|
||||
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;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
ENDTURN_ORDER,
|
||||
@ -2105,6 +2123,9 @@ enum
|
||||
ENDTURN_ION_DELUGE,
|
||||
ENDTURN_FAIRY_LOCK,
|
||||
ENDTURN_RETALIATE,
|
||||
#if B_AFFECTION_MECHANICS == TRUE
|
||||
ENDTURN_STATUS_HEAL,
|
||||
#endif
|
||||
ENDTURN_FIELD_COUNT,
|
||||
};
|
||||
|
||||
@ -2552,6 +2573,22 @@ u8 DoFieldEndTurnEffects(void)
|
||||
gSideTimers[B_SIDE_OPPONENT].retaliateTimer--;
|
||||
gBattleStruct->turnCountersTracker++;
|
||||
break;
|
||||
#if B_AFFECTION_MECHANICS == TRUE
|
||||
case ENDTURN_STATUS_HEAL:
|
||||
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++)
|
||||
{
|
||||
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER
|
||||
&& GetMonFriendshipScore(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]) >= 4
|
||||
&& (Random() % 100 < 20))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
||||
BattleScriptExecute(BattleScript_AffectionBasedStatusHeal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gBattleStruct->turnCountersTracker++;
|
||||
break;
|
||||
#endif
|
||||
case ENDTURN_FIELD_COUNT:
|
||||
effect++;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user