pokefirered/src/wild_encounter.c
cawtds d17698ee8f changed all ability variables to u16 or larger
added ability capsule and ability patch functionality
removed unused ribbons to free space in pokemonsubstruct3 for hidden ability
2024-04-26 22:09:46 +02:00

785 lines
24 KiB
C

#include "global.h"
#include "random.h"
#include "wild_encounter.h"
#include "event_data.h"
#include "fieldmap.h"
#include "random.h"
#include "roamer.h"
#include "field_player_avatar.h"
#include "battle_setup.h"
#include "overworld.h"
#include "metatile_behavior.h"
#include "event_scripts.h"
#include "script.h"
#include "link.h"
#include "quest_log.h"
#include "constants/maps.h"
#include "constants/abilities.h"
#include "constants/items.h"
#define MAX_ENCOUNTER_RATE 1600
#define HEADER_NONE 0xFFFF
struct WildEncounterData
{
u32 rngState;
u16 prevMetatileBehavior;
u16 encounterRateBuff;
u8 stepsSinceLastEncounter;
u8 abilityEffect;
u16 leadMonHeldItem;
};
static EWRAM_DATA struct WildEncounterData sWildEncounterData = {};
static EWRAM_DATA bool8 sWildEncountersDisabled = FALSE;
static bool8 UnlockedTanobyOrAreNotInTanoby(void);
static u32 GenerateUnownPersonalityByLetter(u8 letter);
static bool8 IsWildLevelAllowedByRepel(u8 level);
static void ApplyFluteEncounterRateMod(u32 *rate);
static u8 GetFluteEncounterRateModType(void);
static void ApplyCleanseTagEncounterRateMod(u32 *rate);
static bool8 IsLeadMonHoldingCleanseTag(void);
static u16 WildEncounterRandom(void);
static void AddToWildEncounterRateBuff(u8 encouterRate);
#include "data/wild_encounters.h"
static const u8 sUnownLetterSlots[][LAND_WILD_COUNT] = {
// A A A A A A A A A A A ?
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27},
// C C C D D D H H H U U O
{ 2, 2, 2, 3, 3, 3, 7, 7, 7, 20, 20, 14},
// N N N N S S S S I I E E
{13, 13, 13, 13, 18, 18, 18, 18, 8, 8, 4, 4},
// P P L L J J R R R Q Q Q
{15, 15, 11, 11, 9, 9, 17, 17, 17, 16, 16, 16},
// Y Y T T G G G F F F K K
{24, 24, 19, 19, 6, 6, 6, 5, 5, 5, 10, 10},
// V V V W W W X X M M B B
{21, 21, 21, 22, 22, 22, 23, 23, 12, 12, 1, 1},
// Z Z Z Z Z Z Z Z Z Z Z !
{25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26},
};
void DisableWildEncounters(bool8 state)
{
sWildEncountersDisabled = state;
}
static u8 ChooseWildMonIndex_Land(void)
{
u8 rand = Random() % ENCOUNTER_CHANCE_LAND_MONS_TOTAL;
if (rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_0)
return 0;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_1)
return 1;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_2)
return 2;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_3)
return 3;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_4)
return 4;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_5)
return 5;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_6)
return 6;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_7)
return 7;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_8)
return 8;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_9)
return 9;
else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_10)
return 10;
else
return 11;
}
static u8 ChooseWildMonIndex_WaterRock(void)
{
u8 rand = Random() % ENCOUNTER_CHANCE_WATER_MONS_TOTAL;
if (rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_0)
return 0;
else if (rand >= ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 && rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_1)
return 1;
else if (rand >= ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 && rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_2)
return 2;
else if (rand >= ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 && rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_3)
return 3;
else
return 4;
}
static u8 ChooseWildMonIndex_Fishing(u8 rod)
{
u8 wildMonIndex = 0;
u8 rand = Random() % max(max(ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_TOTAL, ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_TOTAL),
ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_TOTAL);
switch (rod)
{
case OLD_ROD:
if (rand < ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0)
wildMonIndex = 0;
else
wildMonIndex = 1;
break;
case GOOD_ROD:
if (rand < ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2)
wildMonIndex = 2;
if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 && rand < ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3)
wildMonIndex = 3;
if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 && rand < ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4)
wildMonIndex = 4;
break;
case SUPER_ROD:
if (rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5)
wildMonIndex = 5;
if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 && rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6)
wildMonIndex = 6;
if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 && rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7)
wildMonIndex = 7;
if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 && rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8)
wildMonIndex = 8;
if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 && rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9)
wildMonIndex = 9;
break;
}
return wildMonIndex;
}
static u8 ChooseWildMonLevel(const struct WildPokemon * info)
{
u8 lo;
u8 hi;
u8 mod;
u8 res;
if (info->maxLevel >= info->minLevel)
{
lo = info->minLevel;
hi = info->maxLevel;
}
else
{
lo = info->maxLevel;
hi = info->minLevel;
}
mod = hi - lo + 1;
res = Random() % mod;
return lo + res;
}
static u16 GetCurrentMapWildMonHeaderId(void)
{
u16 i;
for (i = 0; ; i++)
{
const struct WildPokemonHeader * wildHeader = &gWildMonHeaders[i];
if (wildHeader->mapGroup == MAP_GROUP(UNDEFINED))
break;
if (gWildMonHeaders[i].mapGroup == gSaveBlock1Ptr->location.mapGroup &&
gWildMonHeaders[i].mapNum == gSaveBlock1Ptr->location.mapNum)
{
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(SIX_ISLAND_ALTERING_CAVE) &&
gSaveBlock1Ptr->location.mapNum == MAP_NUM(SIX_ISLAND_ALTERING_CAVE))
{
u16 alteringCaveId = VarGet(VAR_ALTERING_CAVE_WILD_SET);
if (alteringCaveId >= NUM_ALTERING_CAVE_TABLES)
alteringCaveId = 0;
i += alteringCaveId;
}
if (!UnlockedTanobyOrAreNotInTanoby())
break;
return i;
}
}
return HEADER_NONE;
}
static bool8 UnlockedTanobyOrAreNotInTanoby(void)
{
if (FlagGet(FLAG_SYS_UNLOCKED_TANOBY_RUINS))
return TRUE;
if (gSaveBlock1Ptr->location.mapGroup != MAP_GROUP(SEVEN_ISLAND_TANOBY_RUINS_DILFORD_CHAMBER))
return TRUE;
if (!(gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_MONEAN_CHAMBER)
|| gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_LIPTOO_CHAMBER)
|| gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_WEEPTH_CHAMBER)
|| gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_DILFORD_CHAMBER)
|| gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_SCUFIB_CHAMBER)
|| gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_RIXY_CHAMBER)
|| gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_VIAPOIS_CHAMBER)
))
return TRUE;
return FALSE;
}
static void GenerateWildMon(u16 species, u8 level, u8 slot)
{
u32 personality;
s8 chamber;
ZeroEnemyPartyMons();
if (species != SPECIES_UNOWN)
{
CreateMonWithNature(&gEnemyParty[0], species, level, USE_RANDOM_IVS, Random() % NUM_NATURES);
}
else
{
chamber = gSaveBlock1Ptr->location.mapNum - MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_MONEAN_CHAMBER);
personality = GenerateUnownPersonalityByLetter(sUnownLetterSlots[chamber][slot]);
CreateMon(&gEnemyParty[0], species, level, USE_RANDOM_IVS, TRUE, personality, FALSE, 0);
}
}
static u32 GenerateUnownPersonalityByLetter(u8 letter)
{
u32 personality;
do
{
personality = (Random() << 16) | Random();
} while (GetUnownLetterByPersonalityLoByte(personality) != letter);
return personality;
}
u8 GetUnownLetterByPersonalityLoByte(u32 personality)
{
return GET_UNOWN_LETTER(personality);
}
enum
{
WILD_AREA_LAND,
WILD_AREA_WATER,
WILD_AREA_ROCKS,
WILD_AREA_FISHING,
};
#define WILD_CHECK_REPEL 0x1
#define WILD_CHECK_KEEN_EYE 0x2
static bool8 TryGenerateWildMon(const struct WildPokemonInfo * info, u8 area, u8 flags)
{
u8 slot = 0;
u8 level;
switch (area)
{
case WILD_AREA_LAND:
slot = ChooseWildMonIndex_Land();
break;
case WILD_AREA_WATER:
slot = ChooseWildMonIndex_WaterRock();
break;
case WILD_AREA_ROCKS:
slot = ChooseWildMonIndex_WaterRock();
break;
}
level = ChooseWildMonLevel(&info->wildPokemon[slot]);
if (flags == WILD_CHECK_REPEL && !IsWildLevelAllowedByRepel(level))
{
return FALSE;
}
GenerateWildMon(info->wildPokemon[slot].species, level, slot);
return TRUE;
}
static u16 GenerateFishingEncounter(const struct WildPokemonInfo * info, u8 rod)
{
u8 slot = ChooseWildMonIndex_Fishing(rod);
u8 level = ChooseWildMonLevel(&info->wildPokemon[slot]);
GenerateWildMon(info->wildPokemon[slot].species, level, slot);
return info->wildPokemon[slot].species;
}
static bool8 DoWildEncounterRateDiceRoll(u16 encounterRate)
{
if (WildEncounterRandom() % MAX_ENCOUNTER_RATE < encounterRate)
return TRUE;
return FALSE;
}
static bool8 DoWildEncounterRateTest(u32 encounterRate, bool8 ignoreAbility)
{
encounterRate *= 16;
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE))
encounterRate = encounterRate * 80 / 100;
encounterRate += sWildEncounterData.encounterRateBuff * 16 / 200;
ApplyFluteEncounterRateMod(&encounterRate);
ApplyCleanseTagEncounterRateMod(&encounterRate);
if (!ignoreAbility)
{
switch (sWildEncounterData.abilityEffect)
{
case 1:
encounterRate /= 2;
break;
case 2:
encounterRate *= 2;
break;
}
}
if (encounterRate > MAX_ENCOUNTER_RATE)
encounterRate = MAX_ENCOUNTER_RATE;
return DoWildEncounterRateDiceRoll(encounterRate);
}
static u8 GetAbilityEncounterRateModType(void)
{
sWildEncounterData.abilityEffect = 0;
if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG))
{
u16 ability = GetMonAbility(&gPlayerParty[0]);
if (ability == ABILITY_STENCH)
sWildEncounterData.abilityEffect = 1;
else if (ability == ABILITY_ILLUMINATE)
sWildEncounterData.abilityEffect = 2;
}
return sWildEncounterData.abilityEffect;
}
static bool8 DoGlobalWildEncounterDiceRoll(void)
{
if ((Random() % 100) >= 60)
return FALSE;
return TRUE;
}
bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior)
{
u16 headerId;
struct Roamer * roamer;
if (sWildEncountersDisabled == TRUE)
return FALSE;
headerId = GetCurrentMapWildMonHeaderId();
if (headerId != HEADER_NONE)
{
if (ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_ENCOUNTER_TYPE) == TILE_ENCOUNTER_LAND)
{
if (gWildMonHeaders[headerId].landMonsInfo == NULL)
return FALSE;
else if (previousMetatileBehavior != ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR) && !DoGlobalWildEncounterDiceRoll())
return FALSE;
if (DoWildEncounterRateTest(gWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE)
{
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate);
return FALSE;
}
else if (TryStartRoamerEncounter() == TRUE)
{
roamer = &gSaveBlock1Ptr->roamer;
if (!IsWildLevelAllowedByRepel(roamer->level))
{
return FALSE;
}
StartRoamerBattle();
return TRUE;
}
else
{
// try a regular wild land encounter
if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE)
{
StartWildBattle();
return TRUE;
}
else
{
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate);
}
}
}
else if (ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_ENCOUNTER_TYPE) == TILE_ENCOUNTER_WATER
|| (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) && MetatileBehavior_IsBridge(ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR)) == TRUE))
{
if (gWildMonHeaders[headerId].waterMonsInfo == NULL)
return FALSE;
else if (previousMetatileBehavior != ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR) && !DoGlobalWildEncounterDiceRoll())
return FALSE;
else if (DoWildEncounterRateTest(gWildMonHeaders[headerId].waterMonsInfo->encounterRate, FALSE) != TRUE)
{
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].waterMonsInfo->encounterRate);
return FALSE;
}
if (TryStartRoamerEncounter() == TRUE)
{
roamer = &gSaveBlock1Ptr->roamer;
if (!IsWildLevelAllowedByRepel(roamer->level))
{
return FALSE;
}
StartRoamerBattle();
return TRUE;
}
else // try a regular surfing encounter
{
if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE)
{
StartWildBattle();
return TRUE;
}
else
{
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].waterMonsInfo->encounterRate);
}
}
}
}
return FALSE;
}
void RockSmashWildEncounter(void)
{
u16 headerIdx = GetCurrentMapWildMonHeaderId();
if (headerIdx == HEADER_NONE)
gSpecialVar_Result = FALSE;
else if (gWildMonHeaders[headerIdx].rockSmashMonsInfo == NULL)
gSpecialVar_Result = FALSE;
else if (DoWildEncounterRateTest(gWildMonHeaders[headerIdx].rockSmashMonsInfo->encounterRate, TRUE) != TRUE)
gSpecialVar_Result = FALSE;
else if (TryGenerateWildMon(gWildMonHeaders[headerIdx].rockSmashMonsInfo, WILD_AREA_ROCKS, WILD_CHECK_REPEL) == TRUE)
{
StartWildBattle();
gSpecialVar_Result = TRUE;
}
else
gSpecialVar_Result = FALSE;
}
bool8 SweetScentWildEncounter(void)
{
s16 x, y;
u16 headerId;
PlayerGetDestCoords(&x, &y);
headerId = GetCurrentMapWildMonHeaderId();
if (headerId != HEADER_NONE)
{
if (MapGridGetMetatileAttributeAt(x, y, METATILE_ATTRIBUTE_ENCOUNTER_TYPE) == TILE_ENCOUNTER_LAND)
{
if (TryStartRoamerEncounter() == TRUE)
{
StartRoamerBattle();
return TRUE;
}
if (gWildMonHeaders[headerId].landMonsInfo == NULL)
return FALSE;
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0);
StartWildBattle();
return TRUE;
}
else if (MapGridGetMetatileAttributeAt(x, y, METATILE_ATTRIBUTE_ENCOUNTER_TYPE) == TILE_ENCOUNTER_WATER)
{
if (TryStartRoamerEncounter() == TRUE)
{
StartRoamerBattle();
return TRUE;
}
if (gWildMonHeaders[headerId].waterMonsInfo == NULL)
return FALSE;
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, 0);
StartWildBattle();
return TRUE;
}
}
return FALSE;
}
bool8 DoesCurrentMapHaveFishingMons(void)
{
u16 headerIdx = GetCurrentMapWildMonHeaderId();
if (headerIdx == HEADER_NONE)
return FALSE;
if (gWildMonHeaders[headerIdx].fishingMonsInfo == NULL)
return FALSE;
return TRUE;
}
void FishingWildEncounter(u8 rod)
{
GenerateFishingEncounter(gWildMonHeaders[GetCurrentMapWildMonHeaderId()].fishingMonsInfo, rod);
IncrementGameStat(GAME_STAT_FISHING_CAPTURES);
StartWildBattle();
}
u16 GetLocalWildMon(bool8 *isWaterMon)
{
u16 headerId;
const struct WildPokemonInfo * landMonsInfo;
const struct WildPokemonInfo * waterMonsInfo;
*isWaterMon = FALSE;
headerId = GetCurrentMapWildMonHeaderId();
if (headerId == HEADER_NONE)
return SPECIES_NONE;
landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
// Neither
if (landMonsInfo == NULL && waterMonsInfo == NULL)
return SPECIES_NONE;
// Land Pokemon
else if (landMonsInfo != NULL && waterMonsInfo == NULL)
return landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species;
// Water Pokemon
else if (landMonsInfo == NULL && waterMonsInfo != NULL)
{
*isWaterMon = TRUE;
return waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
}
// Either land or water Pokemon
if ((Random() % 100) < 80)
{
return landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species;
}
else
{
*isWaterMon = TRUE;
return waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
}
}
u16 GetLocalWaterMon(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
if (headerId != HEADER_NONE)
{
const struct WildPokemonInfo * waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
if (waterMonsInfo)
return waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
}
return SPECIES_NONE;
}
bool8 UpdateRepelCounter(void)
{
u16 steps;
if (InUnionRoom() == TRUE)
return FALSE;
if (gQuestLogState == QL_STATE_PLAYBACK)
return FALSE;
steps = VarGet(VAR_REPEL_STEP_COUNT);
if (steps != 0)
{
steps--;
VarSet(VAR_REPEL_STEP_COUNT, steps);
if (steps == 0)
{
ScriptContext_SetupScript(EventScript_RepelWoreOff);
return TRUE;
}
}
return FALSE;
}
static bool8 IsWildLevelAllowedByRepel(u8 wildLevel)
{
u8 i;
if (!VarGet(VAR_REPEL_STEP_COUNT))
return TRUE;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_HP) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))
{
u8 ourLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL);
if (wildLevel < ourLevel)
return FALSE;
else
return TRUE;
}
}
return FALSE;
}
static void ApplyFluteEncounterRateMod(u32 *encounterRate)
{
switch (GetFluteEncounterRateModType())
{
case 1:
*encounterRate += *encounterRate / 2;
break;
case 2:
*encounterRate = *encounterRate / 2;
break;
}
}
static u8 GetFluteEncounterRateModType(void)
{
if (FlagGet(FLAG_SYS_WHITE_FLUTE_ACTIVE) == TRUE)
return 1;
else if (FlagGet(FLAG_SYS_BLACK_FLUTE_ACTIVE) == TRUE)
return 2;
else
return 0;
}
static void ApplyCleanseTagEncounterRateMod(u32 *encounterRate)
{
if (IsLeadMonHoldingCleanseTag())
*encounterRate = *encounterRate * 2 / 3;
}
static bool8 IsLeadMonHoldingCleanseTag(void)
{
if (sWildEncounterData.leadMonHeldItem == ITEM_CLEANSE_TAG)
return TRUE;
else
return FALSE;
}
void SeedWildEncounterRng(u16 seed)
{
sWildEncounterData.rngState = seed;
ResetEncounterRateModifiers();
}
static u16 WildEncounterRandom(void)
{
sWildEncounterData.rngState = ISO_RANDOMIZE2(sWildEncounterData.rngState);
return sWildEncounterData.rngState >> 16;
}
static u8 GetMapBaseEncounterCooldown(u8 encounterType)
{
u16 headerIdx = GetCurrentMapWildMonHeaderId();
if (headerIdx == HEADER_NONE)
return 0xFF;
if (encounterType == TILE_ENCOUNTER_LAND)
{
if (gWildMonHeaders[headerIdx].landMonsInfo == NULL)
return 0xFF;
if (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate >= 80)
return 0;
if (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate < 10)
return 8;
return 8 - (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate / 10);
}
if (encounterType == TILE_ENCOUNTER_WATER)
{
if (gWildMonHeaders[headerIdx].waterMonsInfo == NULL)
return 0xFF;
if (gWildMonHeaders[headerIdx].waterMonsInfo->encounterRate >= 80)
return 0;
if (gWildMonHeaders[headerIdx].waterMonsInfo->encounterRate < 10)
return 8;
return 8 - (gWildMonHeaders[headerIdx].waterMonsInfo->encounterRate / 10);
}
return 0xFF;
}
void ResetEncounterRateModifiers(void)
{
sWildEncounterData.encounterRateBuff = 0;
sWildEncounterData.stepsSinceLastEncounter = 0;
}
static bool8 HandleWildEncounterCooldown(u32 currMetatileAttrs)
{
u8 encounterType = ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_ENCOUNTER_TYPE);
u32 minSteps;
u32 encRate;
if (encounterType == TILE_ENCOUNTER_NONE)
return FALSE;
minSteps = GetMapBaseEncounterCooldown(encounterType);
if (minSteps == 0xFF)
return FALSE;
minSteps *= 256;
encRate = 5 * 256;
switch (GetFluteEncounterRateModType())
{
case 1:
minSteps -= minSteps / 2;
encRate += encRate / 2;
break;
case 2:
minSteps *= 2;
encRate /= 2;
break;
}
sWildEncounterData.leadMonHeldItem = GetMonData(&gPlayerParty[0], MON_DATA_HELD_ITEM);
if (IsLeadMonHoldingCleanseTag() == TRUE)
{
minSteps += minSteps / 3;
encRate -= encRate / 3;
}
switch (GetAbilityEncounterRateModType())
{
case 1:
minSteps *= 2;
encRate /= 2;
break;
case 2:
minSteps /= 2;
encRate *= 2;
break;
}
minSteps /= 256;
encRate /= 256;
if (sWildEncounterData.stepsSinceLastEncounter >= minSteps)
return TRUE;
sWildEncounterData.stepsSinceLastEncounter++;
if ((Random() % 100) < encRate)
return TRUE;
return FALSE;
}
bool8 TryStandardWildEncounter(u32 currMetatileAttrs)
{
if (!HandleWildEncounterCooldown(currMetatileAttrs))
{
sWildEncounterData.prevMetatileBehavior = ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR);
return FALSE;
}
else if (StandardWildEncounter(currMetatileAttrs, sWildEncounterData.prevMetatileBehavior) == TRUE)
{
sWildEncounterData.encounterRateBuff = 0;
sWildEncounterData.stepsSinceLastEncounter = 0;
sWildEncounterData.prevMetatileBehavior = ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR);
return TRUE;
}
else
{
sWildEncounterData.prevMetatileBehavior = ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR);
return FALSE;
}
}
static void AddToWildEncounterRateBuff(u8 encounterRate)
{
if (VarGet(VAR_REPEL_STEP_COUNT) == 0)
sWildEncounterData.encounterRateBuff += encounterRate;
else
sWildEncounterData.encounterRateBuff = 0;
}