diff --git a/include/battle.h b/include/battle.h index e4b773089244..0f97f904d256 100644 --- a/include/battle.h +++ b/include/battle.h @@ -437,6 +437,7 @@ struct BattleStruct u8 arenaLostPlayerMons; // Bits for party member, lost as in referee's decision, not by fainting. u8 arenaLostOpponentMons; u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed pokemon. + u8 sentInBackup; }; #define GET_MOVE_TYPE(move, typeArg) \ diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 9e0d8e0be4fd..8942fb45543e 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -1,7 +1,7 @@ #ifndef GUARD_CONSTANTS_BATTLE_STRING_IDS_H #define GUARD_CONSTANTS_BATTLE_STRING_IDS_H -#define BATTLESTRINGS_COUNT 369 +#define BATTLESTRINGS_COUNT 370 #define BATTLESTRINGS_ID_ADDER 12 // all battlestrings have its ID + 12, because first 5 are reserved @@ -382,5 +382,6 @@ #define STRINGID_PKMNBOXLANETTESPCFULL 378 #define STRINGID_TRAINER1WINTEXT 379 #define STRINGID_TRAINER2WINTEXT 380 +#define STRINGID_EXPSHAREDISTRIBUTES 381 #endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H diff --git a/src/battle_message.c b/src/battle_message.c index c004665d759b..83fcbf71b555 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -519,6 +519,8 @@ static const u8 sText_Trainer2WinText[]; static const u8 sText_TwoInGameTrainersDefeated[]; static const u8 sText_Trainer2LoseText[]; +static const u8 sText_ExpShareDistributes[]; + const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT] = { [STRINGID_TRAINER1LOSETEXT - 12] = sText_Trainer1LoseText, @@ -890,6 +892,7 @@ const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_PKMNBOXLANETTESPCFULL - 12] = gText_PkmnTransferredLanettesPCBoxFull, [STRINGID_TRAINER1WINTEXT - 12] = sText_Trainer1WinText, [STRINGID_TRAINER2WINTEXT - 12] = sText_Trainer2WinText, + [STRINGID_EXPSHAREDISTRIBUTES - 12] = sText_ExpShareDistributes, }; const u16 gMissStringIds[] = @@ -1354,6 +1357,8 @@ const u8 gText_BattleRecordedOnPass[] = _("{B_PLAYER_NAME}'s battle result was r static const u8 sText_LinkTrainerWantsToBattlePause[] = _("{B_LINK_OPPONENT1_NAME}\nwants to battle!{PAUSE 49}"); static const u8 sText_TwoLinkTrainersWantToBattlePause[] = _("{B_LINK_OPPONENT1_NAME} and {B_LINK_OPPONENT2_NAME}\nwant to battle!{PAUSE 49}"); +static const u8 sText_ExpShareDistributes[] = _("The rest of your team gained Exp.\nPoints due to the Exp. Share!{PAUSE 64}"); + // This is four lists of moves which use a different attack string in Japanese // to the default. See the documentation for ChooseTypeOfMoveUsedString for more detail. static const u16 sGrammarMoveUsedTable[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2fdc11ceb91c..7a6aa06d6015 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -111,6 +111,9 @@ static void Cmd_jumpifsideaffecting(void); static void Cmd_jumpifstat(void); static void Cmd_jumpifstatus3condition(void); static void Cmd_jumpiftype(void); +static u32 ExpCalculator(u32 a, u32 t, u32 b, u32 e, u32 L, u32 Lp, u32 p, u32 f, u32 v, u32 s); +static bool8 WasWholeTeamSentIn(u8 sentIn); +static bool8 CouldHaveEvolvedViaLevelUp(u16 species, u8 level); static void Cmd_getexp(void); static void Cmd_unknown_24(void); static void Cmd_movevaluescleanup(void); @@ -3211,22 +3214,119 @@ static void Cmd_jumpiftype(void) gBattlescriptCurrInstr += 7; } +static u32 ExpCalculator(u32 a, u32 t, u32 b, u32 e, u32 L, u32 Lp, u32 p, u32 f, u32 v, u32 s) +{ + u32 calculatedExp; + + Lp++; + calculatedExp = (a * t * b * e * L * p * v) / (10 * 10 * 10 * 10); + calculatedExp = (calculatedExp * f) / 10; + calculatedExp = (calculatedExp) / (7 * s); + + // delete the above and replace it with this to update the experience formula + /*u32 calculatedExp, calculatedExpTop, calculatedExpBottom; + + calculatedExp = (a * b * L) / (10 * 5 * s); + + calculatedExpTop = (2 * L + 10) * (2 * L + 10); + calculatedExpBottom = (L + Lp + 10) * (L + Lp + 10) * Sqrt(L + Lp + 10); //(L + Lp + 10)**2.5 + + calculatedExp *= calculatedExpTop; + calculatedExp = calculatedExp / calculatedExpBottom; + calculatedExp *= Sqrt(2 * L + 10); //Best way to prevent overflow; now Base Exp < 3245 works + + calculatedExp += 1; + + calculatedExp = (calculatedExp * t * e * v) / (10 * 10 * 10); + calculatedExp = (calculatedExp * p * f) / 10;*/ + + return calculatedExp; +} + +static bool8 WasWholeTeamSentIn(u8 sentIn) +{ + int i; + + for (i = 0; i < 6; ++i) { + if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, 0) == 0) + return TRUE; + + if (GetMonData(&gPlayerParty[i], MON_DATA_HP, 0) == 0 || GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG, 0) || GetMonData(&gPlayerParty[i], MON_DATA_LEVEL, 0) >= MAX_LEVEL) + continue; + + if (!(sentIn & (1 << i))) + return FALSE; + } + + return TRUE; +} + +// gonna have to add new evo methods as they are implemented +static bool8 CouldHaveEvolvedViaLevelUp(u16 species, u8 level) +{ + u32 i; + const struct Evolution* evolutions = gEvolutionTable[species]; + + for (i = 0; i < EVOS_PER_MON; ++i) + { + switch (evolutions[i].method) + { + case EVO_LEVEL: + case EVO_LEVEL_ATK_GT_DEF: + case EVO_LEVEL_ATK_EQ_DEF: + case EVO_LEVEL_ATK_LT_DEF: + case EVO_LEVEL_SILCOON: + case EVO_LEVEL_CASCOON: + case EVO_LEVEL_NINJASK: + case EVO_LEVEL_SHEDINJA: + if (level >= evolutions[i].param) + return TRUE; + } + } + + return FALSE; +} + +enum +{ + GETEXP_STATE_START, + GETEXP_STATE_CHECK_CURR_MON, + GETEXP_STATE_CALCULATE, + GETEXP_STATE_DISTRIBUTE, + GETEXP_STATE_SET_STATS, + GETEXP_STATE_LEVEL_UP, + GETEXP_STATE_PREPARE_LOOP, + GETEXP_STATE_END, +}; + +enum +{ + EXP_PARTICIPANTS, + EXP_VIA_EXP_SHARE, +}; + static void Cmd_getexp(void) { u16 item; - s32 i; // also used as stringId u8 holdEffect; + s32 i; // also used as stringId s32 sentIn; - s32 viaExpShare = 0; + s32 viaExpShare = 0, viaSentIn = 0; + u16 calculatedExp = 0; u16 *exp = &gBattleStruct->expValue; + + item = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HELD_ITEM, NULL); + holdEffect = ItemId_GetHoldEffect(item); gBattlerFainted = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); sentIn = gSentPokesToOpponent[(gBattlerFainted & 2) >> 1]; switch (gBattleScripting.getexpState) { - case 0: // check if should receive exp at all - if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT || (gBattleTypeFlags & + case GETEXP_STATE_START: // check if should receive exp at all + if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT + || gBattleStruct->givenExpMons & gBitTable[gBattlerPartyIndexes[gBattlerFainted]] + || (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_TRAINER_HILL @@ -3235,156 +3335,191 @@ static void Cmd_getexp(void) | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER))) { - gBattleScripting.getexpState = 6; // goto last case + goto END_EXP_GIVE; } else { gBattleScripting.getexpState++; gBattleStruct->givenExpMons |= gBitTable[gBattlerPartyIndexes[gBattlerFainted]]; + gBattleStruct->expGetterMonId = 0; + gBattleStruct->sentInBackup = sentIn; + gBattleStruct->sentInPokes = sentIn; + gBattleMoveDamage = 0; + *exp = EXP_PARTICIPANTS; } break; - case 1: // calculate experience points to redistribute + case GETEXP_STATE_CHECK_CURR_MON: + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPECIES, NULL) == SPECIES_NONE + || GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP, NULL) == 0 + || GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_IS_EGG, 0)) + { + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.getexpState = GETEXP_STATE_PREPARE_LOOP; + gBattleMoveDamage = 0; // used for exp + break; + } + else if (*exp == EXP_PARTICIPANTS && !(gBattleStruct->sentInPokes & 1)) + { + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.getexpState = GETEXP_STATE_PREPARE_LOOP; + gBattleMoveDamage = 0; // used for exp + break; + } + else if (*exp == EXP_VIA_EXP_SHARE && gBattleStruct->sentInPokes & 1) + { + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.getexpState = GETEXP_STATE_PREPARE_LOOP; + gBattleMoveDamage = 0; // used for exp + break; + } + + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) >= MAX_LEVEL) { - u16 calculatedExp; - s32 viaSentIn; + MonGainEVs(&gPlayerParty[gBattleStruct->expGetterMonId], gBattleMons[gBattlerFainted].species); + gBattleStruct->sentInPokes >>= 1; // One less pokemon to distribute exp to + gBattleScripting.getexpState = GETEXP_STATE_PREPARE_LOOP; + gBattleMoveDamage = 0; // used for exp + break; + } + + gBattleScripting.getexpState++; + // fall through + case GETEXP_STATE_CALCULATE: // calculate experience points to redistribute + { + u32 trainerBonus, tradeBonus, baseExp, eggBoost, defLevel, pokeLevel, affection, evolutionBoost, divisor; for (viaSentIn = 0, i = 0; i < PARTY_SIZE; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == SPECIES_NONE || GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) continue; + if (gBitTable[i] & sentIn) viaSentIn++; - - item = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); - - if (item == ITEM_ENIGMA_BERRY) - holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; - else - holdEffect = ItemId_GetHoldEffect(item); - } - - calculatedExp = gBaseStats[gBattleMons[gBattlerFainted].species].expYield * gBattleMons[gBattlerFainted].level / 7; - - if (gSaveBlock2Ptr->expShare) // exp share is turned on - { - *exp = calculatedExp / 2 / viaSentIn; - if (*exp == 0) - *exp = 1; - - viaExpShare = gSaveBlock1Ptr->playerPartyCount; - gExpShareExp = calculatedExp / 2; - if (gExpShareExp == 0) - gExpShareExp = 1; - } - else - { - *exp = calculatedExp / viaSentIn; - if (*exp == 0) - *exp = 1; - gExpShareExp = 0; - } - + else if (gSaveBlock2Ptr->expShare) + viaExpShare++; + } + + // start with trainer boost + trainerBonus = 10; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + trainerBonus = 15; + + // traded mon boost + tradeBonus = 10; + if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId])) + tradeBonus = 15; + + // get the base experience + baseExp = gBaseStats[gBattleMons[gBattlerFainted].species].expYield; + + // lucky egg boost + eggBoost = 10; + if (holdEffect == HOLD_EFFECT_LUCKY_EGG) + eggBoost = 15; + + defLevel = gBattleMons[gBattlerFainted].level; + + pokeLevel = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL); + + // affection boost + affection = 10; + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_FRIENDSHIP, NULL) >= 220) + affection = 12; + + // evolution boost + evolutionBoost = 10; + if (CouldHaveEvolvedViaLevelUp(GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPECIES, NULL), GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL, NULL))) + evolutionBoost = 12; + + + if (*exp == EXP_PARTICIPANTS) // In battle recieves full EXP + divisor = 1; + else // Otherwise Exp / 2 + divisor = 2; + + calculatedExp = ExpCalculator(trainerBonus, tradeBonus, baseExp, eggBoost, defLevel, pokeLevel, 1, affection, evolutionBoost, divisor); + + if (calculatedExp == 0) + calculatedExp = 1; + + gBattleMoveDamage = calculatedExp; + gBattleScripting.getexpState++; - gBattleStruct->expGetterMonId = 0; - gBattleStruct->sentInPokes = sentIn; } // fall through - case 2: // set exp value to the poke in expgetter_id and print message - if (gBattleControllerExecFlags == 0) - { - item = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HELD_ITEM); - - if (item == ITEM_ENIGMA_BERRY) - holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; - else - holdEffect = ItemId_GetHoldEffect(item); + case GETEXP_STATE_DISTRIBUTE: // set exp value to the poke in expgetter_id and print message + //if (gBattleControllerExecFlags) break; - if (!gSaveBlock2Ptr->expShare && !(gBattleStruct->sentInPokes & 1)) + // music change in wild battle after fainting a poke + if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) + { + // lmao take care of wild double battles too + if (((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && (gBattleMons[0].hp || gBattleMons[2].hp) && gBattleMons[1].hp == 0 && gBattleMons[3].hp == 0) + || (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMons[0].hp && gBattleMons[1].hp)) { - *(&gBattleStruct->sentInPokes) >>= 1; - gBattleScripting.getexpState = 5; - gBattleMoveDamage = 0; // used for exp + BattleStopLowHpSound(); + PlayBGM(MUS_VICTORY_WILD); + gBattleStruct->wildVictorySong++; } - else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) == MAX_LEVEL) + } + + if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP) > 0) + { + // get the boosted stringId + if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId]) + || CouldHaveEvolvedViaLevelUp(GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPECIES, NULL), GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL, NULL)) + || holdEffect == HOLD_EFFECT_LUCKY_EGG + || GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_FRIENDSHIP, NULL) >= 220) { - *(&gBattleStruct->sentInPokes) >>= 1; - gBattleScripting.getexpState = 5; - gBattleMoveDamage = 0; // used for exp + // check if the pokemon doesn't belong to the player + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterMonId >= 3) + i = STRINGID_EMPTYSTRING4; + else + i = STRINGID_ABOOSTED; } else + i = STRINGID_EMPTYSTRING4; + + // Get exp getter bank + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { - // music change in wild battle after fainting a poke - if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && gBattleMons[0].hp && !gBattleStruct->wildVictorySong) + if (gBattlerPartyIndexes[B_POSITION_PLAYER_RIGHT] == gBattleStruct->expGetterMonId && !(gAbsentBattlerFlags & gBitTable[B_POSITION_PLAYER_RIGHT])) { - BattleStopLowHpSound(); - PlayBGM(MUS_VICTORY_WILD); - gBattleStruct->wildVictorySong++; + gBattleStruct->expGetterBattlerId = B_POSITION_PLAYER_RIGHT; } - - if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP) && !GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_IS_EGG)) + else { - if (gBattleStruct->sentInPokes & 1) - gBattleMoveDamage = *exp; + if (!(gAbsentBattlerFlags & gBitTable[B_POSITION_PLAYER_LEFT])) + gBattleStruct->expGetterBattlerId = B_POSITION_PLAYER_LEFT; else - gBattleMoveDamage = 0; - - if (gSaveBlock2Ptr->expShare) - gBattleMoveDamage += gExpShareExp; - if (holdEffect == HOLD_EFFECT_LUCKY_EGG) - gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; - - if (IsTradedMon(&gPlayerParty[gBattleStruct->expGetterMonId])) - { - // check if the pokemon doesn't belong to the player - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gBattleStruct->expGetterMonId >= 3) - { - i = STRINGID_EMPTYSTRING4; - } - else - { - gBattleMoveDamage = (gBattleMoveDamage * 150) / 100; - i = STRINGID_ABOOSTED; - } - } - else - { - i = STRINGID_EMPTYSTRING4; - } - - // get exp getter battlerId - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) - { - if (!(gBattlerPartyIndexes[2] != gBattleStruct->expGetterMonId) && !(gAbsentBattlerFlags & gBitTable[2])) - gBattleStruct->expGetterBattlerId = 2; - else - { - if (!(gAbsentBattlerFlags & gBitTable[0])) - gBattleStruct->expGetterBattlerId = 0; - else - gBattleStruct->expGetterBattlerId = 2; - } - } - else - { - gBattleStruct->expGetterBattlerId = 0; - } - - PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBattlerId, gBattleStruct->expGetterMonId); - // buffer 'gained' or 'gained a boosted' - PREPARE_STRING_BUFFER(gBattleTextBuff2, i); - PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 5, gBattleMoveDamage); - - PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBattlerId); - MonGainEVs(&gPlayerParty[gBattleStruct->expGetterMonId], gBattleMons[gBattlerFainted].species); + gBattleStruct->expGetterBattlerId = B_POSITION_PLAYER_RIGHT; } - gBattleStruct->sentInPokes >>= 1; - gBattleScripting.getexpState++; } + else + gBattleStruct->expGetterBattlerId = B_POSITION_PLAYER_LEFT; + + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattleStruct->expGetterBattlerId, gBattleStruct->expGetterMonId) + + PREPARE_STRING_BUFFER(gBattleTextBuff2, i); + + PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff3, 10, calculatedExp) + + if (*exp == EXP_PARTICIPANTS) //Don't print the gained exp string unless it participated in battle + PrepareStringBattle(STRINGID_PKMNGAINEDEXP, gBattleStruct->expGetterBattlerId); + + MonGainEVs(&gPlayerParty[gBattleStruct->expGetterMonId], gBattleMons[gBattlerFainted].species); } - break; - case 3: // Set stats and give exp + else + { + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.getexpState = GETEXP_STATE_PREPARE_LOOP; + gBattleMoveDamage = 0; + break; + } + gBattleStruct->sentInPokes >>= 1; + gBattleScripting.getexpState++; + // fall through + case GETEXP_STATE_SET_STATS: // Set stats and give exp if (gBattleControllerExecFlags == 0) { gBattleBufferB[gBattleStruct->expGetterBattlerId][0] = 0; @@ -3401,19 +3536,28 @@ static void Cmd_getexp(void) BtlController_EmitExpUpdate(0, gBattleStruct->expGetterMonId, gBattleMoveDamage); MarkBattlerForControllerExec(gActiveBattler); } + else + { + gBattleScripting.getexpState = GETEXP_STATE_PREPARE_LOOP; + gBattleMoveDamage = 0; + break; + } gBattleScripting.getexpState++; } break; - case 4: // lvl up if necessary + case GETEXP_STATE_LEVEL_UP: // lvl up if necessary if (gBattleControllerExecFlags == 0) { gActiveBattler = gBattleStruct->expGetterBattlerId; if (gBattleBufferB[gActiveBattler][0] == CONTROLLER_TWORETURNVALUES && gBattleBufferB[gActiveBattler][1] == RET_VALUE_LEVELED_UP) { + u8 leveledUpBank = 0xFF; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gBattlerPartyIndexes[gActiveBattler] == gBattleStruct->expGetterMonId) HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler); PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattleStruct->expGetterMonId); + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 3, GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL)); BattleScriptPushCursor(); @@ -3423,64 +3567,78 @@ static void Cmd_getexp(void) AdjustFriendship(&gPlayerParty[gBattleStruct->expGetterMonId], FRIENDSHIP_EVENT_GROW_LEVEL); // update battle mon structure after level up - if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId && gBattleMons[0].hp) - { - gBattleMons[0].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL); - gBattleMons[0].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP); - gBattleMons[0].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); - gBattleMons[0].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); - gBattleMons[0].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); - // Why is this duplicated? - gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); - gBattleMons[0].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); - - gBattleMons[0].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK); - gBattleMons[0].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPDEF); - } - // What is else if? - if (gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] == gBattleStruct->expGetterMonId && gBattleMons[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)].hp > 0) + leveledUpBank = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)] == gBattleStruct->expGetterMonId && gBattleMons[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)].hp > 0) + leveledUpBank = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + + if (leveledUpBank != 0xFF) { - gBattleMons[2].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL); - gBattleMons[2].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP); - gBattleMons[2].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); - gBattleMons[2].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); - gBattleMons[2].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); - // Duplicated again, but this time there's no Sp Defense - gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); - gBattleMons[2].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); - - gBattleMons[2].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK); + gBattleMons[leveledUpBank].level = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL); + gBattleMons[leveledUpBank].hp = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP); + gBattleMons[leveledUpBank].maxHP = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); + + if (!(gBattleMons[leveledUpBank].status2 & STATUS2_TRANSFORMED)) + { + gBattleMons[leveledUpBank].attack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); + gBattleMons[leveledUpBank].defense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); + gBattleMons[leveledUpBank].speed = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPEED); + gBattleMons[leveledUpBank].spAttack = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPATK); + gBattleMons[leveledUpBank].spDefense = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_SPDEF); + } } - gBattleScripting.getexpState = 5; } else { gBattleMoveDamage = 0; - gBattleScripting.getexpState = 5; } + gBattleScripting.getexpState++; } break; - case 5: // looper increment + case GETEXP_STATE_PREPARE_LOOP: // looper increment if (gBattleMoveDamage) // there is exp to give, goto case 3 that gives exp { - gBattleScripting.getexpState = 3; + gBattleScripting.getexpState = GETEXP_STATE_SET_STATS; } else { gBattleStruct->expGetterMonId++; - if (gBattleStruct->expGetterMonId < PARTY_SIZE) - gBattleScripting.getexpState = 2; // loop again + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + { + if (gBattleStruct->expGetterMonId < 3) + gBattleScripting.getexpState = GETEXP_STATE_CHECK_CURR_MON; // loop again + else + gBattleScripting.getexpState = GETEXP_STATE_END; // we're done + } else - gBattleScripting.getexpState = 6; // we're done + { + if (gBattleStruct->expGetterMonId < 6) + gBattleScripting.getexpState = GETEXP_STATE_CHECK_CURR_MON; // loop again + else + gBattleScripting.getexpState = GETEXP_STATE_END; // we're done + } } break; - case 6: // increment instruction + case GETEXP_STATE_END: // increment instruction if (gBattleControllerExecFlags == 0) { - // not sure why gf clears the item and ability here - gBattleMons[gBattlerFainted].item = 0; - gBattleMons[gBattlerFainted].ability = 0; - gBattlescriptCurrInstr += 2; + if (gSaveBlock2Ptr->expShare && *exp == EXP_PARTICIPANTS && !WasWholeTeamSentIn(gBattleStruct->sentInBackup)) + { + *exp = EXP_VIA_EXP_SHARE; + gBattleStruct->expGetterMonId = 0; + gBattleMoveDamage = 0; + gBattleStruct->sentInPokes = gBattleStruct->sentInBackup; + gBattleScripting.getexpState = GETEXP_STATE_CHECK_CURR_MON; + PrepareStringBattle(STRINGID_EXPSHAREDISTRIBUTES, 0); + } + else + { + END_EXP_GIVE: + // not sure why gf clears the item and ability here + gBattleMons[gBattlerFainted].item = 0; + gBattleMons[gBattlerFainted].ability = 0; + gBattlescriptCurrInstr += 2; + } } break; }