diff options
Diffstat (limited to 'src/pokemon.c')
-rw-r--r-- | src/pokemon.c | 558 |
1 files changed, 299 insertions, 259 deletions
diff --git a/src/pokemon.c b/src/pokemon.c index 5812e987a..29ac4547f 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -4640,29 +4640,56 @@ void CopyPlayerPartyMonToBattleData(u8 battlerId, u8 partyIndex) bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex) { - return PokemonUseItemEffects(mon, item, partyIndex, moveIndex, 0); -} - -bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, u8 e) + return PokemonUseItemEffects(mon, item, partyIndex, moveIndex, FALSE); +} + +#define UPDATE_FRIENDSHIP_FROM_ITEM \ +{ \ + if ((retVal == 0 || friendshipOnly) && !ShouldSkipFriendshipChange() && friendshipChange == 0) \ + { \ + friendshipChange = itemEffect[itemEffectParam]; \ + friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); \ + if (friendshipChange > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) \ + friendship += 150 * friendshipChange / 100; \ + else \ + friendship += friendshipChange; \ + if (friendshipChange > 0) \ + { \ + if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == ITEM_LUXURY_BALL) \ + friendship++; \ + if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) \ + friendship++; \ + } \ + if (friendship < 0) \ + friendship = 0; \ + if (friendship > MAX_FRIENDSHIP) \ + friendship = MAX_FRIENDSHIP; \ + SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); \ + retVal = FALSE; \ + } \ +} + +// Returns TRUE if the item has no effect on the Pokémon, FALSE otherwise +bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, bool8 usedByAI) { u32 dataUnsigned; s32 dataSigned; s32 friendship; - s32 cmdIndex; + s32 i; bool8 retVal = TRUE; const u8 *itemEffect; - u8 var_3C = 6; - u32 var_38; - s8 var_34 = 0; + u8 itemEffectParam = ITEM_EFFECT_ARG_START; + u32 temp1, temp2; + s8 friendshipChange = 0; u8 holdEffect; - u8 battlerId = 4; - u32 var_28 = 0; + u8 battlerId = MAX_BATTLERS_COUNT; + u32 friendshipOnly = FALSE; u16 heldItem; - u8 r10; - u32 r5; - s8 r2; + u8 effectFlags; + s8 evChange; u16 evCount; + // Get item hold effect heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, NULL); if (heldItem == ITEM_ENIGMA_BERRY) { @@ -4676,19 +4703,20 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov holdEffect = ItemId_GetHoldEffect(heldItem); } + // Get battler id (if relevant) gPotentialItemEffectBattler = gBattlerInMenuId; if (gMain.inBattle) { gActiveBattler = gBattlerInMenuId; - cmdIndex = (GetBattlerSide(gActiveBattler) != B_SIDE_PLAYER); - while (cmdIndex < gBattlersCount) + i = (GetBattlerSide(gActiveBattler) != B_SIDE_PLAYER); + while (i < gBattlersCount) { - if (gBattlerPartyIndexes[cmdIndex] == partyIndex) + if (gBattlerPartyIndexes[i] == partyIndex) { - battlerId = cmdIndex; + battlerId = i; break; } - cmdIndex += 2; + i += 2; } } else @@ -4697,11 +4725,13 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov battlerId = MAX_BATTLERS_COUNT; } + // Skip using the item if it won't do anything if (!ITEM_HAS_EFFECT(item)) return TRUE; if (gItemEffectTable[item - ITEM_POTION] == NULL && item != ITEM_ENIGMA_BERRY) return TRUE; + // Get item effect if (item == ITEM_ENIGMA_BERRY) { if (gMain.inBattle) @@ -4714,79 +4744,98 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov itemEffect = gItemEffectTable[item - ITEM_POTION]; } - for (cmdIndex = 0; cmdIndex < 6; cmdIndex++) + // Do item effect + for (i = 0; i < ITEM_EFFECT_ARG_START; i++) { - switch (cmdIndex) + switch (i) { - // infatuation heal, x attack, sacred ash and dire hit + + // Handle ITEM0 effects (infatuation, Dire Hit, X Attack). ITEM0_SACRED_ASH is handled in party_menu.c case 0: - if ((itemEffect[cmdIndex] & ITEM0_INFATUATION) + // Cure infatuation + if ((itemEffect[i] & ITEM0_INFATUATION) && gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && (gBattleMons[battlerId].status2 & STATUS2_INFATUATION)) { gBattleMons[battlerId].status2 &= ~STATUS2_INFATUATION; retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM0_DIRE_HIT) + + // Dire Hit + if ((itemEffect[i] & ITEM0_DIRE_HIT) && !(gBattleMons[gActiveBattler].status2 & STATUS2_FOCUS_ENERGY)) { gBattleMons[gActiveBattler].status2 |= STATUS2_FOCUS_ENERGY; retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM0_X_ATTACK) + + // X Attack + if ((itemEffect[i] & ITEM0_X_ATTACK) && gBattleMons[gActiveBattler].statStages[STAT_ATK] < MAX_STAT_STAGE) { - gBattleMons[gActiveBattler].statStages[STAT_ATK] += itemEffect[cmdIndex] & ITEM0_X_ATTACK; + gBattleMons[gActiveBattler].statStages[STAT_ATK] += itemEffect[i] & ITEM0_X_ATTACK; if (gBattleMons[gActiveBattler].statStages[STAT_ATK] > MAX_STAT_STAGE) gBattleMons[gActiveBattler].statStages[STAT_ATK] = MAX_STAT_STAGE; retVal = FALSE; } break; - // in-battle stat boosting effects + + // Handle ITEM1 effects (in-battle stat boosting effects) case 1: - if ((itemEffect[cmdIndex] & ITEM1_X_DEFEND) + // X Defend + if ((itemEffect[i] & ITEM1_X_DEFEND) && gBattleMons[gActiveBattler].statStages[STAT_DEF] < MAX_STAT_STAGE) { - gBattleMons[gActiveBattler].statStages[STAT_DEF] += (itemEffect[cmdIndex] & ITEM1_X_DEFEND) >> 4; + gBattleMons[gActiveBattler].statStages[STAT_DEF] += (itemEffect[i] & ITEM1_X_DEFEND) >> 4; if (gBattleMons[gActiveBattler].statStages[STAT_DEF] > MAX_STAT_STAGE) gBattleMons[gActiveBattler].statStages[STAT_DEF] = MAX_STAT_STAGE; retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM1_X_SPEED) + + // X Speed + if ((itemEffect[i] & ITEM1_X_SPEED) && gBattleMons[gActiveBattler].statStages[STAT_SPEED] < MAX_STAT_STAGE) { - gBattleMons[gActiveBattler].statStages[STAT_SPEED] += itemEffect[cmdIndex] & ITEM1_X_SPEED; + gBattleMons[gActiveBattler].statStages[STAT_SPEED] += itemEffect[i] & ITEM1_X_SPEED; if (gBattleMons[gActiveBattler].statStages[STAT_SPEED] > MAX_STAT_STAGE) gBattleMons[gActiveBattler].statStages[STAT_SPEED] = MAX_STAT_STAGE; retVal = FALSE; } break; - // more stat boosting effects + // Handle ITEM2 effects (more stat boosting effects) case 2: - if ((itemEffect[cmdIndex] & ITEM2_X_ACCURACY) + // X Accuracy + if ((itemEffect[i] & ITEM2_X_ACCURACY) && gBattleMons[gActiveBattler].statStages[STAT_ACC] < MAX_STAT_STAGE) { - gBattleMons[gActiveBattler].statStages[STAT_ACC] += (itemEffect[cmdIndex] & ITEM2_X_ACCURACY) >> 4; + gBattleMons[gActiveBattler].statStages[STAT_ACC] += (itemEffect[i] & ITEM2_X_ACCURACY) >> 4; if (gBattleMons[gActiveBattler].statStages[STAT_ACC] > MAX_STAT_STAGE) gBattleMons[gActiveBattler].statStages[STAT_ACC] = MAX_STAT_STAGE; retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM2_X_SPATK) + + // X Sp Attack + if ((itemEffect[i] & ITEM2_X_SPATK) && gBattleMons[gActiveBattler].statStages[STAT_SPATK] < MAX_STAT_STAGE) { - gBattleMons[gActiveBattler].statStages[STAT_SPATK] += itemEffect[cmdIndex] & ITEM2_X_SPATK; + gBattleMons[gActiveBattler].statStages[STAT_SPATK] += itemEffect[i] & ITEM2_X_SPATK; if (gBattleMons[gActiveBattler].statStages[STAT_SPATK] > MAX_STAT_STAGE) gBattleMons[gActiveBattler].statStages[STAT_SPATK] = MAX_STAT_STAGE; retVal = FALSE; } break; + + // Handle ITEM3 effects (Guard Spec, Rare Candy, cure status) case 3: - if ((itemEffect[cmdIndex] & ITEM3_GUARD_SPEC) + // Guard Spec + if ((itemEffect[i] & ITEM3_GUARD_SPEC) && gSideTimers[GetBattlerSide(gActiveBattler)].mistTimer == 0) { gSideTimers[GetBattlerSide(gActiveBattler)].mistTimer = 5; retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM3_LEVEL_UP) + + // Rare Candy + if ((itemEffect[i] & ITEM3_LEVEL_UP) && GetMonData(mon, MON_DATA_LEVEL, NULL) != MAX_LEVEL) { dataUnsigned = gExperienceTables[gBaseStats[GetMonData(mon, MON_DATA_SPECIES, NULL)].growthRate][GetMonData(mon, MON_DATA_LEVEL, NULL) + 1]; @@ -4794,106 +4843,120 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov CalculateMonStats(mon); retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM3_SLEEP) - && HealStatusConditions(mon, partyIndex, 7, battlerId) == 0) + + // Cure status + if ((itemEffect[i] & ITEM3_SLEEP) + && HealStatusConditions(mon, partyIndex, STATUS1_SLEEP, battlerId) == 0) { - if (battlerId != 4) + if (battlerId != MAX_BATTLERS_COUNT) gBattleMons[battlerId].status2 &= ~STATUS2_NIGHTMARE; retVal = FALSE; } - if ((itemEffect[cmdIndex] & ITEM3_POISON) && HealStatusConditions(mon, partyIndex, STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER, battlerId) == 0) + if ((itemEffect[i] & ITEM3_POISON) && HealStatusConditions(mon, partyIndex, STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER, battlerId) == 0) retVal = FALSE; - if ((itemEffect[cmdIndex] & ITEM3_BURN) && HealStatusConditions(mon, partyIndex, STATUS1_BURN, battlerId) == 0) + if ((itemEffect[i] & ITEM3_BURN) && HealStatusConditions(mon, partyIndex, STATUS1_BURN, battlerId) == 0) retVal = FALSE; - if ((itemEffect[cmdIndex] & ITEM3_FREEZE) && HealStatusConditions(mon, partyIndex, STATUS1_FREEZE, battlerId) == 0) + if ((itemEffect[i] & ITEM3_FREEZE) && HealStatusConditions(mon, partyIndex, STATUS1_FREEZE, battlerId) == 0) retVal = FALSE; - if ((itemEffect[cmdIndex] & ITEM3_PARALYSIS) && HealStatusConditions(mon, partyIndex, STATUS1_PARALYSIS, battlerId) == 0) + if ((itemEffect[i] & ITEM3_PARALYSIS) && HealStatusConditions(mon, partyIndex, STATUS1_PARALYSIS, battlerId) == 0) retVal = FALSE; - if ((itemEffect[cmdIndex] & ITEM3_CONFUSION) // heal confusion + if ((itemEffect[i] & ITEM3_CONFUSION) // heal confusion && gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)) { gBattleMons[battlerId].status2 &= ~STATUS2_CONFUSION; retVal = FALSE; } break; - // EV, HP, and PP raising effects + + // Handle ITEM4 effects (Change HP/Atk EVs, HP heal, PP heal, PP up, Revive, and evolution stones) case 4: - r10 = itemEffect[cmdIndex]; - if (r10 & ITEM4_PP_UP) + effectFlags = itemEffect[i]; + + // PP Up + if (effectFlags & ITEM4_PP_UP) { - r10 &= ~ITEM4_PP_UP; + effectFlags &= ~ITEM4_PP_UP; dataUnsigned = (GetMonData(mon, MON_DATA_PP_BONUSES, NULL) & gPPUpGetMask[moveIndex]) >> (moveIndex * 2); - var_38 = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); - if (dataUnsigned <= 2 && var_38 > 4) + temp1 = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); + if (dataUnsigned <= 2 && temp1 > 4) { dataUnsigned = GetMonData(mon, MON_DATA_PP_BONUSES, NULL) + gPPUpAddMask[moveIndex]; SetMonData(mon, MON_DATA_PP_BONUSES, &dataUnsigned); - dataUnsigned = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), dataUnsigned, moveIndex) - var_38; + dataUnsigned = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), dataUnsigned, moveIndex) - temp1; dataUnsigned = GetMonData(mon, MON_DATA_PP1 + moveIndex, NULL) + dataUnsigned; SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); retVal = FALSE; } } - var_38 = 0; - while (r10 != 0) + temp1 = 0; + + // Loop through and try each of the remaining ITEM4 effects + while (effectFlags != 0) { - if (r10 & 1) + if (effectFlags & 1) { - switch (var_38) + switch (temp1) { - case 0: - case 1: - // ev raise + case 0: // ITEM4_EV_HP + case 1: // ITEM4_EV_ATK evCount = GetMonEVCount(mon); - r5 = itemEffect[var_3C]; - dataSigned = GetMonData(mon, sGetMonDataEVConstants[var_38], NULL); - r2 = r5; - if (r2 > 0) + temp2 = itemEffect[itemEffectParam]; + dataSigned = GetMonData(mon, sGetMonDataEVConstants[temp1], NULL); + evChange = temp2; + + if (evChange > 0) // Increasing EV (HP or Atk) { + // Has EV increase limit already been reached? if (evCount >= MAX_TOTAL_EVS) return TRUE; if (dataSigned >= EV_ITEM_RAISE_LIMIT) break; - if (dataSigned + r2 > EV_ITEM_RAISE_LIMIT) - r5 = EV_ITEM_RAISE_LIMIT - (dataSigned + r2) + r2; + // Limit the increase + if (dataSigned + evChange > EV_ITEM_RAISE_LIMIT) + temp2 = EV_ITEM_RAISE_LIMIT - (dataSigned + evChange) + evChange; else - r5 = r2; + temp2 = evChange; - if (evCount + r5 > MAX_TOTAL_EVS) - r5 += MAX_TOTAL_EVS - (evCount + r5); - dataSigned += r5; + if (evCount + temp2 > MAX_TOTAL_EVS) + temp2 += MAX_TOTAL_EVS - (evCount + temp2); + + dataSigned += temp2; } - else + else // Decreasing EV (HP or Atk) { if (dataSigned == 0) { - var_28 = 1; - var_3C++; + // No EVs to lose, but make sure friendship updates anyway + friendshipOnly = TRUE; + itemEffectParam++; break; } - dataSigned += r2; + dataSigned += evChange; if (dataSigned < 0) dataSigned = 0; } - SetMonData(mon, sGetMonDataEVConstants[var_38], &dataSigned); + + // Update EVs and stats + SetMonData(mon, sGetMonDataEVConstants[temp1], &dataSigned); CalculateMonStats(mon); - var_3C++; + itemEffectParam++; retVal = FALSE; break; - case 2: - // revive - if (r10 & 0x10) + + case 2: // ITEM4_HEAL_HP + // If Revive, update number of times revive has been used + if (effectFlags & (ITEM4_REVIVE >> 2)) { if (GetMonData(mon, MON_DATA_HP, NULL) != 0) { - var_3C++; + itemEffectParam++; break; } if (gMain.inBattle) { - if (battlerId != 4) + if (battlerId != MAX_BATTLERS_COUNT) { gAbsentBattlerFlags &= ~gBitTable[battlerId]; CopyPlayerPartyMonToBattleData(battlerId, GetPartyIdFromBattlePartyId(gBattlerPartyIndexes[battlerId])); @@ -4912,48 +4975,53 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov { if (GetMonData(mon, MON_DATA_HP, NULL) == 0) { - var_3C++; + itemEffectParam++; break; } } // Get amount of HP to restore - dataUnsigned = itemEffect[var_3C++]; + dataUnsigned = itemEffect[itemEffectParam++]; switch (dataUnsigned) { - case ITEM6_HEAL_FULL: + case ITEM6_HEAL_HP_FULL: dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL) - GetMonData(mon, MON_DATA_HP, NULL); break; - case ITEM6_HEAL_HALF: + case ITEM6_HEAL_HP_HALF: dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL) / 2; if (dataUnsigned == 0) dataUnsigned = 1; break; - case ITEM6_HEAL_LVL_UP: + case ITEM6_HEAL_HP_LVL_UP: dataUnsigned = gBattleScripting.levelUpHP; break; } + + // Only restore HP if not at max health if (GetMonData(mon, MON_DATA_MAX_HP, NULL) != GetMonData(mon, MON_DATA_HP, NULL)) { - if (e == 0) + if (!usedByAI) { + // Restore HP dataUnsigned = GetMonData(mon, MON_DATA_HP, NULL) + dataUnsigned; if (dataUnsigned > GetMonData(mon, MON_DATA_MAX_HP, NULL)) dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL); SetMonData(mon, MON_DATA_HP, &dataUnsigned); - if (gMain.inBattle && battlerId != 4) + + // Update battler (if applicable) + if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT) { gBattleMons[battlerId].hp = dataUnsigned; - if (!(r10 & 0x10) && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + if (!(effectFlags & (ITEM4_REVIVE >> 2)) && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) { if (gBattleResults.numHealingItemsUsed < 255) gBattleResults.numHealingItemsUsed++; - // I have to re-use this variable to match. - r5 = gActiveBattler; + + temp2 = gActiveBattler; gActiveBattler = battlerId; BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); MarkBattlerForControllerExec(gActiveBattler); - gActiveBattler = r5; + gActiveBattler = temp2; } } } @@ -4963,227 +5031,197 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov } retVal = FALSE; } - r10 &= 0xEF; + effectFlags &= ~(ITEM4_REVIVE >> 2); break; - case 3: - // Heal pp in all moves. - if (!(r10 & 2)) + + case 3: // ITEM4_HEAL_PP + if (!(effectFlags & (ITEM4_HEAL_PP_ONE >> 3))) { - for (r5 = 0; (signed)(r5) < (signed)(4); r5++) + // Heal PP for all moves + for (temp2 = 0; (signed)(temp2) < (signed)(MAX_MON_MOVES); temp2++) { u16 moveId; - - dataUnsigned = GetMonData(mon, MON_DATA_PP1 + r5, NULL); - moveId = GetMonData(mon, MON_DATA_MOVE1 + r5, NULL); - if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), r5)) + dataUnsigned = GetMonData(mon, MON_DATA_PP1 + temp2, NULL); + moveId = GetMonData(mon, MON_DATA_MOVE1 + temp2, NULL); + if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2)) { - dataUnsigned += itemEffect[var_3C]; - moveId = GetMonData(mon, MON_DATA_MOVE1 + r5, NULL); - if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), r5)) + dataUnsigned += itemEffect[itemEffectParam]; + moveId = GetMonData(mon, MON_DATA_MOVE1 + temp2, NULL); // Redundant + if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2)) { - moveId = GetMonData(mon, MON_DATA_MOVE1 + r5, NULL); - dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), r5); + moveId = GetMonData(mon, MON_DATA_MOVE1 + temp2, NULL); // Redundant + dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2); } - SetMonData(mon, MON_DATA_PP1 + r5, &dataUnsigned); + SetMonData(mon, MON_DATA_PP1 + temp2, &dataUnsigned); + + // Heal battler PP too (if applicable) if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) - && !(gDisableStructs[battlerId].mimickedMoves & gBitTable[r5])) - gBattleMons[battlerId].pp[r5] = dataUnsigned; + && !(gDisableStructs[battlerId].mimickedMoves & gBitTable[temp2])) + gBattleMons[battlerId].pp[temp2] = dataUnsigned; + retVal = FALSE; } } - var_3C++; + itemEffectParam++; } - // Heal pp in one move. else { + // Heal PP for one move u16 moveId; - dataUnsigned = GetMonData(mon, MON_DATA_PP1 + moveIndex, NULL); moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex)) { - dataUnsigned += itemEffect[var_3C++]; - moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); + dataUnsigned += itemEffect[itemEffectParam++]; + moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); // Redundant if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex)) { - moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); + moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); // Redundant dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); } SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); + + // Heal battler PP too (if applicable) if (gMain.inBattle - && battlerId != 4 && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) + && battlerId != MAX_BATTLERS_COUNT && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[battlerId].mimickedMoves & gBitTable[moveIndex])) gBattleMons[battlerId].pp[moveIndex] = dataUnsigned; + retVal = FALSE; } } break; - // Evolution stone - case 7: + + // cases 4-6 are ITEM4_HEAL_PP_ONE, ITEM4_PP_UP, and ITEM4_REVIVE, which + // are already handled above by other cases or before the loop + + case 7: // ITEM4_EVO_STONE { - u16 targetSpecies = GetEvolutionTargetSpecies(mon, 2, item); + u16 targetSpecies = GetEvolutionTargetSpecies(mon, EVO_MODE_ITEM_USE, item); if (targetSpecies != SPECIES_NONE) { - BeginEvolutionScene(mon, targetSpecies, 0, partyIndex); + BeginEvolutionScene(mon, targetSpecies, FALSE, partyIndex); return FALSE; } } break; } } - var_38++; - r10 >>= 1; + temp1++; + effectFlags >>= 1; } break; - // EV and friendship + + // Handle ITEM5 effects (Change Def/SpDef/SpAtk/Speed EVs, PP Max, and friendship changes) case 5: - r10 = itemEffect[cmdIndex]; - var_38 = 0; - while (r10 != 0) + effectFlags = itemEffect[i]; + temp1 = 0; + + // Loop through and try each of the ITEM5 effects + while (effectFlags != 0) { - if (r10 & 1) + if (effectFlags & 1) { - switch (var_38) + switch (temp1) { - case 0: - case 1: - case 2: - case 3: + case 0: // ITEM5_EV_DEF + case 1: // ITEM5_EV_SPEED + case 2: // ITEM5_EV_SPDEF + case 3: // ITEM5_EV_SPATK evCount = GetMonEVCount(mon); - r5 = itemEffect[var_3C]; - dataSigned = GetMonData(mon, sGetMonDataEVConstants[var_38 + 2], NULL); - r2 = r5; - if (r2 > 0) + temp2 = itemEffect[itemEffectParam]; + dataSigned = GetMonData(mon, sGetMonDataEVConstants[temp1 + 2], NULL); + evChange = temp2; + if (evChange > 0) // Increasing EV { + // Has EV increase limit already been reached? if (evCount >= MAX_TOTAL_EVS) return TRUE; if (dataSigned >= EV_ITEM_RAISE_LIMIT) break; - if (dataSigned + r2 > EV_ITEM_RAISE_LIMIT) - r5 = EV_ITEM_RAISE_LIMIT - (dataSigned + r2) + r2; + // Limit the increase + if (dataSigned + evChange > EV_ITEM_RAISE_LIMIT) + temp2 = EV_ITEM_RAISE_LIMIT - (dataSigned + evChange) + evChange; else - r5 = r2; + temp2 = evChange; - if (evCount + r5 > MAX_TOTAL_EVS) - r5 += MAX_TOTAL_EVS - (evCount + r5); - dataSigned += r5; + if (evCount + temp2 > MAX_TOTAL_EVS) + temp2 += MAX_TOTAL_EVS - (evCount + temp2); + + dataSigned += temp2; } - else + else // Decreasing EV { if (dataSigned == 0) { - var_28 = 1; - var_3C++; + // No EVs to lose, but make sure friendship updates anyway + friendshipOnly = TRUE; + itemEffectParam++; break; } - dataSigned += r2; + dataSigned += evChange; if (dataSigned < 0) dataSigned = 0; } - SetMonData(mon, sGetMonDataEVConstants[var_38 + 2], &dataSigned); + + // Update EVs and stats + SetMonData(mon, sGetMonDataEVConstants[temp1 + 2], &dataSigned); CalculateMonStats(mon); retVal = FALSE; - var_3C++; + itemEffectParam++; break; - case 4: + + case 4: // ITEM5_PP_MAX dataUnsigned = (GetMonData(mon, MON_DATA_PP_BONUSES, NULL) & gPPUpGetMask[moveIndex]) >> (moveIndex * 2); - r5 = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); - if (dataUnsigned < 3 && r5 > 4) + temp2 = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); + if (dataUnsigned < 3 && temp2 > 4) { dataUnsigned = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); dataUnsigned &= gPPUpSetMask[moveIndex]; dataUnsigned += gPPUpAddMask[moveIndex] * 3; SetMonData(mon, MON_DATA_PP_BONUSES, &dataUnsigned); - dataUnsigned = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), dataUnsigned, moveIndex) - r5; + dataUnsigned = CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL), dataUnsigned, moveIndex) - temp2; dataUnsigned = GetMonData(mon, MON_DATA_PP1 + moveIndex, NULL) + dataUnsigned; SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); retVal = FALSE; } break; - case 5: - if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) < 100 && (retVal == 0 || var_28 != 0) && !ShouldSkipFriendshipChange() && var_34 == 0) + + case 5: // ITEM5_FRIENDSHIP_LOW + // Changes to friendship are given differently depending on + // how much friendship the Pokémon already has. + // In general, Pokémon with lower friendship receive more, + // and Pokémon with higher friendship receive less. + if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) < 100) { - var_34 = itemEffect[var_3C]; - friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); - if (var_34 > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) - friendship += 150 * var_34 / 100; - else - friendship += var_34; - if (var_34 > 0) - { - if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == ITEM_LUXURY_BALL) - friendship++; - if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) - friendship++; - } - if (friendship < 0) - friendship = 0; - if (friendship > MAX_FRIENDSHIP) - friendship = MAX_FRIENDSHIP; - SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); - retVal = FALSE; + UPDATE_FRIENDSHIP_FROM_ITEM; } - var_3C++; + itemEffectParam++; break; - case 6: - if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 100 && GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) < 200 - && (retVal == 0 || var_28 != 0) && !ShouldSkipFriendshipChange() && var_34 == 0) + + case 6: // ITEM5_FRIENDSHIP_MID + if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 100 && GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) < 200) { - var_34 = itemEffect[var_3C]; - friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); - if ((s8)(var_34) > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) - friendship += 150 * var_34 / 100; - else - friendship += var_34; - if (var_34 > 0) - { - if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == ITEM_LUXURY_BALL) - friendship++; - if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) - friendship++; - } - if (friendship < 0) - friendship = 0; - if (friendship > MAX_FRIENDSHIP) - friendship = MAX_FRIENDSHIP; - SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); - retVal = FALSE; + UPDATE_FRIENDSHIP_FROM_ITEM; } - var_3C++; + itemEffectParam++; break; - case 7: - if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 200 && (retVal == 0 || var_28 != 0) && !ShouldSkipFriendshipChange() && var_34 == 0) + + case 7: // ITEM5_FRIENDSHIP_HIGH + if (GetMonData(mon, MON_DATA_FRIENDSHIP, NULL) >= 200) { - var_34 = itemEffect[var_3C]; - friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL); - if ((s8)(var_34) > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) - friendship += 150 * var_34 / 100; - else - friendship += var_34; - if (var_34 > 0) - { - if (GetMonData(mon, MON_DATA_POKEBALL, NULL) == ITEM_LUXURY_BALL) - friendship++; - if (GetMonData(mon, MON_DATA_MET_LOCATION, NULL) == GetCurrentRegionMapSectionId()) - friendship++; - } - if (friendship < 0) - friendship = 0; - if (friendship > MAX_FRIENDSHIP) - friendship = MAX_FRIENDSHIP; - SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); - retVal = FALSE; + UPDATE_FRIENDSHIP_FROM_ITEM; } - var_3C++; + itemEffectParam++; break; } } - var_38++; - r10 >>= 1; + temp1++; + effectFlags >>= 1; } break; } @@ -5216,9 +5254,9 @@ u8 GetItemEffectParamOffset(u16 itemId, u8 effectByte, u8 effectBit) u8 offset; int i; u8 j; - u8 val; + u8 effectFlags; - offset = 6; + offset = ITEM_EFFECT_ARG_START; temp = gItemEffectTable[itemId - ITEM_POTION]; @@ -5232,7 +5270,7 @@ u8 GetItemEffectParamOffset(u16 itemId, u8 effectByte, u8 effectBit) itemEffect = temp; - for (i = 0; i < 6; i++) + for (i = 0; i < ITEM_EFFECT_ARG_START; i++) { switch (i) { @@ -5244,74 +5282,75 @@ u8 GetItemEffectParamOffset(u16 itemId, u8 effectByte, u8 effectBit) return 0; break; case 4: - val = itemEffect[4]; - if (val & ITEM4_PP_UP) - val &= ~(ITEM4_PP_UP); + effectFlags = itemEffect[4]; + if (effectFlags & ITEM4_PP_UP) + effectFlags &= ~(ITEM4_PP_UP); j = 0; - while (val) + while (effectFlags) { - if (val & 1) + if (effectFlags & 1) { switch (j) { - case 2: - if (val & 0x10) - val &= 0xEF; - case 0: - if (i == effectByte && (val & effectBit)) + case 2: // ITEM4_HEAL_HP + if (effectFlags & (ITEM4_REVIVE >> 2)) + effectFlags &= ~(ITEM4_REVIVE >> 2); + // fallthrough + case 0: // ITEM4_EV_HP + if (i == effectByte && (effectFlags & effectBit)) return offset; offset++; break; - case 1: - if (i == effectByte && (val & effectBit)) + case 1: // ITEM4_EV_ATK + if (i == effectByte && (effectFlags & effectBit)) return offset; offset++; break; - case 3: - if (i == effectByte && (val & effectBit)) + case 3: // ITEM4_HEAL_PP + if (i == effectByte && (effectFlags & effectBit)) return offset; offset++; break; - case 7: + case 7: // ITEM4_EVO_STONE if (i == effectByte) return 0; break; } } j++; - val >>= 1; + effectFlags >>= 1; if (i == effectByte) effectBit >>= 1; } break; case 5: - val = itemEffect[5]; + effectFlags = itemEffect[5]; j = 0; - while (val) + while (effectFlags) { - if (val & 1) + if (effectFlags & 1) { switch (j) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - if (i == effectByte && (val & effectBit)) + case 0: // ITEM5_EV_DEF + case 1: // ITEM5_EV_SPEED + case 2: // ITEM5_EV_SPDEF + case 3: // ITEM5_EV_SPATK + case 4: // ITEM5_PP_MAX + case 5: // ITEM5_FRIENDSHIP_LOW + case 6: // ITEM5_FRIENDSHIP_MID + if (i == effectByte && (effectFlags & effectBit)) return offset; offset++; break; - case 7: + case 7: // ITEM5_FRIENDSHIP_HIGH if (i == effectByte) return 0; break; } } j++; - val >>= 1; + effectFlags >>= 1; if (i == effectByte) effectBit >>= 1; } @@ -5387,7 +5426,7 @@ u8 GetNatureFromPersonality(u32 personality) return personality % NUM_NATURES; } -u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem) +u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem) { int i; u16 targetSpecies = 0; @@ -5405,12 +5444,13 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem) else holdEffect = ItemId_GetHoldEffect(heldItem); - if (holdEffect == HOLD_EFFECT_PREVENT_EVOLVE && type != 3) + // Prevent evolution with Everstone, unless we're just viewing the party menu with an evolution item + if (holdEffect == HOLD_EFFECT_PREVENT_EVOLVE && mode != EVO_MODE_ITEM_CHECK) return SPECIES_NONE; - switch (type) + switch (mode) { - case 0: + case EVO_MODE_NORMAL: level = GetMonData(mon, MON_DATA_LEVEL, 0); friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, 0); @@ -5470,7 +5510,7 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem) } } break; - case 1: + case EVO_MODE_TRADE: for (i = 0; i < EVOS_PER_MON; i++) { switch (gEvolutionTable[species][i].method) @@ -5489,8 +5529,8 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem) } } break; - case 2: - case 3: + case EVO_MODE_ITEM_USE: + case EVO_MODE_ITEM_CHECK: for (i = 0; i < EVOS_PER_MON; i++) { if (gEvolutionTable[species][i].method == EVO_ITEM |