#include "global.h" #include "pokemon.h" #include "main.h" #include "items.h" #include "string_util.h" #include "battle_message.h" #include "rtc.h" #include "item.h" #include "battle.h" #include "species.h" #include "link.h" #include "hold_effects.h" #include "rng.h" #include "trainer_classes.h" #include "trainer_ids.h" #include "songs.h" #include "sound.h" #include "m4a.h" #include "task.h" #include "sprite.h" #include "text.h" #include "abilities.h" #include "pokemon_animation.h" #include "pokedex.h" extern struct BattlePokemon gBattleMons[4]; extern struct BattleEnigmaBerry gEnigmaBerries[4]; extern u8 gActiveBank; extern u8 gBankInMenu; extern u8 gBankTarget; extern u8 gBankAttacker; extern u8 gStringBank; extern u16 gTrainerBattleOpponent_A; extern u32 gBattleTypeFlags; extern u8 gBattleMonForms[4]; extern u16 gBattlePartyID[4]; extern u8 gLastUsedAbility; extern u16 gPartnerTrainerId; extern u32 gHitMarker; extern const u16 gSpeciesToHoennPokedexNum[]; extern const u16 gSpeciesToNationalPokedexNum[]; extern const u16 gHoennToNationalOrder[]; extern const u16 gSpeciesIdToCryId[]; extern const struct SpindaSpot gSpindaSpotGraphics[]; extern const u8* const gStatNamesTable[]; extern const u8 gSpeciesNames[][11]; extern const u8 gUnknown_08329EC8[]; extern const u8 gUnknown_085CB38A[]; extern const u8 gUnknown_085CB3AA[]; extern const u8 gUnknown_085CA459[]; extern const u8 gUnknown_085CA424[]; extern const s8 gNatureStatTable[][5]; extern const s8 gUnknown_08329ECE[][3]; extern const u32 gBitTable[]; extern const u32 gTMHMLearnsets[][2]; extern const u8 BattleText_Wally[]; extern const u8 BattleText_PreventedSwitch[]; extern const struct CompressedSpritePalette gMonPaletteTable[]; extern const struct CompressedSpritePalette gMonShinyPaletteTable[]; extern const u16 gHMMoves[]; extern const s8 gPokeblockFlavorCompatibilityTable[]; extern const u8 gMonAnimationDelayTable[]; extern const u8 gMonFrontAnimIdsTable[]; extern bool8 InBattlePyramid(void); extern bool8 InBattlePike(void); extern bool8 sub_81D5C18(void); extern bool8 sub_806F104(void); extern bool32 IsNationalPokedexEnabled(void); extern u8 GetTrainerEncounterMusicIdInBattlePyramind(u16 trainerOpponentId); extern u8 sub_81D63C8(u16 trainerOpponentId); extern u8 sav1_map_get_name(void); extern u8 GetFrontierOpponentClass(u16 trainerId); extern u8 pokemon_order_func(u8 bankPartyId); extern void GetFrontierTrainerName(u8* dest, u16 trainerId); extern void sub_81C488C(u8); extern void sub_817F578(struct Sprite*, u8 frontAnimId); extern u8 GetSpeciesBackAnimId(u16 species); static void sub_806E6CC(u8 taskId); bool8 HealStatusConditions(struct Pokemon *mon, u32 battlePartyId, u32 healMask, u8 battleBank) { u32 status = GetMonData(mon, MON_DATA_STATUS, 0); if (status & healMask) { status &= ~healMask; SetMonData(mon, MON_DATA_STATUS, (u8 *)&status); if (gMain.inBattle && battleBank != 4) gBattleMons[battleBank].status1 &= ~healMask; return FALSE; } else { return TRUE; } } u8 GetItemEffectParamOffset(u16 itemId, u8 effectByte, u8 effectBit) { const u8 *temp; const u8 *itemEffect; u8 offset; int i; u8 j; u8 val; offset = 6; temp = gItemEffectTable[itemId - 13]; if (!temp && itemId != ITEM_ENIGMA_BERRY) return 0; if (itemId == ITEM_ENIGMA_BERRY) { temp = gEnigmaBerries[gActiveBank].itemEffect; } itemEffect = temp; for (i = 0; i < 6; i++) { switch (i) { case 0: case 1: case 2: case 3: if (i == effectByte) return 0; break; case 4: val = itemEffect[4]; if (val & 0x20) val &= 0xDF; j = 0; while (val) { if (val & 1) { switch (j) { case 2: if (val & 0x10) val &= 0xEF; case 0: if (i == effectByte && (val & effectBit)) return offset; offset++; break; case 1: if (i == effectByte && (val & effectBit)) return offset; offset++; break; case 3: if (i == effectByte && (val & effectBit)) return offset; offset++; break; case 7: if (i == effectByte) return 0; break; } } j++; val >>= 1; if (i == effectByte) effectBit >>= 1; } break; case 5: val = itemEffect[5]; j = 0; while (val) { if (val & 1) { switch (j) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: if (i == effectByte && (val & effectBit)) return offset; offset++; break; case 7: if (i == effectByte) return 0; break; } } j++; val >>= 1; if (i == effectByte) effectBit >>= 1; } break; } } return offset; } void sub_806CF24(s32 stat) { gBankTarget = gBankInMenu; StringCopy(gBattleTextBuff1, gStatNamesTable[gUnknown_08329EC8[stat]]); StringCopy(gBattleTextBuff2, gUnknown_085CB38A); StrCpyDecodeToDisplayedStringBattle(gUnknown_085CB3AA); } u8 *sub_806CF78(u16 itemId) { int i; const u8 *itemEffect; if (itemId == ITEM_ENIGMA_BERRY) { if (gMain.inBattle) itemEffect = gEnigmaBerries[gBankInMenu].itemEffect; else itemEffect = gSaveBlock1Ptr->enigmaBerry.itemEffect; } else { itemEffect = gItemEffectTable[itemId - 13]; } gStringBank = gBankInMenu; for (i = 0; i < 3; i++) { if (itemEffect[i] & 0xF) sub_806CF24(i * 2); if (itemEffect[i] & 0xF0) { if (i) { sub_806CF24(i * 2 + 1); } else { gBankAttacker = gBankInMenu; StrCpyDecodeToDisplayedStringBattle(gUnknown_085CA459); } } } if (itemEffect[3] & 0x80) { gBankAttacker = gBankInMenu; StrCpyDecodeToDisplayedStringBattle(gUnknown_085CA424); } return gDisplayedStringBattle; } u8 GetNature(struct Pokemon *mon) { return GetMonData(mon, MON_DATA_PERSONALITY, 0) % 25; } u8 GetNatureFromPersonality(u32 personality) { return personality % 25; } u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem) { int i; u16 targetSpecies = 0; u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); u16 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0); u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0); u8 level; u16 friendship; u8 beauty = GetMonData(mon, MON_DATA_BEAUTY, 0); u16 upperPersonality = personality >> 16; u8 holdEffect; if (heldItem == ITEM_ENIGMA_BERRY) holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; else holdEffect = ItemId_GetHoldEffect(heldItem); if (holdEffect == 38 && type != 3) return 0; switch (type) { case 0: level = GetMonData(mon, MON_DATA_LEVEL, 0); friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, 0); for (i = 0; i < 5; i++) { switch (gEvolutionTable[species].evolutions[i].method) { case EVO_FRIENDSHIP: if (friendship >= 220) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_FRIENDSHIP_DAY: RtcCalcLocalTime(); if (gLocalTime.hours >= 12 && gLocalTime.hours < 24 && friendship >= 220) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_FRIENDSHIP_NIGHT: RtcCalcLocalTime(); if (gLocalTime.hours >= 0 && gLocalTime.hours < 12 && friendship >= 220) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL: if (gEvolutionTable[species].evolutions[i].param <= level) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL_ATK_GT_DEF: if (gEvolutionTable[species].evolutions[i].param <= level) if (GetMonData(mon, MON_DATA_ATK, 0) > GetMonData(mon, MON_DATA_DEF, 0)) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL_ATK_EQ_DEF: if (gEvolutionTable[species].evolutions[i].param <= level) if (GetMonData(mon, MON_DATA_ATK, 0) == GetMonData(mon, MON_DATA_DEF, 0)) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL_ATK_LT_DEF: if (gEvolutionTable[species].evolutions[i].param <= level) if (GetMonData(mon, MON_DATA_ATK, 0) < GetMonData(mon, MON_DATA_DEF, 0)) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL_SILCOON: if (gEvolutionTable[species].evolutions[i].param <= level && (upperPersonality % 10) <= 4) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL_CASCOON: if (gEvolutionTable[species].evolutions[i].param <= level && (upperPersonality % 10) > 4) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_LEVEL_NINJASK: if (gEvolutionTable[species].evolutions[i].param <= level) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_BEAUTY: if (gEvolutionTable[species].evolutions[i].param <= beauty) targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; } } break; case 1: for (i = 0; i < 5; i++) { switch (gEvolutionTable[species].evolutions[i].method) { case EVO_TRADE: targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; case EVO_TRADE_ITEM: if (gEvolutionTable[species].evolutions[i].param == heldItem) { heldItem = 0; SetMonData(mon, MON_DATA_HELD_ITEM, (u8 *)&heldItem); targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; } break; } } break; case 2: case 3: for (i = 0; i < 5; i++) { if (gEvolutionTable[species].evolutions[i].method == EVO_ITEM && gEvolutionTable[species].evolutions[i].param == evolutionItem) { targetSpecies = gEvolutionTable[species].evolutions[i].targetSpecies; break; } } break; } return targetSpecies; } u16 HoennPokedexNumToSpecies(u16 hoennNum) { u16 species; if (!hoennNum) return 0; species = 0; while (species < 411 && gSpeciesToHoennPokedexNum[species] != hoennNum) species++; if (species == 411) return 0; return species + 1; } u16 NationalPokedexNumToSpecies(u16 nationalNum) { u16 species; if (!nationalNum) return 0; species = 0; while (species < 411 && gSpeciesToNationalPokedexNum[species] != nationalNum) species++; if (species == 411) return 0; return species + 1; } u16 NationalToHoennOrder(u16 nationalNum) { u16 hoennNum; if (!nationalNum) return 0; hoennNum = 0; while (hoennNum < 411 && gHoennToNationalOrder[hoennNum] != nationalNum) hoennNum++; if (hoennNum == 411) return 0; return hoennNum + 1; } u16 SpeciesToNationalPokedexNum(u16 species) { if (!species) return 0; return gSpeciesToNationalPokedexNum[species - 1]; } u16 SpeciesToHoennPokedexNum(u16 species) { if (!species) return 0; return gSpeciesToHoennPokedexNum[species - 1]; } u16 HoennToNationalOrder(u16 hoennNum) { if (!hoennNum) return 0; return gHoennToNationalOrder[hoennNum - 1]; } u16 SpeciesToCryId(u16 species) { if (species <= 250) return species; if (species < 276) return 200; return gSpeciesIdToCryId[species - 276]; } void sub_806D544(u16 species, u32 personality, u8 *dest) { if (species == SPECIES_SPINDA && dest != gBattleSpritesGfx->sprites[0] && dest != gBattleSpritesGfx->sprites[2]) { int i; for (i = 0; i < 4; i++) { int j; u8 x = gSpindaSpotGraphics[i].x + ((personality & 0x0F) - 8); u8 y = gSpindaSpotGraphics[i].y + (((personality & 0xF0) >> 4) - 8); for (j = 0; j < 16; j++) { int k; s32 row = gSpindaSpotGraphics[i].image[j]; for (k = x; k < x + 16; k++) { u8 *val = dest + ((k / 8) * 32) + ((k % 8) / 2) + ((y >> 3) << 8) + ((y & 7) << 2); if (row & 1) { if (k & 1) { if ((u8)((*val & 0xF0) - 0x10) <= 0x20) *val += 0x40; } else { if ((u8)((*val & 0xF) - 0x01) <= 0x02) *val += 0x04; } } row >>= 1; } y++; } personality >>= 8; } } } void DrawSpindaSpots(u16 species, u32 personality, u8 *dest, u8 a4) { if (species == SPECIES_SPINDA && a4) { int i; for (i = 0; i < 4; i++) { int j; u8 x = gSpindaSpotGraphics[i].x + ((personality & 0x0F) - 8); u8 y = gSpindaSpotGraphics[i].y + (((personality & 0xF0) >> 4) - 8); for (j = 0; j < 16; j++) { int k; s32 row = gSpindaSpotGraphics[i].image[j]; for (k = x; k < x + 16; k++) { u8 *val = dest + ((k / 8) * 32) + ((k % 8) / 2) + ((y >> 3) << 8) + ((y & 7) << 2); if (row & 1) { if (k & 1) { if ((u8)((*val & 0xF0) - 0x10) <= 0x20) *val += 0x40; } else { if ((u8)((*val & 0xF) - 0x01) <= 0x02) *val += 0x04; } } row >>= 1; } y++; } personality >>= 8; } } } void EvolutionRenameMon(struct Pokemon *mon, u16 oldSpecies, u16 newSpecies) { u8 language; GetMonData(mon, MON_DATA_NICKNAME, gStringVar1); language = GetMonData(mon, MON_DATA_LANGUAGE, &language); if (language == GAME_LANGUAGE && !StringCompare(gSpeciesNames[oldSpecies], gStringVar1)) SetMonData(mon, MON_DATA_NICKNAME, gSpeciesNames[newSpecies]); } bool8 sub_806D7EC(void) { bool8 retVal = FALSE; switch (gLinkPlayers[GetMultiplayerId()].lp_field_18) { case 0: case 3: retVal = FALSE; break; case 1: case 2: retVal = TRUE; break; } return retVal; } bool8 sub_806D82C(u8 id) { bool8 retVal = FALSE; switch (gLinkPlayers[id].lp_field_18) { case 0: case 3: retVal = FALSE; break; case 1: case 2: retVal = TRUE; break; } return retVal; } s32 sub_806D864(u16 a1) { s32 id; for (id = 0; id < MAX_LINK_PLAYERS; id++) if (gLinkPlayers[id].lp_field_18 == a1) break; return id; } u8 GetTrainerEncounterMusicId(u16 trainerOpponentId) { if (InBattlePyramid()) return GetTrainerEncounterMusicIdInBattlePyramind(trainerOpponentId); if (sub_81D5C18()) return sub_81D63C8(trainerOpponentId); return TRAINER_ENCOUNTER_MUSIC(trainerOpponentId); } u16 nature_stat_mod(u8 nature, u16 n, u8 statIndex) { if (statIndex < 1 || statIndex > 5) { // should just be "return n", but it wouldn't match without this u16 retVal = n; retVal++; retVal--; return retVal; } switch (gNatureStatTable[nature][statIndex - 1]) { case 1: return (u16)(n * 110) / 100; case -1: return (u16)(n * 90) / 100; } return n; } void AdjustFriendship(struct Pokemon *mon, u8 event) { u16 species, heldItem; u8 holdEffect; if (sub_806F104()) return; species = GetMonData(mon, MON_DATA_SPECIES2, 0); heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0); if (heldItem == ITEM_ENIGMA_BERRY) { if (gMain.inBattle) holdEffect = gEnigmaBerries[0].holdEffect; else holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; } else { holdEffect = ItemId_GetHoldEffect(heldItem); } if (species && species != SPECIES_EGG) { u8 friendshipLevel = 0; s16 friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, 0); if (friendship > 99) friendshipLevel++; if (friendship > 199) friendshipLevel++; if ((event != 5 || !(Random() & 1)) && (event != 3 || ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) && (gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_ELITE_FOUR || gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_LEADER || gTrainers[gTrainerBattleOpponent_A].trainerClass == CLASS_CHAMPION)))) { s8 mod = gUnknown_08329ECE[event][friendshipLevel]; if (mod > 0 && holdEffect == HOLD_EFFECT_HAPPINESS_UP) mod = (150 * mod) / 100; friendship += mod; if (mod > 0) { if (GetMonData(mon, MON_DATA_POKEBALL, 0) == ITEM_LUXURY_BALL) friendship++; if (GetMonData(mon, MON_DATA_MET_LOCATION, 0) == sav1_map_get_name()) friendship++; } if (friendship < 0) friendship = 0; if (friendship > 255) friendship = 255; SetMonData(mon, MON_DATA_FRIENDSHIP, &friendship); } } } void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) { u8 evs[NUM_STATS]; u16 evIncrease = 0; u16 totalEVs = 0; u16 heldItem; u8 holdEffect; int i; for (i = 0; i < NUM_STATS; i++) { evs[i] = GetMonData(mon, MON_DATA_HP_EV + i, 0); totalEVs += evs[i]; } for (i = 0; i < NUM_STATS; i++) { u8 hasHadPokerus; int multiplier; if (totalEVs >= MAX_TOTAL_EVS) break; hasHadPokerus = CheckPartyHasHadPokerus(mon, 0); if (hasHadPokerus) multiplier = 2; else multiplier = 1; switch (i) { case 0: evIncrease = gBaseStats[defeatedSpecies].evYield_HP * multiplier; break; case 1: evIncrease = gBaseStats[defeatedSpecies].evYield_Attack * multiplier; break; case 2: evIncrease = gBaseStats[defeatedSpecies].evYield_Defense * multiplier; break; case 3: evIncrease = gBaseStats[defeatedSpecies].evYield_Speed * multiplier; break; case 4: evIncrease = gBaseStats[defeatedSpecies].evYield_SpAttack * multiplier; break; case 5: evIncrease = gBaseStats[defeatedSpecies].evYield_SpDefense * multiplier; break; } heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0); if (heldItem == ITEM_ENIGMA_BERRY) { if (gMain.inBattle) holdEffect = gEnigmaBerries[0].holdEffect; else holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect; } else { holdEffect = ItemId_GetHoldEffect(heldItem); } if (holdEffect == HOLD_EFFECT_MACHO_BRACE) evIncrease *= 2; if (totalEVs + (s16)evIncrease > MAX_TOTAL_EVS) evIncrease = ((s16)evIncrease + MAX_TOTAL_EVS) - (totalEVs + evIncrease); if (evs[i] + (s16)evIncrease > 255) { int val1 = (s16)evIncrease + 255; int val2 = evs[i] + evIncrease; evIncrease = val1 - val2; } evs[i] += evIncrease; totalEVs += evIncrease; SetMonData(mon, MON_DATA_HP_EV + i, &evs[i]); } } u16 GetMonEVCount(struct Pokemon *mon) { int i; u16 count = 0; for (i = 0; i < NUM_STATS; i++) count += GetMonData(mon, MON_DATA_HP_EV + i, 0); return count; } void RandomlyGivePartyPokerus(struct Pokemon *party) { u16 rnd = Random(); if (rnd == 0x4000 || rnd == 0x8000 || rnd == 0xC000) { struct Pokemon *mon; do { do { rnd = Random() % PARTY_SIZE; mon = &party[rnd]; } while (!GetMonData(mon, MON_DATA_SPECIES, 0)); } while (GetMonData(mon, MON_DATA_IS_EGG, 0)); if (!(CheckPartyHasHadPokerus(party, gBitTable[rnd]))) { u8 rnd2; do { rnd2 = Random(); } while ((rnd2 & 0x7) == 0); if (rnd2 & 0xF0) rnd2 &= 0x7; rnd2 |= (rnd2 << 4); rnd2 &= 0xF3; rnd2++; SetMonData(&party[rnd], MON_DATA_POKERUS, &rnd2); } } } u8 CheckPartyPokerus(struct Pokemon *party, u8 selection) { u8 retVal; int partyIndex = 0; unsigned curBit = 1; retVal = 0; if (selection) { do { if ((selection & 1) && (GetMonData(&party[partyIndex], MON_DATA_POKERUS, 0) & 0xF)) retVal |= curBit; partyIndex++; curBit <<= 1; selection >>= 1; } while (selection); } else if (GetMonData(&party[0], MON_DATA_POKERUS, 0) & 0xF) { retVal = 1; } return retVal; } u8 CheckPartyHasHadPokerus(struct Pokemon *party, u8 selection) { u8 retVal; int partyIndex = 0; unsigned curBit = 1; retVal = 0; if (selection) { do { if ((selection & 1) && GetMonData(&party[partyIndex], MON_DATA_POKERUS, 0)) retVal |= curBit; partyIndex++; curBit <<= 1; selection >>= 1; } while (selection); } else if (GetMonData(&party[0], MON_DATA_POKERUS, 0)) { retVal = 1; } return retVal; } void UpdatePartyPokerusTime(u16 days) { int i; for (i = 0; i < PARTY_SIZE; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, 0)) { u8 pokerus = GetMonData(&gPlayerParty[i], MON_DATA_POKERUS, 0); if (pokerus & 0xF) { if ((pokerus & 0xF) < days || days > 4) pokerus &= 0xF0; else pokerus -= days; if (pokerus == 0) pokerus = 0x10; SetMonData(&gPlayerParty[i], MON_DATA_POKERUS, &pokerus); } } } } void PartySpreadPokerus(struct Pokemon *party) { if ((Random() % 3) == 0) { int i; for (i = 0; i < PARTY_SIZE; i++) { if (GetMonData(&party[i], MON_DATA_SPECIES, 0)) { u8 pokerus = GetMonData(&party[i], MON_DATA_POKERUS, 0); u8 curPokerus = pokerus; if (pokerus) { if (pokerus & 0xF) { // spread to adjacent party members if (i != 0 && !(GetMonData(&party[i - 1], MON_DATA_POKERUS, 0) & 0xF0)) SetMonData(&party[i - 1], MON_DATA_POKERUS, &curPokerus); if (i != (PARTY_SIZE - 1) && !(GetMonData(&party[i + 1], MON_DATA_POKERUS, 0) & 0xF0)) { SetMonData(&party[i + 1], MON_DATA_POKERUS, &curPokerus); i++; } } } } } } } bool8 TryIncrementMonLevel(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); u8 nextLevel = GetMonData(mon, MON_DATA_LEVEL, 0) + 1; u32 expPoints = GetMonData(mon, MON_DATA_EXP, 0); if (expPoints > gExperienceTables[gBaseStats[species].growthRate][MAX_MON_LEVEL]) { expPoints = gExperienceTables[gBaseStats[species].growthRate][MAX_MON_LEVEL]; SetMonData(mon, MON_DATA_EXP, &expPoints); } if (nextLevel > MAX_MON_LEVEL || expPoints < gExperienceTables[gBaseStats[species].growthRate][nextLevel]) { return FALSE; } else { SetMonData(mon, MON_DATA_LEVEL, &nextLevel); return TRUE; } } u32 CanMonLearnTMHM(struct Pokemon *mon, u8 tm) { u16 species = GetMonData(mon, MON_DATA_SPECIES2, 0); if (species == SPECIES_EGG) { return 0; } else if (tm < 32) { u32 mask = 1 << tm; return gTMHMLearnsets[species][0] & mask; } else { u32 mask = 1 << (tm - 32); return gTMHMLearnsets[species][1] & mask; } } u32 CanSpeciesLearnTMHM(u16 species, u8 tm) { if (species == SPECIES_EGG) { return 0; } else if (tm < 32) { u32 mask = 1 << tm; return gTMHMLearnsets[species][0] & mask; } else { u32 mask = 1 << (tm - 32); return gTMHMLearnsets[species][1] & mask; } } u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves) { u16 learnedMoves[4]; u8 numMoves = 0; u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); u8 level = GetMonData(mon, MON_DATA_LEVEL, 0); int i, j, k; for (i = 0; i < 4; i++) learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); for (i = 0; i < 20; i++) { u16 moveLevel; if (gLevelUpLearnsets[species][i] == 0xFFFF) break; moveLevel = gLevelUpLearnsets[species][i] & 0xFE00; if (moveLevel <= (level << 9)) { for (j = 0; j < 4 && learnedMoves[j] != (gLevelUpLearnsets[species][i] & 0x1FF); j++) ; if (j == 4) { for (k = 0; k < numMoves && moves[k] != (gLevelUpLearnsets[species][i] & 0x1FF); k++) ; if (k == numMoves) moves[numMoves++] = gLevelUpLearnsets[species][i] & 0x1FF; } } } return numMoves; } u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves) { u8 numMoves = 0; int i; for (i = 0; i < 20 && gLevelUpLearnsets[species][i] != 0xFFFF; i++) moves[numMoves++] = gLevelUpLearnsets[species][i] & 0x1FF; return numMoves; } u8 GetNumberOfRelearnableMoves(struct Pokemon *mon) { u16 learnedMoves[4]; u16 moves[20]; u8 numMoves = 0; u16 species = GetMonData(mon, MON_DATA_SPECIES2, 0); u8 level = GetMonData(mon, MON_DATA_LEVEL, 0); int i, j, k; if (species == SPECIES_EGG) return 0; for (i = 0; i < 4; i++) learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); for (i = 0; i < 20; i++) { u16 moveLevel; if (gLevelUpLearnsets[species][i] == 0xFFFF) break; moveLevel = gLevelUpLearnsets[species][i] & 0xFE00; if (moveLevel <= (level << 9)) { for (j = 0; j < 4 && learnedMoves[j] != (gLevelUpLearnsets[species][i] & 0x1FF); j++) ; if (j == 4) { for (k = 0; k < numMoves && moves[k] != (gLevelUpLearnsets[species][i] & 0x1FF); k++) ; if (k == numMoves) moves[numMoves++] = gLevelUpLearnsets[species][i] & 0x1FF; } } } return numMoves; } u16 SpeciesToPokedexNum(u16 species) { if (IsNationalPokedexEnabled()) { return SpeciesToNationalPokedexNum(species); } else { species = SpeciesToHoennPokedexNum(species); if (species <= 202) return species; return 0xFFFF; } } bool32 sub_806E3F8(u16 species) { if (SpeciesToHoennPokedexNum(species) > 202) return FALSE; else return TRUE; } void ClearBattleMonForms(void) { int i; for (i = 0; i < 4; i++) gBattleMonForms[i] = 0; } u16 GetBattleBGM(void) { if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON) return 0x1E0; if (gBattleTypeFlags & BATTLE_TYPE_REGI) return 0x1DF; if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) return 0x1DC; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { u8 trainerClass; if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) trainerClass = GetFrontierOpponentClass(gTrainerBattleOpponent_A); else if (gBattleTypeFlags & BATTLE_TYPE_x4000000) trainerClass = CLASS_EXPERT; else trainerClass = gTrainers[gTrainerBattleOpponent_A].trainerClass; switch (trainerClass) { case CLASS_AQUA_LEADER: case CLASS_MAGMA_LEADER: return 0x1E3; case CLASS_TEAM_AQUA: case CLASS_TEAM_MAGMA: case CLASS_AQUA_ADMIN: case CLASS_MAGMA_ADMIN: return 0x1DB; case CLASS_LEADER: return 0x1DD; case CLASS_CHAMPION: return 0x1DE; case CLASS_PKMN_TRAINER_RIVAL: if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) return 0x1E1; if (!StringCompare(gTrainers[gTrainerBattleOpponent_A].trainerName, BattleText_Wally)) return 0x1DC; return 0x1E1; case CLASS_ELITE_FOUR: return 0x1E2; case CLASS_SALON_MAIDEN: case CLASS_DOME_ACE: case CLASS_PALACE_MAVEN: case CLASS_ARENA_TYCOON: case CLASS_FACTORY_HEAD: case CLASS_PIKE_QUEEN: case CLASS_PYRAMID_KING: return 0x1D7; default: return 0x1DC; } } return 0x1DA; } void PlayBattleBGM(void) { ResetMapMusic(); m4aMPlayAllStop(); PlayBGM(GetBattleBGM()); } void PlayMapChosenOrBattleBGM(u16 songId) { ResetMapMusic(); m4aMPlayAllStop(); if (songId) PlayNewMapMusic(songId); else PlayNewMapMusic(GetBattleBGM()); } void sub_806E694(u16 songId) { u8 taskId; ResetMapMusic(); m4aMPlayAllStop(); taskId = CreateTask(sub_806E6CC, 0); gTasks[taskId].data[0] = songId; } static void sub_806E6CC(u8 taskId) { if (gTasks[taskId].data[0]) PlayNewMapMusic(gTasks[taskId].data[0]); else PlayNewMapMusic(GetBattleBGM()); DestroyTask(taskId); } const u8 *pokemon_get_pal(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES2, 0); u32 otId = GetMonData(mon, MON_DATA_OT_ID, 0); u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0); return species_and_otid_get_pal(species, otId, personality); } // Extracts the upper 16 bits of a 32-bit number #define HIHALF(n) (((n) & 0xFFFF0000) >> 16) // Extracts the lower 16 bits of a 32-bit number #define LOHALF(n) ((n) & 0xFFFF) const u8 *species_and_otid_get_pal(u16 species, u32 otId, u32 personality) { u32 shinyValue; if (species > SPECIES_EGG) return gMonPaletteTable[0].data; shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality); if (shinyValue < 8) return gMonShinyPaletteTable[species].data; else return gMonPaletteTable[species].data; } const struct CompressedSpritePalette *sub_806E794(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES2, 0); u32 otId = GetMonData(mon, MON_DATA_OT_ID, 0); u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0); return sub_806E7CC(species, otId, personality); } const struct CompressedSpritePalette *sub_806E7CC(u16 species, u32 otId , u32 personality) { u32 shinyValue; shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality); if (shinyValue < 8) return &gMonShinyPaletteTable[species]; else return &gMonPaletteTable[species]; } bool32 IsHMMove2(u16 move) { int i = 0; while (gHMMoves[i] != 0xFFFF) { if (gHMMoves[i++] == move) return TRUE; } return FALSE; } bool8 IsPokeSpriteNotFlipped(u16 species) { return gBaseStats[species].noFlip; } s8 GetMonFlavourRelation(struct Pokemon *mon, u8 a2) { u8 nature = GetNature(mon); return gPokeblockFlavorCompatibilityTable[nature * 5 + a2]; } s8 GetFlavourRelationByPersonality(u32 personality, u8 a2) { u8 nature = GetNatureFromPersonality(personality); return gPokeblockFlavorCompatibilityTable[nature * 5 + a2]; } bool8 IsTradedMon(struct Pokemon *mon) { u8 otName[8]; u32 otId; GetMonData(mon, MON_DATA_OT_NAME, otName); otId = GetMonData(mon, MON_DATA_OT_ID, 0); return IsOtherTrainer(otId, otName); } bool8 IsOtherTrainer(u32 otId, u8 *otName) { if (otId == (gSaveBlock2Ptr->playerTrainerId[0] | (gSaveBlock2Ptr->playerTrainerId[1] << 8) | (gSaveBlock2Ptr->playerTrainerId[2] << 16) | (gSaveBlock2Ptr->playerTrainerId[3] << 24))) { int i; for (i = 0; otName[i] != EOS; i++) if (otName[i] != gSaveBlock2Ptr->playerName[i]) return TRUE; return FALSE; } return TRUE; } void MonRestorePP(struct Pokemon *mon) { BoxMonRestorePP(&mon->box); } void BoxMonRestorePP(struct BoxPokemon *boxMon) { int i; for (i = 0; i < 4; i++) { if (GetBoxMonData(boxMon, MON_DATA_MOVE1 + i, 0)) { u16 move = GetBoxMonData(boxMon, MON_DATA_MOVE1 + i, 0); u16 bonus = GetBoxMonData(boxMon, MON_DATA_PP_BONUSES, 0); u8 pp = CalculatePPWithBonus(move, bonus, i); SetBoxMonData(boxMon, MON_DATA_PP1 + i, &pp); } } } void sub_806E994(void) { gLastUsedAbility = gBattleStruct->field_B0; gBattleTextBuff1[0] = 0xFD; gBattleTextBuff1[1] = 4; gBattleTextBuff1[2] = gBattleStruct->field_49; gBattleTextBuff1[4] = EOS; if (!GetBankSide(gBattleStruct->field_49)) gBattleTextBuff1[3] = pokemon_order_func(gBattlePartyID[gBattleStruct->field_49]); else gBattleTextBuff1[3] = gBattlePartyID[gBattleStruct->field_49]; gBattleTextBuff2[0] = 0xFD; gBattleTextBuff2[1] = 4; gBattleTextBuff2[2] = gBankInMenu; gBattleTextBuff2[3] = pokemon_order_func(gBattlePartyID[gBankInMenu]); gBattleTextBuff2[4] = EOS; StrCpyDecodeBattle(BattleText_PreventedSwitch, gStringVar4); } struct PokeItem { u16 species; u16 item; }; extern const struct PokeItem gAlteringCaveWildMonHeldItems[9]; static s32 GetWildMonTableIdInAlteringCave(u16 species) { s32 i; for (i = 0; i < 9; i++) if (gAlteringCaveWildMonHeldItems[i].species == species) return i; return 0; } void SetWildMonHeldItem(void) { if (!(gBattleTypeFlags & (BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_TRAINER | BATTLE_TYPE_PYRAMID | BATTLE_TYPE_x100000))) { u16 rnd = Random() % 100; u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, 0); u16 var1 = 45; u16 var2 = 95; if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_BIT3, 0) && GetMonAbility(&gPlayerParty[0]) == ABILITY_COMPOUND_EYES) { var1 = 20; var2 = 80; } if (gMapHeader.mapDataId == 0x1A4) { s32 alteringCaveId = GetWildMonTableIdInAlteringCave(species); if (alteringCaveId != 0) { if (rnd < var2) return; SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &gAlteringCaveWildMonHeldItems[alteringCaveId].item); } else { if (rnd < var1) return; if (rnd < var2) SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &gBaseStats[species].item1); else SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &gBaseStats[species].item2); } } else { if (gBaseStats[species].item1 == gBaseStats[species].item2 && gBaseStats[species].item1 != 0) { SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &gBaseStats[species].item1); } else { if (rnd < var1) return; if (rnd < var2) SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &gBaseStats[species].item1); else SetMonData(&gEnemyParty[0], MON_DATA_HELD_ITEM, &gBaseStats[species].item2); } } } } bool8 IsMonShiny(struct Pokemon *mon) { u32 otId = GetMonData(mon, MON_DATA_OT_ID, 0); u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0); return IsShinyOtIdPersonality(otId, personality); } bool8 IsShinyOtIdPersonality(u32 otId, u32 personality) { bool8 retVal = FALSE; u32 shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality); if (shinyValue < 8) retVal = TRUE; return retVal; } const u8* GetTrainerPartnerName(void) { if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { if (gPartnerTrainerId == STEVEN_PARTNER_ID) return gTrainers[TRAINER_ID_STEVEN].trainerName; else { GetFrontierTrainerName(gStringVar1, gPartnerTrainerId); return gStringVar1; } } else { u8 id = GetMultiplayerId(); return gLinkPlayers[sub_806D864(gLinkPlayers[id].lp_field_18 ^ 2)].name; } } #define READ_PTR_FROM_TASK(taskId, dataId) \ (void*)( \ ((u16)(gTasks[taskId].data[dataId]) | \ ((u16)(gTasks[taskId].data[dataId + 1]) << 0x10))) #define STORE_PTR_IN_TASK(ptr, taskId, dataId) \ { \ gTasks[taskId].data[dataId] = (u32)(ptr); \ gTasks[taskId].data[dataId + 1] = (u32)(ptr) >> 0x10; \ } static void Task_AnimateAfterDelay(u8 taskId) { if (--gTasks[taskId].data[3] == 0) { LaunchAnimationTaskForFrontSprite(READ_PTR_FROM_TASK(taskId, 0), gTasks[taskId].data[2]); DestroyTask(taskId); } } static void Task_PokemonSummaryAnimateAfterDelay(u8 taskId) { if (--gTasks[taskId].data[3] == 0) { sub_817F578(READ_PTR_FROM_TASK(taskId, 0), gTasks[taskId].data[2]); sub_81C488C(0xFF); DestroyTask(taskId); } } void DoMonFrontSpriteAnimation(struct Sprite* sprite, u16 species, bool8 noCry, u8 arg3); void BattleAnimateFrontSprite(struct Sprite* sprite, u16 species, bool8 noCry, u8 arg3) { if (gHitMarker & HITMARKER_NO_ANIMATIONS && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) DoMonFrontSpriteAnimation(sprite, species, noCry, arg3 | 0x80); else DoMonFrontSpriteAnimation(sprite, species, noCry, arg3); } bool8 HasTwoFramesAnimation(u16 species); extern void SpriteCallbackDummy_2(struct Sprite*); extern void sub_817F60C(struct Sprite*); void DoMonFrontSpriteAnimation(struct Sprite* sprite, u16 species, bool8 noCry, u8 arg3) { s8 pan; switch (arg3 & 0x7F) { case 0: pan = -25; break; case 1: pan = 25; break; default: pan = 0; break; } if (arg3 & 0x80) { if (!noCry) PlayCry1(species, pan); sprite->callback = SpriteCallbackDummy; } else { if (!noCry) { PlayCry1(species, pan); if (HasTwoFramesAnimation(species)) StartSpriteAnim(sprite, 1); } if (gMonAnimationDelayTable[species - 1] != 0) { u8 taskId = CreateTask(Task_AnimateAfterDelay, 0); STORE_PTR_IN_TASK(sprite, taskId, 0); gTasks[taskId].data[2] = gMonFrontAnimIdsTable[species - 1]; gTasks[taskId].data[3] = gMonAnimationDelayTable[species - 1]; } else { LaunchAnimationTaskForFrontSprite(sprite, gMonFrontAnimIdsTable[species - 1]); } sprite->callback = SpriteCallbackDummy_2; } } void PokemonSummaryDoMonAnimation(struct Sprite* sprite, u16 species, bool8 oneFrame) { if (!oneFrame && HasTwoFramesAnimation(species)) StartSpriteAnim(sprite, 1); if (gMonAnimationDelayTable[species - 1] != 0) { u8 taskId = CreateTask(Task_PokemonSummaryAnimateAfterDelay, 0); STORE_PTR_IN_TASK(sprite, taskId, 0); gTasks[taskId].data[2] = gMonFrontAnimIdsTable[species - 1]; gTasks[taskId].data[3] = gMonAnimationDelayTable[species - 1]; sub_81C488C(taskId); sub_817F60C(sprite); } else { sub_817F578(sprite, gMonFrontAnimIdsTable[species - 1]); } } void sub_806EE98(void) { u8 delayTaskId = FindTaskIdByFunc(Task_PokemonSummaryAnimateAfterDelay); if (delayTaskId != 0xFF) DestroyTask(delayTaskId); } void BattleAnimateBackSprite(struct Sprite* sprite, u16 species) { if (gHitMarker & HITMARKER_NO_ANIMATIONS && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))) { sprite->callback = SpriteCallbackDummy; } else { LaunchAnimationTaskForBackSprite(sprite, GetSpeciesBackAnimId(species)); sprite->callback = SpriteCallbackDummy_2; } } u8 sub_806EF08(u8 arg0) { s32 i; s32 var = 0; u8 multiplayerId = GetMultiplayerId(); switch (gLinkPlayers[multiplayerId].lp_field_18) { case 0: case 2: var = (arg0 != 0) ? 1 : 3; break; case 1: case 3: var = (arg0 != 0) ? 2 : 0; break; } for (i = 0; i < 4; i++) { if (gLinkPlayers[i].lp_field_18 == (s16)(var)) break; } return i; } u8 sub_806EF84(u8 arg0, u8 arg1) { s32 i; s32 var = 0; switch (gLinkPlayers[arg1].lp_field_18) { case 0: case 2: var = (arg0 != 0) ? 1 : 3; break; case 1: case 3: var = (arg0 != 0) ? 2 : 0; break; } for (i = 0; i < 4; i++) { if (gLinkPlayers[i].lp_field_18 == (s16)(var)) break; } return i; } extern const u8 gUnknown_0831F578[]; u16 sub_806EFF0(u16 arg0) { return gUnknown_0831F578[arg0]; } u16 sub_806F000(u8 playerGender) { if (playerGender) return sub_806EFF0(0x3F); else return sub_806EFF0(0x3C); } extern const u8 gTrainerClassNames[][13]; void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality) { u8 getFlagCaseId = (caseId == FLAG_SET_SEEN) ? FLAG_GET_SEEN : FLAG_GET_CAUGHT; if (!GetSetPokedexFlag(nationalNum, getFlagCaseId)) // don't set if it's already set { GetSetPokedexFlag(nationalNum, caseId); if (NationalPokedexNumToSpecies(nationalNum) == SPECIES_UNOWN) gSaveBlock2Ptr->pokedex.unownPersonality = personality; if (NationalPokedexNumToSpecies(nationalNum) == SPECIES_SPINDA) gSaveBlock2Ptr->pokedex.spindaPersonality = personality; } } const u8* GetTrainerClassNameFromId(u16 trainerId) { if (trainerId > NO_OF_TRAINERS) trainerId = 0; return gTrainerClassNames[gTrainers[trainerId].trainerClass]; } const u8* GetTrainerNameFromId(u16 trainerId) { if (trainerId > NO_OF_TRAINERS) trainerId = 0; return gTrainers[trainerId].trainerName; } bool8 HasTwoFramesAnimation(u16 species) { return (species != SPECIES_CASTFORM && species != SPECIES_DEOXYS && species != SPECIES_SPINDA && species != SPECIES_UNOWN); } bool8 sub_806F104(void) { if (gMain.inBattle && gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) return TRUE; if (!gMain.inBattle && (InBattlePike() || InBattlePyramid())) return TRUE; return FALSE; } /* extern const struct SpriteTemplate gUnknown_08329D98[]; struct Unknown_806F160_Struct { u8 field_0; u8 field_1; u8 field_2; u8 field_3; u8 field_4; u8 field_5; u8 field_6; u8 field_7; u8 field_8; u8 field_9; u8 field_A; u8 field_B; struct SpriteTemplate* templates; }; void sub_806F160(struct Unknown_806F160_Struct* structPtr) { u16 i, j; for (i = 0; i < structPtr->field_0; i++) { structPtr->templates[i] = gUnknown_08329D98[i]; for (j = 0; j < structPtr->field_1) { // no clue what the pointer in the struct point to :/ } } } */