Some constants in wild_encounter.c, document Feebas spot generation

This commit is contained in:
GriffinR 2021-10-09 14:18:05 -04:00
parent ff01eb951b
commit b01213b8bc

View file

@ -25,9 +25,27 @@
extern const u8 EventScript_RepelWoreOff[]; extern const u8 EventScript_RepelWoreOff[];
#define NUM_FEEBAS_SPOTS 6 #define MAX_ENCOUNTER_RATE 2880
#define NUM_FEEBAS_SPOTS 6
// Number of accessible fishing spots in each section of Route 119
// Each section is an area of the route between the y coordinates in sRoute119WaterTileData
#define NUM_FISHING_SPOTS_1 131
#define NUM_FISHING_SPOTS_2 167
#define NUM_FISHING_SPOTS_3 149
#define NUM_FISHING_SPOTS (NUM_FISHING_SPOTS_1 + NUM_FISHING_SPOTS_2 + NUM_FISHING_SPOTS_3)
enum {
WILD_AREA_LAND,
WILD_AREA_WATER,
WILD_AREA_ROCKS,
WILD_AREA_FISHING,
};
#define WILD_CHECK_REPEL (1 << 0)
#define WILD_CHECK_KEEN_EYE (1 << 1)
// this file's functions
static u16 FeebasRandom(void); static u16 FeebasRandom(void);
static void FeebasSeedRng(u16 seed); static void FeebasSeedRng(u16 seed);
static bool8 IsWildLevelAllowedByRepel(u8 level); static bool8 IsWildLevelAllowedByRepel(u8 level);
@ -36,60 +54,64 @@ static void ApplyCleanseTagEncounterRateMod(u32 *encRate);
static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u8 ability, u8 *monIndex); static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u8 ability, u8 *monIndex);
static bool8 IsAbilityAllowingEncounter(u8 level); static bool8 IsAbilityAllowingEncounter(u8 level);
// EWRAM vars
EWRAM_DATA static u8 sWildEncountersDisabled = 0; EWRAM_DATA static u8 sWildEncountersDisabled = 0;
EWRAM_DATA static u32 sFeebasRngValue = 0; EWRAM_DATA static u32 sFeebasRngValue = 0;
#include "data/wild_encounters.h" #include "data/wild_encounters.h"
//Special Feebas-related data. static const struct WildPokemon sWildFeebas = {20, 25, SPECIES_FEEBAS};
const struct WildPokemon gWildFeebasRoute119Data = {20, 25, SPECIES_FEEBAS};
const u16 gRoute119WaterTileData[] = static const u16 sRoute119WaterTileData[] =
{ {
0, 0x2D, 0, //yMin, yMax, numSpots in previous sections
0x2E, 0x5B, 0x83, 0, 45, 0,
0x5C, 0x8B, 0x12A, 46, 91, NUM_FISHING_SPOTS_1,
92, 139, NUM_FISHING_SPOTS_1 + NUM_FISHING_SPOTS_2,
}; };
// code
void DisableWildEncounters(bool8 disabled) void DisableWildEncounters(bool8 disabled)
{ {
sWildEncountersDisabled = disabled; sWildEncountersDisabled = disabled;
} }
static u16 GetRoute119WaterTileNum(s16 x, s16 y, u8 section) // Each fishing spot on Route 119 is given a number between 1 and NUM_FISHING_SPOTS inclusive.
// The number is determined by counting the valid fishing spots left to right top to bottom.
// The map is divided into three sections, with each section having a pre-counted number of
// fishing spots to start from to avoid counting a large number of spots at the bottom of the map.
// Note that a spot is considered valid if it is surfable and not a waterfall. To exclude all
// of the inaccessible water metatiles (so that they can't be selected as a Feebas spot) they
// use a different metatile that isn't actually surfable because it has MB_NORMAL instead.
// This function is given the coordinates and section of a fishing spot and returns which number it is.
static u16 GetFeebasFishingSpotId(s16 targetX, s16 targetY, u8 section)
{ {
u16 xCur; u16 x, y;
u16 yCur; u16 yMin = sRoute119WaterTileData[section * 3 + 0];
u16 yMin = gRoute119WaterTileData[section * 3 + 0]; u16 yMax = sRoute119WaterTileData[section * 3 + 1];
u16 yMax = gRoute119WaterTileData[section * 3 + 1]; u16 spotId = sRoute119WaterTileData[section * 3 + 2];
u16 tileNum = gRoute119WaterTileData[section * 3 + 2];
for (yCur = yMin; yCur <= yMax; yCur++) for (y = yMin; y <= yMax; y++)
{ {
for (xCur = 0; xCur < gMapHeader.mapLayout->width; xCur++) for (x = 0; x < gMapHeader.mapLayout->width; x++)
{ {
u8 tileBehaviorId = MapGridGetMetatileBehaviorAt(xCur + MAP_OFFSET, yCur + MAP_OFFSET); u8 behavior = MapGridGetMetatileBehaviorAt(x + MAP_OFFSET, y + MAP_OFFSET);
if (MetatileBehavior_IsSurfableAndNotWaterfall(tileBehaviorId) == TRUE) if (MetatileBehavior_IsSurfableAndNotWaterfall(behavior) == TRUE)
{ {
tileNum++; spotId++;
if (x == xCur && y == yCur) if (targetX == x && targetY == y)
return tileNum; return spotId;
} }
} }
} }
return tileNum + 1; return spotId + 1;
} }
static bool8 CheckFeebas(void) static bool8 CheckFeebas(void)
{ {
u8 i; u8 i;
u16 feebasSpots[NUM_FEEBAS_SPOTS]; u16 feebasSpots[NUM_FEEBAS_SPOTS];
s16 x; s16 x, y;
s16 y;
u8 route119Section = 0; u8 route119Section = 0;
u16 waterTileNum; u16 spotId;
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(ROUTE119) if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(ROUTE119)
&& gSaveBlock1Ptr->location.mapNum == MAP_NUM(ROUTE119)) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(ROUTE119))
@ -98,29 +120,42 @@ static bool8 CheckFeebas(void)
x -= MAP_OFFSET; x -= MAP_OFFSET;
y -= MAP_OFFSET; y -= MAP_OFFSET;
if (y >= gRoute119WaterTileData[3 * 0 + 0] && y <= gRoute119WaterTileData[3 * 0 + 1]) // Get which third of the map the player is in
if (y >= sRoute119WaterTileData[3 * 0 + 0] && y <= sRoute119WaterTileData[3 * 0 + 1])
route119Section = 0; route119Section = 0;
if (y >= gRoute119WaterTileData[3 * 1 + 0] && y <= gRoute119WaterTileData[3 * 1 + 1]) if (y >= sRoute119WaterTileData[3 * 1 + 0] && y <= sRoute119WaterTileData[3 * 1 + 1])
route119Section = 1; route119Section = 1;
if (y >= gRoute119WaterTileData[3 * 2 + 0] && y <= gRoute119WaterTileData[3 * 2 + 1]) if (y >= sRoute119WaterTileData[3 * 2 + 0] && y <= sRoute119WaterTileData[3 * 2 + 1])
route119Section = 2; route119Section = 2;
if (Random() % 100 > 49) // 50% chance of encountering Feebas // 50% chance of encountering Feebas (assuming this is a Feebas spot)
if (Random() % 100 > 49)
return FALSE; return FALSE;
FeebasSeedRng(gSaveBlock1Ptr->dewfordTrends[0].rand); FeebasSeedRng(gSaveBlock1Ptr->dewfordTrends[0].rand);
// Assign each Feebas spot to a random fishing spot.
// Randomness is fixed depending on the seed above.
for (i = 0; i != NUM_FEEBAS_SPOTS;) for (i = 0; i != NUM_FEEBAS_SPOTS;)
{ {
feebasSpots[i] = FeebasRandom() % 447; feebasSpots[i] = FeebasRandom() % NUM_FISHING_SPOTS;
if (feebasSpots[i] == 0) if (feebasSpots[i] == 0)
feebasSpots[i] = 447; feebasSpots[i] = NUM_FISHING_SPOTS;
// < 1 below is a pointless check, it will never be TRUE.
// >= 4 to skip fishing spots 1-3, because these are inaccessible
// spots at the top of the map, at (9,7), (7,13), and (15,16).
// The first accessible fishing spot is spot 4 at (18,18).
if (feebasSpots[i] < 1 || feebasSpots[i] >= 4) if (feebasSpots[i] < 1 || feebasSpots[i] >= 4)
i++; i++;
} }
waterTileNum = GetRoute119WaterTileNum(x, y, route119Section);
// Check which fishing spot the player is at, and see if
// it matches any of the Feebas spots.
spotId = GetFeebasFishingSpotId(x, y, route119Section);
for (i = 0; i < NUM_FEEBAS_SPOTS; i++) for (i = 0; i < NUM_FEEBAS_SPOTS; i++)
{ {
if (waterTileNum == feebasSpots[i]) if (spotId == feebasSpots[i])
return TRUE; return TRUE;
} }
} }
@ -256,7 +291,6 @@ static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon)
rand--; rand--;
} }
} }
return min + rand; return min + rand;
} }
@ -365,24 +399,13 @@ static void CreateWildMon(u16 species, u8 level)
else else
gender = MON_FEMALE; gender = MON_FEMALE;
CreateMonWithGenderNatureLetter(&gEnemyParty[0], species, level, 32, gender, PickWildMonNature(), 0); CreateMonWithGenderNatureLetter(&gEnemyParty[0], species, level, USE_RANDOM_IVS, gender, PickWildMonNature(), 0);
return; return;
} }
CreateMonWithNature(&gEnemyParty[0], species, level, 32, PickWildMonNature()); CreateMonWithNature(&gEnemyParty[0], species, level, USE_RANDOM_IVS, PickWildMonNature());
} }
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 *wildMonInfo, u8 area, u8 flags) static bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, u8 area, u8 flags)
{ {
u8 wildMonIndex = 0; u8 wildMonIndex = 0;
@ -436,7 +459,7 @@ static bool8 SetUpMassOutbreakEncounter(u8 flags)
return FALSE; return FALSE;
CreateWildMon(gSaveBlock1Ptr->outbreakPokemonSpecies, gSaveBlock1Ptr->outbreakPokemonLevel); CreateWildMon(gSaveBlock1Ptr->outbreakPokemonSpecies, gSaveBlock1Ptr->outbreakPokemonLevel);
for (i = 0; i < 4; i++) for (i = 0; i < MAX_MON_MOVES; i++)
SetMonMoveSlot(&gEnemyParty[0], gSaveBlock1Ptr->outbreakPokemonMoves[i], i); SetMonMoveSlot(&gEnemyParty[0], gSaveBlock1Ptr->outbreakPokemonMoves[i], i);
return TRUE; return TRUE;
@ -444,7 +467,7 @@ static bool8 SetUpMassOutbreakEncounter(u8 flags)
static bool8 DoMassOutbreakEncounterTest(void) static bool8 DoMassOutbreakEncounterTest(void)
{ {
if (gSaveBlock1Ptr->outbreakPokemonSpecies != 0 if (gSaveBlock1Ptr->outbreakPokemonSpecies != SPECIES_NONE
&& gSaveBlock1Ptr->location.mapNum == gSaveBlock1Ptr->outbreakLocationMapNum && gSaveBlock1Ptr->location.mapNum == gSaveBlock1Ptr->outbreakLocationMapNum
&& gSaveBlock1Ptr->location.mapGroup == gSaveBlock1Ptr->outbreakLocationMapGroup) && gSaveBlock1Ptr->location.mapGroup == gSaveBlock1Ptr->outbreakLocationMapGroup)
{ {
@ -456,7 +479,7 @@ static bool8 DoMassOutbreakEncounterTest(void)
static bool8 DoWildEncounterRateDiceRoll(u16 encounterRate) static bool8 DoWildEncounterRateDiceRoll(u16 encounterRate)
{ {
if (Random() % 2880 < encounterRate) if (Random() % MAX_ENCOUNTER_RATE < encounterRate)
return TRUE; return TRUE;
else else
return FALSE; return FALSE;
@ -486,8 +509,8 @@ static bool8 DoWildEncounterRateTest(u32 encounterRate, bool8 ignoreAbility)
else if (ability == ABILITY_SAND_VEIL && gSaveBlock1Ptr->weather == WEATHER_SANDSTORM) else if (ability == ABILITY_SAND_VEIL && gSaveBlock1Ptr->weather == WEATHER_SANDSTORM)
encounterRate /= 2; encounterRate /= 2;
} }
if (encounterRate > 2880) if (encounterRate > MAX_ENCOUNTER_RATE)
encounterRate = 2880; encounterRate = MAX_ENCOUNTER_RATE;
return DoWildEncounterRateDiceRoll(encounterRate); return DoWildEncounterRateDiceRoll(encounterRate);
} }
@ -639,7 +662,7 @@ void RockSmashWildEncounter(void)
gSpecialVar_Result = FALSE; gSpecialVar_Result = FALSE;
} }
else if (DoWildEncounterRateTest(wildPokemonInfo->encounterRate, 1) == TRUE else if (DoWildEncounterRateTest(wildPokemonInfo->encounterRate, 1) == TRUE
&& TryGenerateWildMon(wildPokemonInfo, 2, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE) && TryGenerateWildMon(wildPokemonInfo, WILD_AREA_ROCKS, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE)
{ {
BattleSetup_StartWildBattle(); BattleSetup_StartWildBattle();
gSpecialVar_Result = TRUE; gSpecialVar_Result = TRUE;
@ -744,9 +767,9 @@ void FishingWildEncounter(u8 rod)
if (CheckFeebas() == TRUE) if (CheckFeebas() == TRUE)
{ {
u8 level = ChooseWildMonLevel(&gWildFeebasRoute119Data); u8 level = ChooseWildMonLevel(&sWildFeebas);
species = gWildFeebasRoute119Data.species; species = sWildFeebas.species;
CreateWildMon(species, level); CreateWildMon(species, level);
} }
else else