mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 19:54:21 +01:00
1752 lines
46 KiB
C
1752 lines
46 KiB
C
#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 gText_StatRose[];
|
|
extern const u8 gText_PkmnsStatChanged2[];
|
|
extern const u8 gText_PkmnGettingPumped[];
|
|
extern const u8 gText_PkmnShroudedInMist[];
|
|
extern const s8 gNatureStatTable[][5];
|
|
extern const s8 gUnknown_08329ECE[][3];
|
|
extern const u32 gBitTable[];
|
|
extern const u32 gTMHMLearnsets[][2];
|
|
extern const u8 gText_BattleWallyName[];
|
|
extern const u8 gText_PkmnsXPreventsSwitching[];
|
|
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, gText_StatRose);
|
|
BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnsStatChanged2);
|
|
}
|
|
|
|
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;
|
|
BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnGettingPumped);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (itemEffect[3] & 0x80)
|
|
{
|
|
gBankAttacker = gBankInMenu;
|
|
BattleStringExpandPlaceholdersToDisplayedString(gText_PkmnShroudedInMist);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool16 sub_806D82C(u8 id)
|
|
{
|
|
bool16 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, gText_BattleWallyName))
|
|
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] = B_BUFF_PLACEHOLDER_BEGIN;
|
|
gBattleTextBuff1[1] = B_BUFF_MON_NICK_WITH_PREFIX;
|
|
gBattleTextBuff1[2] = gBattleStruct->field_49;
|
|
gBattleTextBuff1[4] = B_BUFF_EOS;
|
|
|
|
if (!GetBankSide(gBattleStruct->field_49))
|
|
gBattleTextBuff1[3] = pokemon_order_func(gBattlePartyID[gBattleStruct->field_49]);
|
|
else
|
|
gBattleTextBuff1[3] = gBattlePartyID[gBattleStruct->field_49];
|
|
|
|
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff2, gBankInMenu, pokemon_order_func(gBattlePartyID[gBankInMenu]))
|
|
|
|
BattleStringExpandPlaceholders(gText_PkmnsXPreventsSwitching, gStringVar4);
|
|
}
|
|
|
|
struct PokeItem
|
|
{
|
|
u16 species;
|
|
u16 item;
|
|
};
|
|
|
|
extern const struct PokeItem gAlteringCaveWildMonHeldItems[9];
|
|
|
|
static s32 GetWildMonTableIdInAlteringCave(u16 species)
|
|
{
|
|
s32 i;
|
|
for (i = 0; i < (s32) ARRAY_COUNT(gAlteringCaveWildMonHeldItems); 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 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 :/
|
|
}
|
|
}
|
|
} */
|
|
|