diff options
Diffstat (limited to 'src/wild_encounter.c')
-rw-r--r-- | src/wild_encounter.c | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/src/wild_encounter.c b/src/wild_encounter.c new file mode 100644 index 000000000..f17e1f79b --- /dev/null +++ b/src/wild_encounter.c @@ -0,0 +1,789 @@ +#include "global.h" +#include "random.h" +#include "wild_encounter.h" +#include "event_data.h" +#include "fieldmap.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/species.h" +#include "constants/maps.h" +#include "constants/vars.h" +#include "constants/abilities.h" +#include "constants/items.h" + +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[][12] = { + // 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) + 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; +} + +enum +{ + OLD_ROD, + GOOD_ROD, + SUPER_ROD +}; + +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) + 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 == 0xFF) + 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 > 8) + alteringCaveId = 0; + + i += alteringCaveId; + } + + if (!UnlockedTanobyOrAreNotInTanoby()) + break; + return i; + } + } + + return -1; +} + +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, 32, Random() % 25); + } + else + { + chamber = gSaveBlock1Ptr->location.mapNum - MAP_NUM(SEVEN_ISLAND_TANOBY_RUINS_MONEAN_CHAMBER); + personality = GenerateUnownPersonalityByLetter(sUnownLetterSlots[chamber][slot]); + CreateMon(&gEnemyParty[0], species, level, 32, 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 (((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | (personality & 0x3)) % 0x1C; +} + +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 a0) +{ + if (WildEncounterRandom() % 1600 < a0) + 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 > 1600) + encounterRate = 1600; + return DoWildEncounterRateDiceRoll(encounterRate); +} + +static u8 GetAbilityEncounterRateModType(void) +{ + sWildEncounterData.abilityEffect = 0; + if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) + { + u8 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 currMetatileBehavior, u16 previousMetatileBehavior) +{ + u16 headerId; + struct Roamer * roamer; + + if (sWildEncountersDisabled == TRUE) + return FALSE; + + headerId = GetCurrentMapWildMonHeaderId(); + if (headerId != 0xFFFF) + { + if (sub_8058F1C(currMetatileBehavior, 4) == TRUE) + { + if (gWildMonHeaders[headerId].landMonsInfo == NULL) + return FALSE; + else if (previousMetatileBehavior != sub_8058F1C(currMetatileBehavior, 0) && !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; + } + + BattleSetup_StartRoamerBattle(); + return TRUE; + } + else + { + + // try a regular wild land encounter + if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE) + { + BattleSetup_StartWildBattle(); + return TRUE; + } + else + { + AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate); + } + } + } + else if (sub_8058F1C(currMetatileBehavior, 4) == 2 + || (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) && MetatileBehavior_IsBridge(sub_8058F1C(currMetatileBehavior, 0)) == TRUE)) + { + if (gWildMonHeaders[headerId].waterMonsInfo == NULL) + return FALSE; + else if (previousMetatileBehavior != sub_8058F1C(currMetatileBehavior, 0) && !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; + } + + BattleSetup_StartRoamerBattle(); + return TRUE; + } + else // try a regular surfing encounter + { + if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE) + { + BattleSetup_StartWildBattle(); + return TRUE; + } + else + { + AddToWildEncounterRateBuff(gWildMonHeaders[headerId].waterMonsInfo->encounterRate); + } + } + } + } + + return FALSE; +} + +void ScrSpecial_RockSmashWildEncounter(void) +{ + u16 headerIdx = GetCurrentMapWildMonHeaderId(); + if (headerIdx == 0xFFFF) + 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) + { + BattleSetup_StartWildBattle(); + gSpecialVar_Result = TRUE; + } + else + gSpecialVar_Result = FALSE; +} + +bool8 SweetScentWildEncounter(void) +{ + s16 x, y; + u16 headerId; + + PlayerGetDestCoords(&x, &y); + headerId = GetCurrentMapWildMonHeaderId(); + if (headerId != 0xFFFF) + { + if (sub_8058F48(x, y, 4) == 1) + { + if (TryStartRoamerEncounter() == TRUE) + { + BattleSetup_StartRoamerBattle(); + return TRUE; + } + + if (gWildMonHeaders[headerId].landMonsInfo == NULL) + return FALSE; + + TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0); + + BattleSetup_StartWildBattle(); + return TRUE; + } + else if (sub_8058F48(x, y, 4) == 2) + { + if (TryStartRoamerEncounter() == TRUE) + { + BattleSetup_StartRoamerBattle(); + return TRUE; + } + + if (gWildMonHeaders[headerId].waterMonsInfo == NULL) + return FALSE; + + TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, 0); + BattleSetup_StartWildBattle(); + return TRUE; + } + } + + return FALSE; +} + +bool8 DoesCurrentMapHaveFishingMons(void) +{ + u16 headerIdx = GetCurrentMapWildMonHeaderId(); + if (headerIdx == 0xFFFF) + 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); + BattleSetup_StartWildBattle(); +} + +u16 GetLocalWildMon(bool8 *isWaterMon) +{ + u16 headerId; + const struct WildPokemonInfo * landMonsInfo; + const struct WildPokemonInfo * waterMonsInfo; + + *isWaterMon = FALSE; + headerId = GetCurrentMapWildMonHeaderId(); + if (headerId == 0xFFFF) + 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 != 0xFFFF) + { + 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 (gUnknown_203ADFA == 2) + return FALSE; + + steps = VarGet(VAR_REPEL_STEP_COUNT); + + if (steps != 0) + { + steps--; + VarSet(VAR_REPEL_STEP_COUNT, steps); + if (steps == 0) + { + ScriptContext1_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 *= 1103515245; + sWildEncounterData.rngState += 12345; + return sWildEncounterData.rngState >> 16; +} + +static u8 GetMapBaseEncounterCooldown(u8 a0) +{ + u16 headerIdx = GetCurrentMapWildMonHeaderId(); + if (headerIdx == 0xFFFF) + return 0xFF; + if (a0 == 1) + { + 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 (a0 == 2) + { + 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 currMetatileBehavior) +{ + u8 unk = sub_8058F1C(currMetatileBehavior, 4); + u32 minSteps; + u32 encRate; + if (unk == 0) + return FALSE; + minSteps = GetMapBaseEncounterCooldown(unk); + 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 currMetatileBehavior) +{ + if (!HandleWildEncounterCooldown(currMetatileBehavior)) + { + sWildEncounterData.prevMetatileBehavior = sub_8058F1C(currMetatileBehavior, 0); + return FALSE; + } + else if (StandardWildEncounter(currMetatileBehavior, sWildEncounterData.prevMetatileBehavior) == TRUE) + { + sWildEncounterData.encounterRateBuff = 0; + sWildEncounterData.stepsSinceLastEncounter = 0; + sWildEncounterData.prevMetatileBehavior = sub_8058F1C(currMetatileBehavior, 0); + return TRUE; + } + else + { + sWildEncounterData.prevMetatileBehavior = sub_8058F1C(currMetatileBehavior, 0); + return FALSE; + } +} + +static void AddToWildEncounterRateBuff(u8 encounterRate) +{ + if (VarGet(VAR_REPEL_STEP_COUNT) == 0) + sWildEncounterData.encounterRateBuff += encounterRate; + else + sWildEncounterData.encounterRateBuff = 0; +} |