summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--src/dodrio_berry_picking.c14
-rw-r--r--src/roamer.c167
3 files changed, 102 insertions, 81 deletions
diff --git a/README.md b/README.md
index 7adbb3e2d..c23965485 100644
--- a/README.md
+++ b/README.md
@@ -28,4 +28,4 @@ Other disassembly and/or decompilation projects:
## Contacts
-You can find us on [Discord](https://discord.gg/d5dubZ3) and [IRC](https://kiwiirc.com/client/irc.freenode.net/?#pret).
+You can find us on [Discord](https://discord.gg/d5dubZ3) and [IRC](https://web.libera.chat/?#pret).
diff --git a/src/dodrio_berry_picking.c b/src/dodrio_berry_picking.c
index c69ef9267..e5ff1d184 100644
--- a/src/dodrio_berry_picking.c
+++ b/src/dodrio_berry_picking.c
@@ -517,21 +517,21 @@ static const u8 sDodrioNeighborMap[MAX_RFU_PLAYERS][MAX_RFU_PLAYERS][3] =
},
};
-#define __ 9 // No player at this column. This may go out of bounds if this is returned
+#define x 9 // No player at this column. This may go out of bounds if this is returned
// Takes the number of players and a column and returns the player id at that column.
// Note that the assignment is somewhat arbitrary as players share neighboring columns.
ALIGNED(4)
static const u8 sPlayerIdAtColumn[MAX_RFU_PLAYERS][NUM_BERRY_COLUMNS] =
{
- {__, __, __, __, 1, 1, 1, __, __, __, __}, // 1 player
- {__, __, __, 0, 0, 1, 1, 0, __, __, __}, // 2 players
- {__, __, 2, 2, 0, 0, 1, 1, 1, __, __}, // 3 players
- {__, 3, 3, 0, 0, 1, 1, 2, 2, 3, __}, // 4 players
- { 3, 3, 4, 4, 0, 0, 1, 1, 2, 2, 3}, // 5 players
+ {x, x, x, x, 1, 1, 1, x, x, x, x}, // 1 player
+ {x, x, x, 0, 0, 1, 1, 0, x, x, x}, // 2 players
+ {x, x, 2, 2, 0, 0, 1, 1, 1, x, x}, // 3 players
+ {x, 3, 3, 0, 0, 1, 1, 2, 2, 3, x}, // 4 players
+ {3, 3, 4, 4, 0, 0, 1, 1, 2, 2, 3}, // 5 players
};
-#undef __
+#undef x
// Each array contains the columns that belong solely to one player, dependent on the number of players
// When determing how difficult the berries in a column should be, the highest
diff --git a/src/roamer.c b/src/roamer.c
index d053e5b25..b8d100967 100644
--- a/src/roamer.c
+++ b/src/roamer.c
@@ -5,51 +5,74 @@
#include "roamer.h"
#include "constants/maps.h"
+// Despite having a variable to track it, the roamer is
+// hard-coded to only ever be in map group 0
+#define ROAMER_MAP_GROUP 0
+
enum
{
- MAP_GRP = 0, // map group
- MAP_NUM = 1, // map number
+ MAP_GRP, // map group
+ MAP_NUM, // map number
};
+#define ROAMER (&gSaveBlock1Ptr->roamer)
EWRAM_DATA static u8 sLocationHistory[3][2] = {0};
EWRAM_DATA static u8 sRoamerLocation[2] = {0};
+#define ___ MAP_NUM(UNDEFINED) // For empty spots in the location table
+
+// Note: There are two potential softlocks that can occur with this table if its maps are
+// changed in particular ways. They can be avoided by ensuring the following:
+// - There must be at least 2 location sets that start with a different map,
+// i.e. every location set cannot start with the same map. This is because of
+// the while loop in RoamerMoveToOtherLocationSet.
+// - Each location set must have at least 3 unique maps. This is because of
+// the while loop in RoamerMove. In this loop the first map in the set is
+// ignored, and an additional map is ignored if the roamer was there recently.
+// - Additionally, while not a softlock, it's worth noting that if for any
+// map in the location table there is not a location set that starts with
+// that map then the roamer will be significantly less likely to move away
+// from that map when it lands there.
static const u8 sRoamerLocations[][6] =
{
- { MAP_NUM(ROUTE110), MAP_NUM(ROUTE111), MAP_NUM(ROUTE117), MAP_NUM(ROUTE118), MAP_NUM(ROUTE134), 0xFF },
- { MAP_NUM(ROUTE111), MAP_NUM(ROUTE110), MAP_NUM(ROUTE117), MAP_NUM(ROUTE118), 0xFF, 0xFF },
- { MAP_NUM(ROUTE117), MAP_NUM(ROUTE111), MAP_NUM(ROUTE110), MAP_NUM(ROUTE118), 0xFF, 0xFF },
+ { MAP_NUM(ROUTE110), MAP_NUM(ROUTE111), MAP_NUM(ROUTE117), MAP_NUM(ROUTE118), MAP_NUM(ROUTE134), ___ },
+ { MAP_NUM(ROUTE111), MAP_NUM(ROUTE110), MAP_NUM(ROUTE117), MAP_NUM(ROUTE118), ___, ___ },
+ { MAP_NUM(ROUTE117), MAP_NUM(ROUTE111), MAP_NUM(ROUTE110), MAP_NUM(ROUTE118), ___, ___ },
{ MAP_NUM(ROUTE118), MAP_NUM(ROUTE117), MAP_NUM(ROUTE110), MAP_NUM(ROUTE111), MAP_NUM(ROUTE119), MAP_NUM(ROUTE123) },
- { MAP_NUM(ROUTE119), MAP_NUM(ROUTE118), MAP_NUM(ROUTE120), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE120), MAP_NUM(ROUTE119), MAP_NUM(ROUTE121), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE121), MAP_NUM(ROUTE120), MAP_NUM(ROUTE122), MAP_NUM(ROUTE123), 0xFF, 0xFF },
- { MAP_NUM(ROUTE122), MAP_NUM(ROUTE121), MAP_NUM(ROUTE123), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE123), MAP_NUM(ROUTE122), MAP_NUM(ROUTE118), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE124), MAP_NUM(ROUTE121), MAP_NUM(ROUTE125), MAP_NUM(ROUTE126), 0xFF, 0xFF },
- { MAP_NUM(ROUTE125), MAP_NUM(ROUTE124), MAP_NUM(ROUTE127), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE126), MAP_NUM(ROUTE124), MAP_NUM(ROUTE127), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE127), MAP_NUM(ROUTE125), MAP_NUM(ROUTE126), MAP_NUM(ROUTE128), 0xFF, 0xFF },
- { MAP_NUM(ROUTE128), MAP_NUM(ROUTE127), MAP_NUM(ROUTE129), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE129), MAP_NUM(ROUTE128), MAP_NUM(ROUTE130), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE130), MAP_NUM(ROUTE129), MAP_NUM(ROUTE131), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE131), MAP_NUM(ROUTE130), MAP_NUM(ROUTE132), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE132), MAP_NUM(ROUTE131), MAP_NUM(ROUTE133), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE133), MAP_NUM(ROUTE132), MAP_NUM(ROUTE134), 0xFF, 0xFF, 0xFF },
- { MAP_NUM(ROUTE134), MAP_NUM(ROUTE133), MAP_NUM(ROUTE110), 0xFF, 0xFF, 0xFF },
- { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { MAP_NUM(ROUTE119), MAP_NUM(ROUTE118), MAP_NUM(ROUTE120), ___, ___, ___ },
+ { MAP_NUM(ROUTE120), MAP_NUM(ROUTE119), MAP_NUM(ROUTE121), ___, ___, ___ },
+ { MAP_NUM(ROUTE121), MAP_NUM(ROUTE120), MAP_NUM(ROUTE122), MAP_NUM(ROUTE123), ___, ___ },
+ { MAP_NUM(ROUTE122), MAP_NUM(ROUTE121), MAP_NUM(ROUTE123), ___, ___, ___ },
+ { MAP_NUM(ROUTE123), MAP_NUM(ROUTE122), MAP_NUM(ROUTE118), ___, ___, ___ },
+ { MAP_NUM(ROUTE124), MAP_NUM(ROUTE121), MAP_NUM(ROUTE125), MAP_NUM(ROUTE126), ___, ___ },
+ { MAP_NUM(ROUTE125), MAP_NUM(ROUTE124), MAP_NUM(ROUTE127), ___, ___, ___ },
+ { MAP_NUM(ROUTE126), MAP_NUM(ROUTE124), MAP_NUM(ROUTE127), ___, ___, ___ },
+ { MAP_NUM(ROUTE127), MAP_NUM(ROUTE125), MAP_NUM(ROUTE126), MAP_NUM(ROUTE128), ___, ___ },
+ { MAP_NUM(ROUTE128), MAP_NUM(ROUTE127), MAP_NUM(ROUTE129), ___, ___, ___ },
+ { MAP_NUM(ROUTE129), MAP_NUM(ROUTE128), MAP_NUM(ROUTE130), ___, ___, ___ },
+ { MAP_NUM(ROUTE130), MAP_NUM(ROUTE129), MAP_NUM(ROUTE131), ___, ___, ___ },
+ { MAP_NUM(ROUTE131), MAP_NUM(ROUTE130), MAP_NUM(ROUTE132), ___, ___, ___ },
+ { MAP_NUM(ROUTE132), MAP_NUM(ROUTE131), MAP_NUM(ROUTE133), ___, ___, ___ },
+ { MAP_NUM(ROUTE133), MAP_NUM(ROUTE132), MAP_NUM(ROUTE134), ___, ___, ___ },
+ { MAP_NUM(ROUTE134), MAP_NUM(ROUTE133), MAP_NUM(ROUTE110), ___, ___, ___ },
+ { ___, ___, ___, ___, ___, ___ },
};
+#undef ___
+#define NUM_LOCATION_SETS (ARRAY_COUNT(sRoamerLocations) - 1)
+#define NUM_LOCATIONS_PER_SET (ARRAY_COUNT(sRoamerLocations[0]))
+
void ClearRoamerData(void)
{
- memset(&gSaveBlock1Ptr->roamer, 0, sizeof(struct Roamer));
- (&gSaveBlock1Ptr->roamer)->species = SPECIES_LATIAS;
+ memset(ROAMER, 0, sizeof(*ROAMER));
+ ROAMER->species = SPECIES_LATIAS;
}
void ClearRoamerLocationData(void)
{
u8 i;
- for (i = 0; i < 3; i++)
+ for (i = 0; i < ARRAY_COUNT(sLocationHistory); i++)
{
sLocationHistory[i][MAP_GRP] = 0;
sLocationHistory[i][MAP_NUM] = 0;
@@ -62,26 +85,27 @@ void ClearRoamerLocationData(void)
static void CreateInitialRoamerMon(bool16 createLatios)
{
if (!createLatios)
- (&gSaveBlock1Ptr->roamer)->species = SPECIES_LATIAS;
+ ROAMER->species = SPECIES_LATIAS;
else
- (&gSaveBlock1Ptr->roamer)->species = SPECIES_LATIOS;
-
- CreateMon(&gEnemyParty[0], (&gSaveBlock1Ptr->roamer)->species, 40, 0x20, 0, 0, OT_ID_PLAYER_ID, 0);
- (&gSaveBlock1Ptr->roamer)->level = 40;
- (&gSaveBlock1Ptr->roamer)->status = 0;
- (&gSaveBlock1Ptr->roamer)->active = TRUE;
- (&gSaveBlock1Ptr->roamer)->ivs = GetMonData(&gEnemyParty[0], MON_DATA_IVS);
- (&gSaveBlock1Ptr->roamer)->personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY);
- (&gSaveBlock1Ptr->roamer)->hp = GetMonData(&gEnemyParty[0], MON_DATA_MAX_HP);
- (&gSaveBlock1Ptr->roamer)->cool = GetMonData(&gEnemyParty[0], MON_DATA_COOL);
- (&gSaveBlock1Ptr->roamer)->beauty = GetMonData(&gEnemyParty[0], MON_DATA_BEAUTY);
- (&gSaveBlock1Ptr->roamer)->cute = GetMonData(&gEnemyParty[0], MON_DATA_CUTE);
- (&gSaveBlock1Ptr->roamer)->smart = GetMonData(&gEnemyParty[0], MON_DATA_SMART);
- (&gSaveBlock1Ptr->roamer)->tough = GetMonData(&gEnemyParty[0], MON_DATA_TOUGH);
- sRoamerLocation[MAP_GRP] = 0;
- sRoamerLocation[MAP_NUM] = sRoamerLocations[Random() % (ARRAY_COUNT(sRoamerLocations) - 1)][0];
+ ROAMER->species = SPECIES_LATIOS;
+
+ CreateMon(&gEnemyParty[0], ROAMER->species, 40, USE_RANDOM_IVS, FALSE, 0, OT_ID_PLAYER_ID, 0);
+ ROAMER->level = 40;
+ ROAMER->status = 0;
+ ROAMER->active = TRUE;
+ ROAMER->ivs = GetMonData(&gEnemyParty[0], MON_DATA_IVS);
+ ROAMER->personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY);
+ ROAMER->hp = GetMonData(&gEnemyParty[0], MON_DATA_MAX_HP);
+ ROAMER->cool = GetMonData(&gEnemyParty[0], MON_DATA_COOL);
+ ROAMER->beauty = GetMonData(&gEnemyParty[0], MON_DATA_BEAUTY);
+ ROAMER->cute = GetMonData(&gEnemyParty[0], MON_DATA_CUTE);
+ ROAMER->smart = GetMonData(&gEnemyParty[0], MON_DATA_SMART);
+ ROAMER->tough = GetMonData(&gEnemyParty[0], MON_DATA_TOUGH);
+ sRoamerLocation[MAP_GRP] = ROAMER_MAP_GROUP;
+ sRoamerLocation[MAP_NUM] = sRoamerLocations[Random() % NUM_LOCATION_SETS][0];
}
+// gSpecialVar_0x8004 here corresponds to the options in the multichoice MULTI_TV_LATI (0 for 'Red', 1 for 'Blue')
void InitRoamer(void)
{
ClearRoamerData();
@@ -104,16 +128,17 @@ void UpdateLocationHistoryForRoamer(void)
void RoamerMoveToOtherLocationSet(void)
{
u8 mapNum = 0;
- struct Roamer *roamer = &gSaveBlock1Ptr->roamer;
-
- if (!roamer->active)
+
+ if (!ROAMER->active)
return;
- sRoamerLocation[MAP_GRP] = 0;
+ sRoamerLocation[MAP_GRP] = ROAMER_MAP_GROUP;
+ // Choose a location set that starts with a map
+ // different from the roamer's current map
while (1)
{
- mapNum = sRoamerLocations[Random() % (ARRAY_COUNT(sRoamerLocations) - 1)][0];
+ mapNum = sRoamerLocations[Random() % NUM_LOCATION_SETS][0];
if (sRoamerLocation[MAP_NUM] != mapNum)
{
sRoamerLocation[MAP_NUM] = mapNum;
@@ -132,20 +157,23 @@ void RoamerMove(void)
}
else
{
- struct Roamer *roamer = &gSaveBlock1Ptr->roamer;
-
- if (!roamer->active)
+ if (!ROAMER->active)
return;
- while (locSet < (ARRAY_COUNT(sRoamerLocations) - 1))
+ while (locSet < NUM_LOCATION_SETS)
{
+ // Find the location set that starts with the roamer's current map
if (sRoamerLocation[MAP_NUM] == sRoamerLocations[locSet][0])
{
u8 mapNum;
while (1)
{
- mapNum = sRoamerLocations[locSet][(Random() % 5) + 1];
- if (!(sLocationHistory[2][MAP_GRP] == 0 && sLocationHistory[2][MAP_NUM] == mapNum) && mapNum != 0xFF)
+ // Choose a new map (excluding the first) within this set
+ // Also exclude a map if the roamer was there 2 moves ago
+ mapNum = sRoamerLocations[locSet][(Random() % (NUM_LOCATIONS_PER_SET - 1)) + 1];
+ if (!(sLocationHistory[2][MAP_GRP] == ROAMER_MAP_GROUP
+ && sLocationHistory[2][MAP_NUM] == mapNum)
+ && mapNum != MAP_NUM(UNDEFINED))
break;
}
sRoamerLocation[MAP_NUM] = mapNum;
@@ -158,9 +186,7 @@ void RoamerMove(void)
bool8 IsRoamerAt(u8 mapGroup, u8 mapNum)
{
- struct Roamer *roamer = &gSaveBlock1Ptr->roamer;
-
- if (roamer->active && mapGroup == sRoamerLocation[MAP_GRP] && mapNum == sRoamerLocation[MAP_NUM])
+ if (ROAMER->active && mapGroup == sRoamerLocation[MAP_GRP] && mapNum == sRoamerLocation[MAP_NUM])
return TRUE;
else
return FALSE;
@@ -168,20 +194,16 @@ bool8 IsRoamerAt(u8 mapGroup, u8 mapNum)
void CreateRoamerMonInstance(void)
{
- struct Pokemon *mon;
- struct Roamer *roamer;
-
- mon = &gEnemyParty[0];
+ struct Pokemon *mon = &gEnemyParty[0];
ZeroEnemyPartyMons();
- roamer = &gSaveBlock1Ptr->roamer;
- CreateMonWithIVsPersonality(mon, roamer->species, roamer->level, roamer->ivs, roamer->personality);
- SetMonData(mon, MON_DATA_STATUS, &gSaveBlock1Ptr->roamer.status);
- SetMonData(mon, MON_DATA_HP, &gSaveBlock1Ptr->roamer.hp);
- SetMonData(mon, MON_DATA_COOL, &gSaveBlock1Ptr->roamer.cool);
- SetMonData(mon, MON_DATA_BEAUTY, &gSaveBlock1Ptr->roamer.beauty);
- SetMonData(mon, MON_DATA_CUTE, &gSaveBlock1Ptr->roamer.cute);
- SetMonData(mon, MON_DATA_SMART, &gSaveBlock1Ptr->roamer.smart);
- SetMonData(mon, MON_DATA_TOUGH, &gSaveBlock1Ptr->roamer.tough);
+ CreateMonWithIVsPersonality(mon, ROAMER->species, ROAMER->level, ROAMER->ivs, ROAMER->personality);
+ SetMonData(mon, MON_DATA_STATUS, &ROAMER->status);
+ SetMonData(mon, MON_DATA_HP, &ROAMER->hp);
+ SetMonData(mon, MON_DATA_COOL, &ROAMER->cool);
+ SetMonData(mon, MON_DATA_BEAUTY, &ROAMER->beauty);
+ SetMonData(mon, MON_DATA_CUTE, &ROAMER->cute);
+ SetMonData(mon, MON_DATA_SMART, &ROAMER->smart);
+ SetMonData(mon, MON_DATA_TOUGH, &ROAMER->tough);
}
bool8 TryStartRoamerEncounter(void)
@@ -199,16 +221,15 @@ bool8 TryStartRoamerEncounter(void)
void UpdateRoamerHPStatus(struct Pokemon *mon)
{
- (&gSaveBlock1Ptr->roamer)->hp = GetMonData(mon, MON_DATA_HP);
- (&gSaveBlock1Ptr->roamer)->status = GetMonData(mon, MON_DATA_STATUS);
+ ROAMER->hp = GetMonData(mon, MON_DATA_HP);
+ ROAMER->status = GetMonData(mon, MON_DATA_STATUS);
RoamerMoveToOtherLocationSet();
}
void SetRoamerInactive(void)
{
- struct Roamer *roamer = &gSaveBlock1Ptr->roamer;
- roamer->active = FALSE;
+ ROAMER->active = FALSE;
}
void GetRoamerLocation(u8 *mapGroup, u8 *mapNum)