mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-25 19:24:16 +01:00
Generation 6 Experience Share (#3276)
This commit is contained in:
parent
820113d883
commit
75d06bb599
@ -219,6 +219,7 @@ void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon);
|
||||
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon);
|
||||
void RecalcBattlerStats(u32 battler, struct Pokemon *mon);
|
||||
bool32 IsAlly(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 IsGen6ExpShareEnabled(void);
|
||||
|
||||
// Ability checks
|
||||
bool32 IsRolePlayBannedAbilityAtk(u16 ability);
|
||||
|
@ -16,6 +16,10 @@
|
||||
// TM config
|
||||
#define I_REUSABLE_TMS FALSE // In Gen5-8, TMs are reusable. Setting this to TRUE will make all vanilla TMs reusable, though they can also be cherry-picked by setting their importance to 1.
|
||||
|
||||
// Exp. Share config
|
||||
#define I_EXP_SHARE_FLAG 0 // If this flag is set, every Pokémon in the party will gain experience, regardless if they participated in the battle or not.
|
||||
#define I_EXP_SHARE_ITEM GEN_5 // In Gen6+, the Exp. Share was changed from a held item to a Key item that toggles the effect described above.
|
||||
|
||||
// Repel/Lure config
|
||||
// These two settings are both independent and complementary.
|
||||
#define VAR_LAST_REPEL_LURE_USED 0 // If this var has been assigned, last Repel/Lure used will be saved and the player will get prompted with the vanilla repel YES/NO option, unless I_REPEL_LURE_MENU is set to TRUE.
|
||||
|
@ -667,8 +667,9 @@
|
||||
#define STRINGID_PKMNITEMMELTED 665
|
||||
#define STRINGID_ULTRABURSTREACTING 666
|
||||
#define STRINGID_ULTRABURSTCOMPLETED 667
|
||||
#define STRINGID_TEAMGAINEDEXP 668
|
||||
|
||||
#define BATTLESTRINGS_COUNT 668
|
||||
#define BATTLESTRINGS_COUNT 669
|
||||
|
||||
// This is the string id that gBattleStringsTable starts with.
|
||||
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
|
||||
|
@ -139,6 +139,8 @@
|
||||
// It looks like file.c:line: size of array `id' is negative
|
||||
#define STATIC_ASSERT(expr, id) typedef char id[(expr) ? 1 : -1];
|
||||
|
||||
#define FEATURE_FLAG_ASSERT(flag, id) STATIC_ASSERT(flag > TEMP_FLAGS_END || flag == 0, id)
|
||||
|
||||
struct Coords8
|
||||
{
|
||||
s8 x;
|
||||
|
@ -30,6 +30,7 @@ void ItemUseOutOfBattle_FormChange(u8);
|
||||
void ItemUseOutOfBattle_FormChange_ConsumedOnUse(u8);
|
||||
void ItemUseOutOfBattle_Honey(u8);
|
||||
void ItemUseOutOfBattle_CannotUse(u8);
|
||||
void ItemUseOutOfBattle_ExpShare(u8);
|
||||
void ItemUseInBattle_BagMenu(u8 taskId);
|
||||
void ItemUseInBattle_PartyMenu(u8 taskId);
|
||||
void ItemUseInBattle_PartyMenuChooseMove(u8 taskId);
|
||||
|
@ -3034,4 +3034,8 @@ extern const u8 gText_BoxName[];
|
||||
extern const u8 gText_PkmnsNickname[];
|
||||
extern const u8 gText_TellHimTheWords[];
|
||||
|
||||
// Exp. Share
|
||||
extern const u8 gText_ExpShareOn[];
|
||||
extern const u8 gText_ExpShareOff[];
|
||||
|
||||
#endif // GUARD_STRINGS_H
|
||||
|
@ -803,7 +803,7 @@ static const u8 sText_MirrorHerbCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} us
|
||||
static const u8 sText_PkmnItemMelted[] = _("{B_ATK_NAME_WITH_PREFIX} corroded\n{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!");
|
||||
static const u8 sText_UltraBurstReacting[] = _("Bright light is about to\nburst out of {B_ATK_NAME_WITH_PREFIX}!");
|
||||
static const u8 sText_UltraBurstCompleted[] = _("{B_ATK_NAME_WITH_PREFIX} regained its\ntrue power through Ultra Burst!");
|
||||
|
||||
static const u8 sText_TeamGainedEXP[] = _("The rest of your team gained EXP.\nPoints thanks to the {B_LAST_ITEM}!\p");
|
||||
|
||||
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
||||
{
|
||||
@ -1462,6 +1462,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
||||
[STRINGID_PKMNFROSTBITEHEALEDBY - BATTLESTRINGS_TABLE_START] = sText_PkmnFrostbiteHealedBy,
|
||||
[STRINGID_ULTRABURSTREACTING - BATTLESTRINGS_TABLE_START] = sText_UltraBurstReacting,
|
||||
[STRINGID_ULTRABURSTCOMPLETED - BATTLESTRINGS_TABLE_START] = sText_UltraBurstCompleted,
|
||||
[STRINGID_TEAMGAINEDEXP - BATTLESTRINGS_TABLE_START] = sText_TeamGainedEXP,
|
||||
};
|
||||
|
||||
const u16 gTrainerUsedItemStringIds[] =
|
||||
|
@ -354,6 +354,7 @@ static void BestowItem(u32 battlerAtk, u32 battlerDef);
|
||||
static bool8 IsFinalStrikeEffect(u16 move);
|
||||
static void TryUpdateRoundTurnOrder(void);
|
||||
static bool32 ChangeOrderTargetAfterAttacker(void);
|
||||
void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler);
|
||||
|
||||
static void Cmd_attackcanceler(void);
|
||||
static void Cmd_accuracycheck(void);
|
||||
@ -4033,6 +4034,8 @@ static void Cmd_jumpbasedontype(void)
|
||||
}
|
||||
}
|
||||
|
||||
FEATURE_FLAG_ASSERT(I_EXP_SHARE_FLAG, YouNeedToSetTheExpShareFlagToAnUnusedFlag);
|
||||
|
||||
static void Cmd_getexp(void)
|
||||
{
|
||||
CMD_ARGS(u8 battler);
|
||||
@ -4088,7 +4091,7 @@ static void Cmd_getexp(void)
|
||||
else
|
||||
holdEffect = ItemId_GetHoldEffect(item);
|
||||
|
||||
if (holdEffect == HOLD_EFFECT_EXP_SHARE)
|
||||
if (holdEffect == HOLD_EFFECT_EXP_SHARE || IsGen6ExpShareEnabled())
|
||||
viaExpShare++;
|
||||
}
|
||||
#if (B_SCALED_EXP >= GEN_5) && (B_SCALED_EXP != GEN_6)
|
||||
@ -4137,7 +4140,8 @@ static void Cmd_getexp(void)
|
||||
else
|
||||
holdEffect = ItemId_GetHoldEffect(item);
|
||||
|
||||
if (holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1))
|
||||
if ((holdEffect != HOLD_EFFECT_EXP_SHARE && !(gBattleStruct->sentInPokes & 1) && !IsGen6ExpShareEnabled())
|
||||
|| GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG)
|
||||
{
|
||||
*(&gBattleStruct->sentInPokes) >>= 1;
|
||||
gBattleScripting.getexpState = 5;
|
||||
@ -4174,34 +4178,15 @@ static void Cmd_getexp(void)
|
||||
else
|
||||
gBattleMoveDamage = 0;
|
||||
|
||||
// only give exp share bonus in later gens if the mon wasn't sent out
|
||||
#if B_SPLIT_EXP < GEN_6
|
||||
if (holdEffect == HOLD_EFFECT_EXP_SHARE)
|
||||
if ((holdEffect == HOLD_EFFECT_EXP_SHARE || IsGen6ExpShareEnabled())
|
||||
#if B_SPLIT_EXP >= GEN_6
|
||||
// only give exp share bonus in later gens if the mon wasn't sent out
|
||||
&& gBattleMoveDamage == 0
|
||||
#endif
|
||||
)
|
||||
gBattleMoveDamage += gExpShareExp;
|
||||
#else
|
||||
if (holdEffect == HOLD_EFFECT_EXP_SHARE && gBattleMoveDamage == 0)
|
||||
gBattleMoveDamage += gExpShareExp;
|
||||
#endif
|
||||
if (holdEffect == HOLD_EFFECT_LUCKY_EGG)
|
||||
gBattleMoveDamage = (gBattleMoveDamage * 150) / 100;
|
||||
#if B_TRAINER_EXP_MULTIPLIER <= GEN_7
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
||||
gBattleMoveDamage = (gBattleMoveDamage * 150) / 100;
|
||||
#endif
|
||||
#if (B_SCALED_EXP >= GEN_5) && (B_SCALED_EXP != GEN_6)
|
||||
{
|
||||
// Note: There is an edge case where if a pokemon receives a large amount of exp, it wouldn't be properly calculated
|
||||
// because of multiplying by scaling factor(the value would simply be larger than an u32 can hold). Hence u64 is needed.
|
||||
u64 value = gBattleMoveDamage;
|
||||
value *= sExperienceScalingFactors[(gBattleMons[gBattlerFainted].level * 2) + 10];
|
||||
value /= sExperienceScalingFactors[gBattleMons[gBattlerFainted].level + GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) + 10];
|
||||
gBattleMoveDamage = value + 1;
|
||||
}
|
||||
#endif
|
||||
#if B_AFFECTION_MECHANICS == TRUE
|
||||
if (GetBattlerFriendshipScore(gBattleStruct->expGetterMonId) >= FRIENDSHIP_50_TO_99)
|
||||
gBattleMoveDamage = (gBattleMoveDamage * 120) / 100;
|
||||
#endif
|
||||
|
||||
ApplyExperienceMultipliers(&gBattleMoveDamage, gBattleStruct->expGetterMonId, gBattlerFainted);
|
||||
|
||||
if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId]))
|
||||
{
|
||||
@ -4244,7 +4229,16 @@ static void Cmd_getexp(void)
|
||||
PREPARE_STRING_BUFFER(gBattleTextBuff2, i);
|
||||
PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 6, gBattleMoveDamage);
|
||||
|
||||
PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBattlerId);
|
||||
if (gBattleStruct->sentInPokes & 1)
|
||||
{
|
||||
PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBattlerId);
|
||||
}
|
||||
else if (!IsValidForBattle(&gPlayerParty[gBattleStruct->expGetterMonId+1]))
|
||||
{
|
||||
gLastUsedItem = ITEM_EXP_SHARE;
|
||||
PrepareStringBattle(STRINGID_TEAMGAINEDEXP, 0);
|
||||
}
|
||||
|
||||
MonGainEVs(&gPlayerParty[gBattleStruct->expGetterMonId], gBattleMons[gBattlerFainted].species);
|
||||
}
|
||||
gBattleStruct->sentInPokes >>= 1;
|
||||
@ -16089,6 +16083,39 @@ u8 GetFirstFaintedPartyIndex(u8 battler)
|
||||
return PARTY_SIZE;
|
||||
}
|
||||
|
||||
void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler)
|
||||
{
|
||||
u16 item = GetMonData(&gPlayerParty[expGetterMonId], MON_DATA_HELD_ITEM);
|
||||
u8 holdEffect;
|
||||
|
||||
if (item == ITEM_ENIGMA_BERRY_E_READER)
|
||||
holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
|
||||
else
|
||||
holdEffect = ItemId_GetHoldEffect(item);
|
||||
|
||||
if (holdEffect == HOLD_EFFECT_LUCKY_EGG)
|
||||
*expAmount = (*expAmount * 150) / 100;
|
||||
if (B_TRAINER_EXP_MULTIPLIER <= GEN_7 && gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
||||
*expAmount = (*expAmount * 150) / 100;
|
||||
if (B_AFFECTION_MECHANICS == TRUE && GetBattlerFriendshipScore(expGetterMonId) >= FRIENDSHIP_50_TO_99)
|
||||
*expAmount = (*expAmount * 120) / 100;
|
||||
if (IsTradedMon(&gPlayerParty[expGetterMonId]))
|
||||
*expAmount = (*expAmount * 150) / 100;
|
||||
|
||||
if (B_SCALED_EXP >= GEN_5 && B_SCALED_EXP != GEN_6)
|
||||
{
|
||||
// Note: There is an edge case where if a pokemon receives a large amount of exp, it wouldn't be properly calculated
|
||||
// because of multiplying by scaling factor(the value would simply be larger than an u32 can hold). Hence u64 is needed.
|
||||
u64 value = *expAmount;
|
||||
u8 faintedLevel = gBattleMons[faintedBattler].level;
|
||||
u8 expGetterLevel = GetMonData(&gPlayerParty[expGetterMonId], MON_DATA_LEVEL);
|
||||
|
||||
value *= sExperienceScalingFactors[(faintedLevel * 2) + 10];
|
||||
value /= sExperienceScalingFactors[faintedLevel + expGetterLevel + 10];
|
||||
*expAmount = value + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BS_ItemRestoreHP(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
|
@ -11082,3 +11082,12 @@ bool32 IsAlly(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
return (GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef));
|
||||
}
|
||||
|
||||
bool32 IsGen6ExpShareEnabled(void)
|
||||
{
|
||||
#if I_EXP_SHARE_ITEM < GEN_6
|
||||
return FALSE;
|
||||
#else
|
||||
return FlagGet(I_EXP_SHARE_FLAG);
|
||||
#endif
|
||||
}
|
||||
|
@ -6102,9 +6102,9 @@ const struct Item gItems[] =
|
||||
.price = 3000,
|
||||
.holdEffect = HOLD_EFFECT_EXP_SHARE,
|
||||
.description = sExpShareDesc,
|
||||
.pocket = POCKET_ITEMS,
|
||||
.type = ITEM_USE_BAG_MENU,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
|
||||
.pocket = I_EXP_SHARE_ITEM >= GEN_6 ? POCKET_KEY_ITEMS : POCKET_ITEMS,
|
||||
.type = ITEM_USE_FIELD,
|
||||
.fieldUseFunc = ItemUseOutOfBattle_ExpShare,
|
||||
.flingPower = 30,
|
||||
},
|
||||
|
||||
|
@ -2406,9 +2406,15 @@ static const u8 sWhiteHerbDesc[] = _(
|
||||
"lowered stat.");
|
||||
|
||||
static const u8 sExpShareDesc[] = _(
|
||||
#if I_EXP_SHARE_ITEM >= GEN_6
|
||||
"This device gives\n"
|
||||
"exp. to other\n"
|
||||
"party members.");
|
||||
#else
|
||||
"A hold item that\n"
|
||||
"gets Exp. points\n"
|
||||
"from battles.");
|
||||
#endif
|
||||
|
||||
static const u8 sQuickClawDesc[] = _(
|
||||
"A hold item that\n"
|
||||
|
@ -200,6 +200,33 @@ void ItemUseOutOfBattle_Mail(u8 taskId)
|
||||
Task_FadeAndCloseBagMenu(taskId);
|
||||
}
|
||||
|
||||
STATIC_ASSERT(I_EXP_SHARE_ITEM < GEN_6 || I_EXP_SHARE_FLAG > TEMP_FLAGS_END, YouNeedToSetAFlagToUseGen6ExpShare);
|
||||
|
||||
void ItemUseOutOfBattle_ExpShare(u8 taskId)
|
||||
{
|
||||
#if I_EXP_SHARE_ITEM >= GEN_6
|
||||
if (IsGen6ExpShareEnabled())
|
||||
{
|
||||
PlaySE(SE_PC_OFF);
|
||||
if (!gTasks[taskId].data[2]) // to account for pressing select in the overworld
|
||||
DisplayItemMessageOnField(taskId, gText_ExpShareOff, Task_CloseCantUseKeyItemMessage);
|
||||
else
|
||||
DisplayItemMessage(taskId, 1, gText_ExpShareOff, CloseItemMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySE(SE_EXP_MAX);
|
||||
if (!gTasks[taskId].data[2]) // to account for pressing select in the overworld
|
||||
DisplayItemMessageOnField(taskId, gText_ExpShareOn, Task_CloseCantUseKeyItemMessage);
|
||||
else
|
||||
DisplayItemMessage(taskId, 1, gText_ExpShareOn, CloseItemMessage);
|
||||
}
|
||||
FlagToggle(I_EXP_SHARE_FLAG);
|
||||
#else
|
||||
DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ItemUseOutOfBattle_Bike(u8 taskId)
|
||||
{
|
||||
s16 *data = gTasks[taskId].data;
|
||||
|
@ -1831,3 +1831,5 @@ const u8 gText_Answer[] = _("ANSWER");
|
||||
const u8 gText_PokeBalls[] = _("POKé BALLS");
|
||||
const u8 gText_Berry[] = _("BERRY");
|
||||
const u8 gText_Berries[] = _("BERRIES");
|
||||
const u8 gText_ExpShareOn[] = _("The Exp. Share has been turned on.{PAUSE_UNTIL_PRESS}");
|
||||
const u8 gText_ExpShareOff[] = _("The Exp. Share has been turned off.{PAUSE_UNTIL_PRESS}");
|
||||
|
Loading…
Reference in New Issue
Block a user