Add Time-Based Encounters (#6454)

This commit is contained in:
khbsd 2025-04-09 02:49:09 -05:00 committed by GitHub
parent 2b417bfeed
commit 26f28103ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1391 additions and 113 deletions

View File

@ -171,6 +171,15 @@ LEARNSET_HELPERS_DATA_DIR := $(LEARNSET_HELPERS_DIR)/porymoves_files
LEARNSET_HELPERS_BUILD_DIR := $(LEARNSET_HELPERS_DIR)/build
ALL_LEARNABLES_JSON := $(LEARNSET_HELPERS_BUILD_DIR)/all_learnables.json
# wild_encounters.h is generated by a Python script
WILD_ENCOUNTERS_TOOL_DIR := $(TOOLS_DIR)/wild_encounters
AUTO_GEN_TARGETS += $(DATA_SRC_SUBDIR)/wild_encounters.h
$(DATA_SRC_SUBDIR)/wild_encounters.h: $(DATA_SRC_SUBDIR)/wild_encounters.json $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py $(INCLUDE_DIRS)/config/overworld.h
python3 $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py > $@
$(C_BUILDDIR)/wild_encounter.o: c_dep += $(DATA_SRC_SUBDIR)/wild_encounters.h
PERL := perl
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c

View File

@ -103,9 +103,13 @@
#define GEN_8_PLA GEN_LATEST + 2
//Time
#define OW_TIMES_OF_DAY GEN_LATEST // Different generations have the times of day change at different times.
#define OW_USE_FAKE_RTC FALSE // When TRUE, seconds on the in-game clock will only advance once every 60 playTimeVBlanks (every 60 frames).
#define OW_ALTERED_TIME_RATIO GEN_LATEST // In GEN_8_PLA, the time in game moves forward 60 seconds for every second in the RTC. In GEN_9, it is 20 seconds. This has no effect if OW_USE_FAKE_RTC is FALSE.
#define OW_TIMES_OF_DAY GEN_LATEST // Different generations have the times of day change at different times.
#define OW_USE_FAKE_RTC FALSE // When TRUE, seconds on the in-game clock will only advance once every 60 playTimeVBlanks (every 60 frames).
#define OW_ALTERED_TIME_RATIO GEN_LATEST // In GEN_8_PLA, the time in game moves forward 60 seconds for every second in the RTC. In GEN_9, it is 20 seconds. This has no effect if OW_USE_FAKE_RTC is FALSE.
#define OW_TIME_OF_DAY_ENCOUNTERS FALSE // If TRUE, will allow the user to define and use different encounter tables based on the time of day.
#define OW_TIME_OF_DAY_DISABLE_FALLBACK FALSE // If TRUE, if the encounter table for a specific map and time is empty, the area will have no encounters instead of falling back to the vanilla map and time.
#define OW_TIME_OF_DAY_DEFAULT TIME_MORNING // Should be set to whatever is the first value in the TimeOfDay enum in rtc.h
#define OW_TIME_OF_DAY_FALLBACK OW_TIME_OF_DAY_DEFAULT // The time of day that encounter tables fall back to. Defaults to whatever OW_TIME_OF_DAY_FALLBACK is set to.
// Overworld flags
// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to.

View File

@ -1,6 +1,16 @@
#ifndef GUARD_POKEDEX_AREA_SCREEN_H
#define GUARD_POKEDEX_AREA_SCREEN_H
void ShowPokedexAreaScreen(u16, u8 *);
#include "rtc.h"
extern u8 gAreaTimeOfDay;
enum PokedexAreaScreenState
{
DEX_SHOW_AREA_SCREEN,
DEX_UPDATE_AREA_SCREEN
};
void DisplayPokedexAreaScreen(u16 species, u8 *screenSwitchState, enum TimeOfDay timeOfDay, enum PokedexAreaScreenState areaState);
#endif // GUARD_POKEDEX_AREA_SCREEN_H

View File

@ -1,7 +1,9 @@
#ifndef GUARD_RTC_UTIL_H
#define GUARD_RTC_UTIL_H
#include "global.h"
#include "siirtc.h"
#include "config/overworld.h"
#define RTC_INIT_ERROR 0x0001
#define RTC_INIT_WARNING 0x0002
@ -83,10 +85,17 @@
#define NIGHT_HOUR_END 6
#endif
#define TIME_MORNING 0
#define TIME_DAY 1
#define TIME_EVENING 2
#define TIME_NIGHT 3
// TIMES_OF_DAY_COUNT must be last
enum TimeOfDay
{
TIME_MORNING,
TIME_DAY,
TIME_EVENING,
TIME_NIGHT,
TIMES_OF_DAY_COUNT,
};
STATIC_ASSERT(OW_TIME_OF_DAY_DEFAULT == 0, TimeOfDayDefaultMustBeFirstElementInTimeOfDayEnum)
extern struct Time gLocalTime;
@ -112,12 +121,15 @@ void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day);
void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t);
void RtcCalcLocalTime(void);
bool8 IsBetweenHours(s32 hours, s32 begin, s32 end);
u8 GetTimeOfDay(void);
enum TimeOfDay GetTimeOfDay(void);
enum TimeOfDay GetTimeOfDayForDex(void);
void RtcInitLocalTimeOffset(s32 hour, s32 minute);
void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds);
void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2);
u32 RtcGetMinuteCount(void);
u32 RtcGetLocalDayCount(void);
void FormatDecimalTimeWithoutSeconds(u8 *dest, s8 hour, s8 minute, bool32 is24Hour);
enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay);
enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay);
#endif // GUARD_RTC_UTIL_H

View File

@ -1,8 +1,19 @@
#ifndef GUARD_WILD_ENCOUNTER_H
#define GUARD_WILD_ENCOUNTER_H
#include "rtc.h"
#include "constants/wild_encounter.h"
#define HEADER_NONE 0xFFFF
enum WildPokemonArea {
WILD_AREA_LAND,
WILD_AREA_WATER,
WILD_AREA_ROCKS,
WILD_AREA_FISHING,
WILD_AREA_HIDDEN
};
struct WildPokemon
{
u8 minLevel;
@ -16,17 +27,28 @@ struct WildPokemonInfo
const struct WildPokemon *wildPokemon;
};
struct WildEncounterTypes
{
const struct WildPokemonInfo *landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo;
const struct WildPokemonInfo *rockSmashMonsInfo;
const struct WildPokemonInfo *fishingMonsInfo;
const struct WildPokemonInfo *hiddenMonsInfo;
};
struct WildPokemonHeader
{
u8 mapGroup;
u8 mapNum;
const struct WildPokemonInfo *landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo;
const struct WildPokemonInfo *rockSmashMonsInfo;
const struct WildPokemonInfo *hiddenMonsInfo;
const struct WildPokemonInfo *fishingMonsInfo;
#if OW_TIME_OF_DAY_ENCOUNTERS
const struct WildEncounterTypes encounterTypes[TIMES_OF_DAY_COUNT];
#else
const struct WildEncounterTypes encounterTypes[1];
#endif
};
extern const struct WildPokemonHeader gWildMonHeaders[];
extern bool8 gIsFishingEncounter;
extern bool8 gIsSurfingEncounter;
@ -50,5 +72,6 @@ u8 ChooseWildMonIndex_Land(void);
u8 ChooseWildMonIndex_WaterRock(void);
u8 ChooseHiddenMonIndex(void);
bool32 MapHasNoEncounterData(void);
enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area);
#endif // GUARD_WILD_ENCOUNTER_H

View File

@ -52,6 +52,7 @@ bool32 InitWindows(const struct WindowTemplate *templates);
u32 AddWindow(const struct WindowTemplate *template);
int AddWindowWithoutTileMap(const struct WindowTemplate *template);
void RemoveWindow(u32 windowId);
void RemoveAllWindowsOnBg(u32 bgId);
void FreeAllWindowBuffers(void);
void CopyWindowToVram(u32 windowId, u32 mode);
void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h);

View File

@ -1,12 +1,6 @@
# JSON files are run through jsonproc, which is a tool that converts JSON data to an output file
# based on an Inja template. https://github.com/pantor/inja
AUTO_GEN_TARGETS += $(DATA_SRC_SUBDIR)/wild_encounters.h
$(DATA_SRC_SUBDIR)/wild_encounters.h: $(DATA_SRC_SUBDIR)/wild_encounters.json $(DATA_SRC_SUBDIR)/wild_encounters.json.txt
$(JSONPROC) $^ $@
$(C_BUILDDIR)/wild_encounter.o: c_dep += $(DATA_SRC_SUBDIR)/wild_encounters.h
AUTO_GEN_TARGETS += $(DATA_SRC_SUBDIR)/region_map/region_map_entries.h
$(DATA_SRC_SUBDIR)/region_map/region_map_entries.h: $(DATA_SRC_SUBDIR)/region_map/region_map_sections.json $(DATA_SRC_SUBDIR)/region_map/region_map_sections.json.txt
$(JSONPROC) $^ $@

View File

@ -0,0 +1,97 @@
import json
import sys
import os
"""
- you can change/add to these if you're adding seasons/days of the week, etc
- if you're just adding times of the day, make sure they are in the same order
as the `TimeOfDay` enum in include/rtc.h.
- you don't need to add an entry for `TIMES_OF_DAY_COUNT`
"""
ENCOUNTER_GROUP_SUFFIX = [
"Morning",
"Day",
"Evening",
"Night"
]
ARGS = [
"--copy",
]
"""
- make sure this number is the same as `OW_TIME_OF_DAY_DEFAULT` in config/overworld.h.
- by default in config/overworld.h it is set to `TIME_MORNING`, which is 0 in the
`TimeOfDay` enum in include/rtc.h
"""
OW_TIME_OF_DAY_DEFAULT = 0
def GetWildEncounterFile():
if not os.path.exists("Makefile"):
print("Please run this script from the project's root folder.")
quit()
wFile = open("src/data/wild_encounters.json")
wData = json.load(wFile)
wBackupData = json.dumps(wData, indent=2)
wBackupFile = open("src/data/wild_encounters.json.bak", mode="w", encoding="utf-8")
wBackupFile.write(wBackupData)
global COPY_FULL_ENCOUNTER
COPY_FULL_ENCOUNTER = False
for arg in ARGS:
if len(sys.argv) > 1:
if arg in sys.argv[1:3]:
if arg == ARGS[0]:
COPY_FULL_ENCOUNTER = True
j = 0
for group in wData["wild_encounter_groups"]:
wEncounters = wData["wild_encounter_groups"][j]["encounters"]
editMap = True
wEncounters_New = list()
for map in wEncounters:
for suffix in ENCOUNTER_GROUP_SUFFIX:
tempSuffix = "_" + suffix
if tempSuffix in map["base_label"]:
editMap = False
break
else:
editMap = True
if editMap:
k = 0
for suffix in ENCOUNTER_GROUP_SUFFIX:
tempDict = dict()
if k == OW_TIME_OF_DAY_DEFAULT or COPY_FULL_ENCOUNTER:
tempDict = map.copy()
tempMapLabel = ""
if "map" in map:
tempMapLabel = map["map"]
tempDict["map"] = tempMapLabel
tempLabel = map["base_label"] + "_" + suffix
tempDict["base_label"] = tempLabel
wEncounters_New.append(tempDict)
if map["base_label"] in wEncounters_New:
wEncounters_New[map["base_label"]].pop()
print(tempLabel + " added")
k += 1
else:
wEncounters_New.append(map.copy())
wData["wild_encounter_groups"][j]["encounters"] = wEncounters_New
j += 1
wNewData = json.dumps(wData, indent=2)
wNewFile = open("src/data/wild_encounters.json", mode="w", encoding="utf-8")
wNewFile.write(wNewData)
GetWildEncounterFile()

View File

@ -36,6 +36,7 @@
#include "pokemon_summary_screen.h"
#include "random.h"
#include "region_map.h"
#include "rtc.h"
#include "scanline_effect.h"
#include "script.h"
#include "script_pokemon_util.h"
@ -1515,10 +1516,8 @@ static u8 DexNavGeneratePotential(u8 searchLevel)
static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
const struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
const struct WildPokemonInfo *hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay;
u8 min = 100;
u8 max = 0;
u8 i;
@ -1526,6 +1525,9 @@ static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
switch (environment)
{
case ENCOUNTER_TYPE_LAND: // grass
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
const struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
if (landMonsInfo == NULL)
return MON_LEVEL_NONEXISTENT; //Hidden pokemon should only appear on walkable tiles or surf tiles
@ -1539,6 +1541,9 @@ static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
}
break;
case ENCOUNTER_TYPE_WATER: //water
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
if (waterMonsInfo == NULL)
return MON_LEVEL_NONEXISTENT; //Hidden pokemon should only appear on walkable tiles or surf tiles
@ -1552,6 +1557,9 @@ static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
}
break;
case ENCOUNTER_TYPE_HIDDEN:
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo *hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
if (hiddenMonsInfo == NULL)
return MON_LEVEL_NONEXISTENT;
@ -1724,11 +1732,13 @@ static void CreateNoDataIcon(s16 x, s16 y)
CreateSprite(&sNoDataIconTemplate, x, y, 0);
}
static bool8 CapturedAllLandMons(u16 headerId)
static bool8 CapturedAllLandMons(u32 headerId)
{
u16 i, species;
int count = 0;
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
if (landMonsInfo != NULL)
{
@ -1756,12 +1766,14 @@ static bool8 CapturedAllLandMons(u16 headerId)
}
//Checks if all Pokemon that can be encountered while surfing have been capture
static bool8 CapturedAllWaterMons(u16 headerId)
static bool8 CapturedAllWaterMons(u32 headerId)
{
u32 i;
u16 species;
u8 count = 0;
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
if (waterMonsInfo != NULL)
{
@ -1787,13 +1799,15 @@ static bool8 CapturedAllWaterMons(u16 headerId)
return FALSE;
}
static bool8 CapturedAllHiddenMons(u16 headerId)
static bool8 CapturedAllHiddenMons(u32 headerId)
{
u32 i;
u16 species;
u8 count = 0;
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
if (hiddenMonsInfo != NULL)
{
for (i = 0; i < HIDDEN_WILD_COUNT; ++i)
@ -1820,7 +1834,7 @@ static bool8 CapturedAllHiddenMons(u16 headerId)
static void DexNavLoadCapturedAllSymbols(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
u32 headerId = GetCurrentMapWildMonHeaderId();
LoadCompressedSpriteSheetUsingHeap(&sCapturedAllPokemonSpriteSheet);
@ -1936,11 +1950,16 @@ static void DexNavLoadEncounterData(void)
u8 hiddenIndex = 0;
u16 species;
u32 i;
u16 headerId = GetCurrentMapWildMonHeaderId();
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
// nop struct data
memset(sDexNavUiDataPtr->landSpecies, 0, sizeof(sDexNavUiDataPtr->landSpecies));
memset(sDexNavUiDataPtr->waterSpecies, 0, sizeof(sDexNavUiDataPtr->waterSpecies));
@ -2509,12 +2528,14 @@ bool8 TryFindHiddenPokemon(void)
if ((*stepPtr) == 0 && (Random() % 100 < HIDDEN_MON_SEARCH_RATE))
{
// hidden pokemon
u16 headerId = GetCurrentMapWildMonHeaderId();
u32 headerId = GetCurrentMapWildMonHeaderId();
u8 index;
u16 species;
u8 environment;
u8 taskId;
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
bool8 isHiddenMon = FALSE;
// while you can still technically find hidden pokemon if there are not hidden-only pokemon on a map,
@ -2539,7 +2560,7 @@ bool8 TryFindHiddenPokemon(void)
}
else
{
species = gWildMonHeaders[headerId].landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species;
species = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species;
environment = ENCOUNTER_TYPE_LAND;
}
break;
@ -2557,7 +2578,7 @@ bool8 TryFindHiddenPokemon(void)
}
else
{
species = gWildMonHeaders[headerId].waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
species = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
environment = ENCOUNTER_TYPE_WATER;
}

View File

@ -1752,6 +1752,7 @@ static void PopulateSpeciesFromTrainerLocation(int matchCallId, u8 *destStr)
int numSpecies;
u8 slot;
int i = 0;
enum TimeOfDay timeOfDay;
if (gWildMonHeaders[i].mapGroup != MAP_GROUP(UNDEFINED)) // ??? This check is nonsense.
{
@ -1766,18 +1767,20 @@ static void PopulateSpeciesFromTrainerLocation(int matchCallId, u8 *destStr)
if (gWildMonHeaders[i].mapGroup != MAP_GROUP(UNDEFINED))
{
timeOfDay = GetTimeOfDayForEncounters(i, WILD_AREA_LAND);
numSpecies = 0;
if (gWildMonHeaders[i].landMonsInfo)
if (gWildMonHeaders[i].encounterTypes[timeOfDay].landMonsInfo)
{
slot = GetLandEncounterSlot();
species[numSpecies] = gWildMonHeaders[i].landMonsInfo->wildPokemon[slot].species;
species[numSpecies] = gWildMonHeaders[i].encounterTypes[timeOfDay].landMonsInfo->wildPokemon[slot].species;
numSpecies++;
}
if (gWildMonHeaders[i].waterMonsInfo)
timeOfDay = GetTimeOfDayForEncounters(i, WILD_AREA_WATER);
if (gWildMonHeaders[i].encounterTypes[timeOfDay].waterMonsInfo)
{
slot = GetWaterEncounterSlot();
species[numSpecies] = gWildMonHeaders[i].waterMonsInfo->wildPokemon[slot].species;
species[numSpecies] = gWildMonHeaders[i].encounterTypes[timeOfDay].waterMonsInfo->wildPokemon[slot].species;
numSpecies++;
}

View File

@ -17,6 +17,7 @@
#include "pokedex_area_screen.h"
#include "pokedex_cry_screen.h"
#include "pokedex_plus_hgss.h"
#include "rtc.h"
#include "scanline_effect.h"
#include "sound.h"
#include "sprite.h"
@ -255,7 +256,8 @@ static void Task_HandleInfoScreenInput(u8);
static void Task_SwitchScreensFromInfoScreen(u8);
static void Task_LoadInfoScreenWaitForFade(u8);
static void Task_ExitInfoScreen(u8);
static void Task_LoadAreaScreen(u8);
static void Task_LoadAreaScreen(u8 taskId);
static void Task_ReloadAreaScreen(u8 taskId);
static void Task_WaitForAreaScreenInput(u8 taskId);
static void Task_SwitchScreensFromAreaScreen(u8);
static void Task_LoadCryScreen(u8);
@ -3245,6 +3247,7 @@ static u8 LoadInfoScreen(struct PokedexListItem *item, u8 monSpriteId)
u8 taskId;
sPokedexListItem = item;
gAreaTimeOfDay = GetTimeOfDayForDex();
taskId = CreateTask(Task_LoadInfoScreen, 0);
gTasks[taskId].tScrolling = FALSE;
gTasks[taskId].tMonSpriteDone = TRUE; // Already has sprite from list view
@ -3552,7 +3555,7 @@ static void Task_LoadAreaScreen(u8 taskId)
gMain.state++;
break;
case 2:
ShowPokedexAreaScreen(NationalPokedexNumToSpecies(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState);
DisplayPokedexAreaScreen(NationalPokedexNumToSpecies(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState, gAreaTimeOfDay, DEX_SHOW_AREA_SCREEN);
SetVBlankCallback(gPokedexVBlankCB);
sPokedexView->screenSwitchState = 0;
gMain.state = 0;
@ -3561,6 +3564,29 @@ static void Task_LoadAreaScreen(u8 taskId)
}
}
static void Task_ReloadAreaScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
sPokedexView->currentPage = PAGE_AREA;
gMain.state = 1;
break;
case 1:
LoadPokedexBgPalette(sPokedexView->isSearchResults);
SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(13) | BGCNT_16COLOR | BGCNT_TXT256x256);
gMain.state++;
break;
case 2:
DisplayPokedexAreaScreen(NationalPokedexNumToSpecies(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState, gAreaTimeOfDay, DEX_UPDATE_AREA_SCREEN);
gMain.state = 0;
gTasks[taskId].func = Task_WaitForAreaScreenInput;
break;
}
}
static void Task_WaitForAreaScreenInput(u8 taskId)
{
// See Task_HandlePokedexAreaScreenInput() in pokedex_area_screen.c
@ -3581,6 +3607,9 @@ static void Task_SwitchScreensFromAreaScreen(u8 taskId)
case 2:
gTasks[taskId].func = Task_LoadCryScreen;
break;
case 3:
gTasks[taskId].func = Task_ReloadAreaScreen;
break;
}
}
}

View File

@ -3,6 +3,7 @@
#include "event_data.h"
#include "gpu_regs.h"
#include "graphics.h"
#include "international_string_util.h"
#include "main.h"
#include "malloc.h"
#include "menu.h"
@ -12,11 +13,15 @@
#include "pokedex_area_screen.h"
#include "region_map.h"
#include "roamer.h"
#include "rtc.h"
#include "sound.h"
#include "string_util.h"
#include "text.h"
#include "text_window.h"
#include "trig.h"
#include "pokedex_area_region_map.h"
#include "wild_encounter.h"
#include "window.h"
#include "constants/region_map_sections.h"
#include "constants/rgb.h"
#include "constants/songs.h"
@ -55,6 +60,15 @@
#define MAX_AREA_HIGHLIGHTS 64 // Maximum number of rectangular route highlights
#define MAX_AREA_MARKERS 32 // Maximum number of circular spot highlights
#define LABEL_WINDOW_BG 1
#define NUM_LABEL_WINDOWS 2
enum PokedexAreaLabels
{
DEX_AREA_LABEL_TIME_OF_DAY,
DEX_AREA_LABEL_AREA_UNKNOWN
};
struct OverworldArea
{
u8 mapGroup;
@ -90,28 +104,41 @@ struct
/*0xF70*/ u8 charBuffer[64];
/*0xFB0*/ struct Sprite * areaUnknownSprites[3];
/*0xFBC*/ u8 areaUnknownGraphicsBuffer[0x600];
/*0xFC0*/ u8 areaScreenLabelIds[NUM_LABEL_WINDOWS];
/*0xFC8*/ u8 areaState;
} static EWRAM_DATA *sPokedexAreaScreen = NULL;
EWRAM_DATA u8 gAreaTimeOfDay = 0;
static void FindMapsWithMon(u16);
static void BuildAreaGlowTilemap(void);
static void SetAreaHasMon(u16, u16);
static void SetSpecialMapHasMon(u16, u16);
static u16 GetRegionMapSectionId(u8, u8);
static bool8 MapHasSpecies(const struct WildPokemonHeader *, u16);
static bool8 MapHasSpecies(const struct WildEncounterTypes *, u16);
static bool8 MonListHasSpecies(const struct WildPokemonInfo *, u16, u16);
static void DoAreaGlow(void);
static void Task_ShowPokedexAreaScreen(u8);
static void Task_ShowPokedexAreaScreen(u8 taskId);
static void Task_UpdatePokedexAreaScreen(u8 taskId);
static void CreateAreaMarkerSprites(void);
static void LoadAreaUnknownGraphics(void);
static void CreateAreaUnknownSprites(void);
static void Task_HandlePokedexAreaScreenInput(u8);
static void ResetPokedexAreaMapBg(void);
static void DestroyAreaScreenSprites(void);
static void LoadHGSSScreenSelectBarSubmenu(void);
static void AddTimeOfDayLabels(void);
static void ShowEncounterInfoLabel(void);
static void ShowAreaUnknownLabel(void);
static void PrintAreaLabelText(const u8 *text, enum PokedexAreaLabels labelId, int textXPos);
static void ClearAreaWindowLabel(enum PokedexAreaLabels labelId);
bool32 ShouldShowAreaUnknownLabel(void);
static const u32 sAreaGlow_Pal[] = INCBIN_U32("graphics/pokedex/area_glow.gbapal");
static const u32 sAreaGlow_Gfx[] = INCBIN_U32("graphics/pokedex/area_glow.4bpp.lz");
static const u32 sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/SelectBar.bin.lz");
static void LoadHGSSScreenSelectBarSubmenu(void);
static const u16 sSpeciesHiddenFromAreaScreen[] = { SPECIES_WYNAUT };
@ -205,6 +232,32 @@ static const struct SpriteTemplate sAreaUnknownSpriteTemplate =
.callback = SpriteCallbackDummy
};
static const u8 sFontColor_AreaInfo[3] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, 5};
static const struct WindowTemplate sTimeOfDayWindowLabelTemplates[] =
{
[DEX_AREA_LABEL_TIME_OF_DAY] =
{
.bg = LABEL_WINDOW_BG,
.tilemapLeft = 22,
.tilemapTop = 18,
.width = 8,
.height = 2,
.paletteNum = 0,
.baseBlock = 0x16C
},
[DEX_AREA_LABEL_AREA_UNKNOWN] =
{
.bg = LABEL_WINDOW_BG,
.tilemapLeft = 12,
.tilemapTop = 18,
.width = 10,
.height = 2,
.paletteNum = 0,
.baseBlock = 0x240
}
};
static void ResetDrawAreaGlowState(void)
{
sPokedexAreaScreen->drawAreaGlowState = 0;
@ -287,7 +340,7 @@ static void FindMapsWithMon(u16 species)
// Add regular species to the area map
for (i = 0; gWildMonHeaders[i].mapGroup != MAP_GROUP(UNDEFINED); i++)
{
if (MapHasSpecies(&gWildMonHeaders[i], species))
if (MapHasSpecies(&gWildMonHeaders[i].encounterTypes[gAreaTimeOfDay], species))
{
switch (gWildMonHeaders[i].mapGroup)
{
@ -373,10 +426,13 @@ static u16 GetRegionMapSectionId(u8 mapGroup, u8 mapNum)
return Overworld_GetMapHeaderByGroupAndId(mapGroup, mapNum)->regionMapSectionId;
}
static bool8 MapHasSpecies(const struct WildPokemonHeader *info, u16 species)
static bool8 MapHasSpecies(const struct WildEncounterTypes *info, u16 species)
{
u32 headerId = GetCurrentMapWildMonHeaderId();
u8 currentMapGroup = gWildMonHeaders[headerId].mapGroup;
u8 currentMapNum = gWildMonHeaders[headerId].mapNum;
// If this is a header for Altering Cave, skip it if it's not the current Altering Cave encounter set
if (GetRegionMapSectionId(info->mapGroup, info->mapNum) == MAPSEC_ALTERING_CAVE)
if (GetRegionMapSectionId(currentMapGroup, currentMapNum) == MAPSEC_ALTERING_CAVE)
{
sPokedexAreaScreen->alteringCaveCounter++;
if (sPokedexAreaScreen->alteringCaveCounter != sPokedexAreaScreen->alteringCaveId + 1)
@ -576,17 +632,98 @@ static void DoAreaGlow(void)
}
}
static const u8 *GetTimeOfDayTextWithButton(enum TimeOfDay timeOfDay)
{
static const u8 gText_Morning[] = _("{DPAD_UPDOWN} MORNING");
static const u8 gText_Day[] = _("{DPAD_UPDOWN} DAY");
static const u8 gText_Evening[] = _("{DPAD_UPDOWN} EVENING");
static const u8 gText_Night[] = _("{DPAD_UPDOWN} NIGHT");
switch (gAreaTimeOfDay)
{
case TIME_MORNING:
return gText_Morning;
case TIME_EVENING:
return gText_Evening;
case TIME_NIGHT:
return gText_Night;
case TIME_DAY:
default:
return gText_Day;
}
}
static void AddTimeOfDayLabels(void)
{
u32 i;
// clear the background before adding any more windows
RemoveAllWindowsOnBg(LABEL_WINDOW_BG);
for (i = 0; i < NUM_LABEL_WINDOWS; i ++)
{
sPokedexAreaScreen->areaScreenLabelIds[i] = AddWindow(&sTimeOfDayWindowLabelTemplates[i]);
FillWindowPixelBuffer(sPokedexAreaScreen->areaScreenLabelIds[i], PIXEL_FILL(0));
}
}
static void ShowEncounterInfoLabel(void)
{
const u8 *gText_TimeOfDay = GetTimeOfDayTextWithButton(gAreaTimeOfDay);
int stringXPos = GetStringCenterAlignXOffset(FONT_NORMAL, gText_TimeOfDay, 64);
PrintAreaLabelText(gText_TimeOfDay, DEX_AREA_LABEL_TIME_OF_DAY, stringXPos);
}
static void ShowAreaUnknownLabel(void)
{
static const u8 gText_AreaUnknown[] = _("AREA UNKNOWN");
int stringXPos = GetStringCenterAlignXOffset(FONT_NORMAL, gText_AreaUnknown, 80);
PrintAreaLabelText(gText_AreaUnknown, DEX_AREA_LABEL_AREA_UNKNOWN, stringXPos);
}
static void ClearAreaWindowLabel(enum PokedexAreaLabels labelId)
{
FillWindowPixelBuffer(sPokedexAreaScreen->areaScreenLabelIds[labelId], PIXEL_FILL(0));
ClearWindowTilemap(sPokedexAreaScreen->areaScreenLabelIds[labelId]);
ScheduleBgCopyTilemapToVram(0);
}
static void PrintAreaLabelText(const u8 *text, enum PokedexAreaLabels labelId, int textXPos)
{
ClearAreaWindowLabel(labelId);
PutWindowTilemap(sPokedexAreaScreen->areaScreenLabelIds[labelId]);
FillWindowPixelBuffer(sPokedexAreaScreen->areaScreenLabelIds[labelId], PIXEL_FILL(7));
AddTextPrinterParameterized4(sPokedexAreaScreen->areaScreenLabelIds[labelId], FONT_NORMAL, textXPos, 0, 0, 0, sFontColor_AreaInfo, TEXT_SKIP_DRAW, text);
CopyWindowToVram(sPokedexAreaScreen->areaScreenLabelIds[labelId], COPYWIN_FULL);
}
bool32 ShouldShowAreaUnknownLabel(void)
{
return !sPokedexAreaScreen->numOverworldAreas && !sPokedexAreaScreen->numSpecialAreas;
}
#define tState data[0]
void ShowPokedexAreaScreen(u16 species, u8 *screenSwitchState)
void DisplayPokedexAreaScreen(u16 species, u8 *screenSwitchState, enum TimeOfDay timeOfDay, enum PokedexAreaScreenState areaState)
{
u8 taskId;
sPokedexAreaScreen = AllocZeroed(sizeof(*sPokedexAreaScreen));
sPokedexAreaScreen->species = species;
sPokedexAreaScreen->screenSwitchState = screenSwitchState;
sPokedexAreaScreen->areaState = areaState;
gAreaTimeOfDay = timeOfDay;
screenSwitchState[0] = 0;
taskId = CreateTask(Task_ShowPokedexAreaScreen, 0);
if (sPokedexAreaScreen->areaState == DEX_UPDATE_AREA_SCREEN)
taskId = CreateTask(Task_UpdatePokedexAreaScreen, 0);
else
taskId = CreateTask(Task_ShowPokedexAreaScreen, 0);
gTasks[taskId].tState = 0;
}
@ -627,20 +764,29 @@ static void Task_ShowPokedexAreaScreen(u8 taskId)
CreateAreaMarkerSprites();
break;
case 7:
LoadAreaUnknownGraphics();
if(!OW_TIME_OF_DAY_ENCOUNTERS)
LoadAreaUnknownGraphics();
break;
case 8:
CreateAreaUnknownSprites();
if(!OW_TIME_OF_DAY_ENCOUNTERS)
CreateAreaUnknownSprites();
break;
case 9:
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 16, 0, RGB_BLACK);
break;
case 10:
if (POKEDEX_PLUS_HGSS)
LoadHGSSScreenSelectBarSubmenu();
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_ALL);
StartAreaGlow();
if (OW_TIME_OF_DAY_ENCOUNTERS)
{
AddTimeOfDayLabels();
ShowEncounterInfoLabel();
if (ShouldShowAreaUnknownLabel())
ShowAreaUnknownLabel();
DoScheduledBgTilemapCopiesToVram();
}
if (POKEDEX_PLUS_HGSS)
LoadHGSSScreenSelectBarSubmenu();
ShowBg(2);
ShowBg(3); // TryShowPokedexAreaMap will have done this already
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON);
@ -654,6 +800,58 @@ static void Task_ShowPokedexAreaScreen(u8 taskId)
gTasks[taskId].tState++;
}
static void Task_UpdatePokedexAreaScreen(u8 taskId)
{
switch (gTasks[taskId].tState)
{
case 0:
ClearAreaWindowLabel(DEX_AREA_LABEL_TIME_OF_DAY);
ClearAreaWindowLabel(DEX_AREA_LABEL_AREA_UNKNOWN);
ResetSpriteData();
FreeAllSpritePalettes();
ResetDrawAreaGlowState();
HideBg(2);
HideBg(0);
break;
case 1:
SetBgAttribute(3, BG_ATTR_CHARBASEINDEX, 3);
LoadPokedexAreaMapGfx(&sPokedexAreaMapTemplate);
PokedexAreaMapChangeBgY(-8);
StringFill(sPokedexAreaScreen->charBuffer, CHAR_SPACE, 16);
break;
case 2:
if (TryShowPokedexAreaMap() == TRUE)
return;
break;
case 3:
if (DrawAreaGlow())
return;
break;
case 4:
ShowRegionMapForPokedexAreaScreen(&sPokedexAreaScreen->regionMap);
CreateRegionMapPlayerIcon(1, 1);
PokedexAreaScreen_UpdateRegionMapVariablesAndVideoRegs(0, -8);
CreateAreaMarkerSprites();
break;
case 5:
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_ALL);
StartAreaGlow();
AddTimeOfDayLabels();
ShowEncounterInfoLabel();
if (ShouldShowAreaUnknownLabel())
ShowAreaUnknownLabel();
ShowBg(2);
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON);
break;
case 6:
gTasks[taskId].func = Task_HandlePokedexAreaScreenInput;
gTasks[taskId].tState = 0;
return;
}
gTasks[taskId].tState++;
}
static void Task_HandlePokedexAreaScreenInput(u8 taskId)
{
DoAreaGlow();
@ -687,16 +885,42 @@ static void Task_HandlePokedexAreaScreenInput(u8 taskId)
gTasks[taskId].data[1] = 2;
PlaySE(SE_DEX_PAGE);
}
else if (JOY_NEW(DPAD_UP) && OW_TIME_OF_DAY_ENCOUNTERS == TRUE)
{
gTasks[taskId].data[1] = 3;
gAreaTimeOfDay = TryDecrementTimeOfDay(gAreaTimeOfDay);
sPokedexAreaScreen->areaState = DEX_UPDATE_AREA_SCREEN;
PlaySE(SE_DEX_PAGE);
}
else if (JOY_NEW(DPAD_DOWN) && OW_TIME_OF_DAY_ENCOUNTERS == TRUE)
{
gTasks[taskId].data[1] = 3;
gAreaTimeOfDay = TryIncrementTimeOfDay(gAreaTimeOfDay);
sPokedexAreaScreen->areaState = DEX_UPDATE_AREA_SCREEN;
PlaySE(SE_DEX_PAGE);
}
else
{
// screen needs to fade if its doing anything except updating the area screen
sPokedexAreaScreen->areaState = DEX_SHOW_AREA_SCREEN;
return;
}
break;
case 2:
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 16, RGB_BLACK);
if (sPokedexAreaScreen->areaState != DEX_UPDATE_AREA_SCREEN)
BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 0, 16, RGB_BLACK);
break;
case 3:
if (gPaletteFade.active)
return;
DestroyAreaScreenSprites();
if (OW_TIME_OF_DAY_ENCOUNTERS)
{
ClearAreaWindowLabel(DEX_AREA_LABEL_TIME_OF_DAY);
ClearAreaWindowLabel(DEX_AREA_LABEL_AREA_UNKNOWN);
RemoveAllWindowsOnBg(LABEL_WINDOW_BG);
}
sPokedexAreaScreen->screenSwitchState[0] = gTasks[taskId].data[1];
ResetPokedexAreaMapBg();
DestroyTask(taskId);
@ -755,13 +979,16 @@ static void DestroyAreaScreenSprites(void)
for (i = 0; i < sPokedexAreaScreen->numAreaMarkerSprites; i++)
DestroySprite(sPokedexAreaScreen->areaMarkerSprites[i]);
// Destroy "Area Unknown" sprites
FreeSpriteTilesByTag(TAG_AREA_UNKNOWN);
FreeSpritePaletteByTag(TAG_AREA_UNKNOWN);
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaUnknownSprites); i++)
if (!OW_TIME_OF_DAY_ENCOUNTERS)
{
if (sPokedexAreaScreen->areaUnknownSprites[i])
DestroySprite(sPokedexAreaScreen->areaUnknownSprites[i]);
// Destroy "Area Unknown" sprites
FreeSpriteTilesByTag(TAG_AREA_UNKNOWN);
FreeSpritePaletteByTag(TAG_AREA_UNKNOWN);
for (i = 0; i < ARRAY_COUNT(sPokedexAreaScreen->areaUnknownSprites); i++)
{
if (sPokedexAreaScreen->areaUnknownSprites[i])
DestroySprite(sPokedexAreaScreen->areaUnknownSprites[i]);
}
}
}

View File

@ -28,6 +28,7 @@
#include "region_map.h"
#include "pokemon.h"
#include "reset_rtc_screen.h"
#include "rtc.h"
#include "scanline_effect.h"
#include "shop.h"
#include "sound.h"
@ -526,7 +527,8 @@ static void Task_HandleInfoScreenInput(u8);
static void Task_SwitchScreensFromInfoScreen(u8);
static void Task_LoadInfoScreenWaitForFade(u8);
static void Task_ExitInfoScreen(u8);
static void Task_LoadAreaScreen(u8);
static void Task_LoadAreaScreen(u8 taskId);
static void Task_ReloadAreaScreen(u8 taskId);
static void Task_WaitForAreaScreenInput(u8 taskId);
static void Task_SwitchScreensFromAreaScreen(u8);
static void Task_LoadCryScreen(u8);
@ -3736,6 +3738,7 @@ static u8 LoadInfoScreen(struct PokedexListItem *item, u8 monSpriteId)
u8 taskId;
sPokedexListItem = item;
gAreaTimeOfDay = GetTimeOfDayForDex();
taskId = CreateTask(Task_LoadInfoScreen, 0);
gTasks[taskId].tScrolling = FALSE;
gTasks[taskId].tMonSpriteDone = TRUE; // Already has sprite from list view
@ -3994,7 +3997,7 @@ static void Task_LoadAreaScreen(u8 taskId)
gMain.state++;
break;
case 2:
ShowPokedexAreaScreen(NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState);
DisplayPokedexAreaScreen(NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState, gAreaTimeOfDay, DEX_SHOW_AREA_SCREEN);
SetVBlankCallback(gPokedexVBlankCB);
sPokedexView->screenSwitchState = 0;
gMain.state = 0;
@ -4003,6 +4006,28 @@ static void Task_LoadAreaScreen(u8 taskId)
}
}
static void Task_ReloadAreaScreen(u8 taskId)
{
switch (gMain.state)
{
case 0:
default:
sPokedexView->currentPage = PAGE_AREA;
gMain.state = 1;
break;
case 1:
LoadPokedexBgPalette(sPokedexView->isSearchResults);
SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(13) | BGCNT_16COLOR | BGCNT_TXT256x256);
gMain.state++;
break;
case 2:
DisplayPokedexAreaScreen(NationalPokedexNumToSpeciesHGSS(sPokedexListItem->dexNum), &sPokedexView->screenSwitchState, gAreaTimeOfDay, DEX_UPDATE_AREA_SCREEN);
gMain.state = 0;
gTasks[taskId].func = Task_WaitForAreaScreenInput;
break;
}
}
static void Task_WaitForAreaScreenInput(u8 taskId)
{
// See Task_HandlePokedexAreaScreenInput() in pokedex_area_screen.c
@ -4026,6 +4051,9 @@ static void Task_SwitchScreensFromAreaScreen(u8 taskId)
else
gTasks[taskId].func = Task_LoadStatsScreen;
break;
case 3:
gTasks[taskId].func = Task_ReloadAreaScreen;
break;
}
}
}

View File

@ -1,4 +1,6 @@
#include "global.h"
#include "battle_pike.h"
#include "battle_pyramid.h"
#include "rtc.h"
#include "string_util.h"
#include "strings.h"
@ -325,7 +327,7 @@ bool8 IsBetweenHours(s32 hours, s32 begin, s32 end)
return hours >= begin && hours < end;
}
u8 GetTimeOfDay(void)
enum TimeOfDay GetTimeOfDay(void)
{
RtcCalcLocalTime();
if (IsBetweenHours(gLocalTime.hours, MORNING_HOUR_BEGIN, MORNING_HOUR_END))
@ -337,6 +339,11 @@ u8 GetTimeOfDay(void)
return TIME_DAY;
}
enum TimeOfDay GetTimeOfDayForDex(void)
{
return OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : OW_TIME_OF_DAY_DEFAULT;
}
void RtcInitLocalTimeOffset(s32 hour, s32 minute)
{
RtcCalcLocalTimeOffset(0, hour, minute, 0);
@ -418,3 +425,13 @@ void FormatDecimalTimeWithoutSeconds(u8 *txtPtr, s8 hour, s8 minute, bool32 is24
*txtPtr++ = EOS;
*txtPtr = EOS;
}
enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay)
{
return timeOfDay == TIME_NIGHT ? TIME_MORNING : timeOfDay + 1;
}
enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay)
{
return timeOfDay == TIME_MORNING ? TIME_NIGHT : timeOfDay - 1;
}

View File

@ -37,25 +37,16 @@ extern const u8 EventScript_SprayWoreOff[];
#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)
#define HEADER_NONE 0xFFFF
static u16 FeebasRandom(void);
static void FeebasSeedRng(u16 seed);
static void UpdateChainFishingStreak();
static bool8 IsWildLevelAllowedByRepel(u8 level);
static void ApplyFluteEncounterRateMod(u32 *encRate);
static void ApplyCleanseTagEncounterRateMod(u32 *encRate);
static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 species, u8 area);
static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 species, enum WildPokemonArea area);
#ifdef BUGFIX
static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u16 ability, u8 *monIndex, u32 size);
#else
@ -305,7 +296,7 @@ static u8 ChooseWildMonIndex_Fishing(u8 rod)
return wildMonIndex;
}
static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIndex, u8 area)
static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIndex, enum WildPokemonArea area)
{
u8 min;
u8 max;
@ -384,6 +375,87 @@ u16 GetCurrentMapWildMonHeaderId(void)
return HEADER_NONE;
}
enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area)
{
const struct WildPokemonInfo *wildMonInfo;
enum TimeOfDay timeOfDay = GetTimeOfDay();
if (!OW_TIME_OF_DAY_ENCOUNTERS)
return OW_TIME_OF_DAY_DEFAULT;
if (InBattlePike())
{
switch (area)
{
default:
case WILD_AREA_LAND:
wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
break;
case WILD_AREA_WATER:
wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
break;
case WILD_AREA_ROCKS:
wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo;
break;
case WILD_AREA_FISHING:
wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo;
break;
case WILD_AREA_HIDDEN:
wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
break;
}
}
else if (InBattlePyramid())
{
switch (area)
{
default:
case WILD_AREA_LAND:
wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
break;
case WILD_AREA_WATER:
wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
break;
case WILD_AREA_ROCKS:
wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo;
break;
case WILD_AREA_FISHING:
wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo;
break;
case WILD_AREA_HIDDEN:
wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
break;
}
}
else
{
switch (area)
{
default:
case WILD_AREA_LAND:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
break;
case WILD_AREA_WATER:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
break;
case WILD_AREA_ROCKS:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo;
break;
case WILD_AREA_FISHING:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo;
break;
case WILD_AREA_HIDDEN:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
break;
}
}
if (wildMonInfo == NULL && !OW_TIME_OF_DAY_DISABLE_FALLBACK)
return OW_TIME_OF_DAY_FALLBACK;
else
return timeOfDay;
}
u8 PickWildMonNature(void)
{
u8 i;
@ -459,7 +531,7 @@ void CreateWildMon(u16 species, u8 level)
#define TRY_GET_ABILITY_INFLUENCED_WILD_MON_INDEX(wildPokemon, type, ability, ptr, count) TryGetAbilityInfluencedWildMonIndex(wildPokemon, type, ability, ptr)
#endif
static bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, u8 area, u8 flags)
static bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, enum WildPokemonArea area, u8 flags)
{
u8 wildMonIndex = 0;
u8 level;
@ -501,6 +573,10 @@ static bool8 TryGenerateWildMon(const struct WildPokemonInfo *wildMonInfo, u8 ar
case WILD_AREA_ROCKS:
wildMonIndex = ChooseWildMonIndex_WaterRock();
break;
default:
case WILD_AREA_FISHING:
case WILD_AREA_HIDDEN:
break;
}
level = ChooseWildMonLevel(wildMonInfo->wildPokemon, wildMonIndex, area);
@ -621,7 +697,8 @@ static bool8 AreLegendariesInSootopolisPreventingEncounters(void)
bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
{
u16 headerId;
u32 headerId;
enum TimeOfDay timeOfDay;
struct Roamer *roamer;
if (sWildEncountersDisabled == TRUE)
@ -633,11 +710,13 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
if (gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PIKE_ROOM_WILD_MONS)
{
headerId = GetBattlePikeWildMonHeaderId();
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (prevMetatileBehavior != curMetatileBehavior && !AllowWildCheckOnNewMetatile())
return FALSE;
else if (WildEncounterCheck(gBattlePikeWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE)
else if (WildEncounterCheck(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate, FALSE) != TRUE)
return FALSE;
else if (TryGenerateWildMon(gBattlePikeWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE)
else if (TryGenerateWildMon(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE)
return FALSE;
else if (!TryGenerateBattlePikeWildMon(TRUE))
return FALSE;
@ -648,11 +727,13 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
if (gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PYRAMID_FLOOR)
{
headerId = gSaveBlock2Ptr->frontier.curChallengeBattleNum;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (prevMetatileBehavior != curMetatileBehavior && !AllowWildCheckOnNewMetatile())
return FALSE;
else if (WildEncounterCheck(gBattlePyramidWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE)
else if (WildEncounterCheck(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate, FALSE) != TRUE)
return FALSE;
else if (TryGenerateWildMon(gBattlePyramidWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE)
else if (TryGenerateWildMon(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE)
return FALSE;
GenerateBattlePyramidWildMon();
@ -664,11 +745,13 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
{
if (MetatileBehavior_IsLandWildEncounter(curMetatileBehavior) == TRUE)
{
if (gWildMonHeaders[headerId].landMonsInfo == NULL)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo == NULL)
return FALSE;
else if (prevMetatileBehavior != curMetatileBehavior && !AllowWildCheckOnNewMetatile())
return FALSE;
else if (WildEncounterCheck(gWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE)
else if (WildEncounterCheck(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate, FALSE) != TRUE)
return FALSE;
if (TryStartRoamerEncounter())
@ -689,12 +772,12 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
}
// try a regular wild land encounter
if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE)
if (TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE)
{
if (TryDoDoubleWildBattle())
{
struct Pokemon mon1 = gEnemyParty[0];
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE);
gEnemyParty[1] = mon1;
BattleSetup_StartDoubleWildBattle();
}
@ -711,13 +794,15 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
else if (MetatileBehavior_IsWaterWildEncounter(curMetatileBehavior) == TRUE
|| (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) && MetatileBehavior_IsBridgeOverWater(curMetatileBehavior) == TRUE))
{
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
if (AreLegendariesInSootopolisPreventingEncounters() == TRUE)
return FALSE;
else if (gWildMonHeaders[headerId].waterMonsInfo == NULL)
else if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo == NULL)
return FALSE;
else if (prevMetatileBehavior != curMetatileBehavior && !AllowWildCheckOnNewMetatile())
return FALSE;
else if (WildEncounterCheck(gWildMonHeaders[headerId].waterMonsInfo->encounterRate, FALSE) != TRUE)
else if (WildEncounterCheck(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate, FALSE) != TRUE)
return FALSE;
if (TryStartRoamerEncounter())
@ -731,13 +816,13 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
}
else // try a regular surfing encounter
{
if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE)
if (TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL | WILD_CHECK_KEEN_EYE) == TRUE)
{
gIsSurfingEncounter = TRUE;
if (TryDoDoubleWildBattle())
{
struct Pokemon mon1 = gEnemyParty[0];
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE);
gEnemyParty[1] = mon1;
BattleSetup_StartDoubleWildBattle();
}
@ -758,11 +843,14 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior)
void RockSmashWildEncounter(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay;
if (headerId != HEADER_NONE)
{
const struct WildPokemonInfo *wildPokemonInfo = gWildMonHeaders[headerId].rockSmashMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_ROCKS);
const struct WildPokemonInfo *wildPokemonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo;
if (wildPokemonInfo == NULL)
{
@ -788,7 +876,8 @@ void RockSmashWildEncounter(void)
bool8 SweetScentWildEncounter(void)
{
s16 x, y;
u16 headerId;
u32 headerId;
enum TimeOfDay timeOfDay;
PlayerGetDestCoords(&x, &y);
headerId = GetCurrentMapWildMonHeaderId();
@ -797,7 +886,9 @@ bool8 SweetScentWildEncounter(void)
if (gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PIKE_ROOM_WILD_MONS)
{
headerId = GetBattlePikeWildMonHeaderId();
if (TryGenerateWildMon(gBattlePikeWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (TryGenerateWildMon(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
return FALSE;
TryGenerateBattlePikeWildMon(FALSE);
@ -807,7 +898,9 @@ bool8 SweetScentWildEncounter(void)
if (gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PYRAMID_FLOOR)
{
headerId = gSaveBlock2Ptr->frontier.curChallengeBattleNum;
if (TryGenerateWildMon(gBattlePyramidWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (TryGenerateWildMon(gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
return FALSE;
GenerateBattlePyramidWildMon();
@ -819,7 +912,9 @@ bool8 SweetScentWildEncounter(void)
{
if (MetatileBehavior_IsLandWildEncounter(MapGridGetMetatileBehaviorAt(x, y)) == TRUE)
{
if (gWildMonHeaders[headerId].landMonsInfo == NULL)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo == NULL)
return FALSE;
if (TryStartRoamerEncounter())
@ -831,16 +926,18 @@ bool8 SweetScentWildEncounter(void)
if (DoMassOutbreakEncounterTest() == TRUE)
SetUpMassOutbreakEncounter(0);
else
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, 0);
BattleSetup_StartWildBattle();
return TRUE;
}
else if (MetatileBehavior_IsWaterWildEncounter(MapGridGetMetatileBehaviorAt(x, y)) == TRUE)
{
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
if (AreLegendariesInSootopolisPreventingEncounters() == TRUE)
return FALSE;
if (gWildMonHeaders[headerId].waterMonsInfo == NULL)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo == NULL)
return FALSE;
if (TryStartRoamerEncounter())
@ -849,7 +946,7 @@ bool8 SweetScentWildEncounter(void)
return TRUE;
}
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, 0);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo, WILD_AREA_WATER, 0);
BattleSetup_StartWildBattle();
return TRUE;
}
@ -860,9 +957,10 @@ bool8 SweetScentWildEncounter(void)
bool8 DoesCurrentMapHaveFishingMons(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_FISHING);
if (headerId != HEADER_NONE && gWildMonHeaders[headerId].fishingMonsInfo != NULL)
if (headerId != HEADER_NONE && gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo != NULL)
return TRUE;
else
return FALSE;
@ -887,6 +985,8 @@ static void UpdateChainFishingStreak()
void FishingWildEncounter(u8 rod)
{
u16 species;
u32 headerId;
enum TimeOfDay timeOfDay;
gIsFishingEncounter = TRUE;
if (CheckFeebas() == TRUE)
@ -898,7 +998,9 @@ void FishingWildEncounter(u8 rod)
}
else
{
species = GenerateFishingWildMon(gWildMonHeaders[GetCurrentMapWildMonHeaderId()].fishingMonsInfo, rod);
headerId = GetCurrentMapWildMonHeaderId();
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_FISHING);
species = GenerateFishingWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo, rod);
}
IncrementGameStat(GAME_STAT_FISHING_ENCOUNTERS);
@ -908,7 +1010,8 @@ void FishingWildEncounter(u8 rod)
u16 GetLocalWildMon(bool8 *isWaterMon)
{
u16 headerId;
u32 headerId;
enum TimeOfDay timeOfDay;
const struct WildPokemonInfo *landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo;
@ -916,8 +1019,13 @@ u16 GetLocalWildMon(bool8 *isWaterMon)
headerId = GetCurrentMapWildMonHeaderId();
if (headerId == HEADER_NONE)
return SPECIES_NONE;
landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
// Neither
if (landMonsInfo == NULL && waterMonsInfo == NULL)
return SPECIES_NONE;
@ -944,11 +1052,14 @@ u16 GetLocalWildMon(bool8 *isWaterMon)
u16 GetLocalWaterMon(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay;
if (headerId != HEADER_NONE)
{
const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
if (waterMonsInfo)
return waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
@ -1053,7 +1164,7 @@ static bool8 TryGetRandomWildMonIndexByType(const struct WildPokemon *wildMon, u
#include "data.h"
static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 species, u8 area)
static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 species, enum WildPokemonArea area)
{
u8 i, maxLevel = 0, numMon = 0;
@ -1068,6 +1179,9 @@ static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16
case WILD_AREA_ROCKS:
numMon = ROCK_WILD_COUNT;
break;
default:
case WILD_AREA_FISHING:
case WILD_AREA_HIDDEN:
}
for (i = 0; i < numMon; i++)
@ -1127,8 +1241,10 @@ bool8 TryDoDoubleWildBattle(void)
bool8 StandardWildEncounter_Debug(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, 0) != TRUE)
return FALSE;
DoStandardWildBattle_Debug();

View File

@ -240,6 +240,20 @@ void RemoveWindow(u32 windowId)
}
}
void RemoveAllWindowsOnBg(u32 bgId)
{
u32 i;
if (bgId > NUM_BACKGROUNDS)
return;
for (i = 0; i < WINDOWS_MAX; i++)
{
if (gWindows[i].window.bg == bgId)
RemoveWindow(i);
}
}
void FreeAllWindowBuffers(void)
{
int i;

View File

@ -0,0 +1,673 @@
import json
import re
import os
IS_ENABLED = False
# C string vars
define = "#define"
ENCOUNTER_CHANCE = "ENCOUNTER_CHANCE"
SLOT = "SLOT"
TOTAL = "TOTAL"
NULL = "NULL"
UNDEFINED = "UNDEFINED"
MAP_UNDEFINED = "MAP_UNDEFINED"
# encounter group header types, filled out programmatically
MON_HEADERS = []
# mon encounter group types
LAND_MONS = "land_mons"
LAND_MONS_LABEL = "LandMons"
LAND_MONS_INDEX = 0
WATER_MONS = "water_mons"
WATER_MONS_LABEL = "WaterMons"
WATER_MONS_INDEX = 1
ROCK_SMASH_MONS = "rock_smash_mons"
ROCK_SMASH_MONS_LABEL = "RockSmashMons"
ROCK_SMASH_MONS_INDEX = 2
FISHING_MONS = "fishing_mons"
FISHING_MONS_LABEL = "FishingMons"
FISHING_MONS_INDEX = 3
HIDDEN_MONS = "hidden_mons"
HIDDEN_MONS_LABEL = "HiddenMons"
HIDDEN_MONS_INDEX = 4
MONS_INFO_TOTAL = HIDDEN_MONS_INDEX + 1
# fishing encounter data
GOOD_ROD = "good_rod"
GOOD_ROD_FIRST_INDEX = 2
GOOD_ROD_LAST_INDEX = 4
OLD_ROD = "old_rod"
OLD_ROD_FIRST_INDEX = 0
OLD_ROD_LAST_INDEX = 1
SUPER_ROD = "super_rod"
SUPER_ROD_FIRST_INDEX = 5
SUPER_ROD_LAST_INDEX = 9
# time of day encounter data
TIME_DEFAULT = "OW_TIME_OF_DAY_DEFAULT"
TIME_DEFAULT_LABEL = ""
TIME_DEFAULT_INDEX = 0
TIME_MORNING = "time_morning"
TIME_MORNING_LABEL = "Morning"
TIME_MORNING_INDEX = 0
TIME_DAY = "time_day"
TIME_DAY_LABEL = "Day"
TIME_DAY_INDEX = 1
TIME_EVENING = "time_evening"
TIME_EVENING_LABEL = "Evening"
TIME_EVENING_INDEX = 2
TIME_NIGHT = "time_night"
TIME_NIGHT_LABEL = "Night"
TIME_NIGHT_INDEX = 3
TOTAL_TIME_STAGES = TIME_NIGHT_INDEX + 1
# struct building blocks
baseStruct = "const struct WildPokemon"
structLabel = ""
structMonType = ""
structTime = ""
structMap = ""
structInfo = "Info"
structHeader = "Header"
structArrayAssign = "[] ="
baseStructLabel = ""
baseStructContent = []
infoStructString = ""
infoStructRate = 0
infoStructContent = []
headerStructLabel = ""
headerStructContent = {}
headerStructTable = {}
headerIndex = 0
# map header data variables
hLabel = ""
hForMaps = True
headersArray = [headerIndex]
# headersArrayItems
landMonsInfo = ""
waterMonsInfo = ""
rockSmashMonsInfo = ""
fishingMonsInfo = ""
# encounter rate variables
eLandMons = []
eWaterMons = []
eRockSmashMons = []
eFishingMons = []
# debug output control
printEncounterHeaders = True
printEncounterRateMacros = True
printEncounterStructsInfoString = True
printEncounterStructs = True
def ImportWildEncounterFile():
# make sure we're in the right directory before anything else
if not os.path.exists("Makefile"):
print("Please run this script from the project's root folder.")
quit()
global MON_HEADERS
global landMonsInfo
global waterMonsInfo
global rockSmashMonsInfo
global fishingMonsInfo
global hiddenMonsInfo
global structLabel
global structMonType
global structTime
global structMap
global baseStructLabel
global baseStructContent
global infoStructString
global infoStructRate
global headerStructLabel
global headerStructContent
global hLabel
global headersArray
global eLandMons
global eWaterMons
global eRockSmashMons
global eFishingMons
global encounterTotalCount
global encounterCount
global headerIndex
global tabStr
tabStr = " "
global IS_ENABLED
IS_ENABLED = IsConfigEnabled()
wFile = open("src/data/wild_encounters.json")
wData = json.load(wFile)
encounterTotalCount = []
encounterCount = []
groupCount = 0
while groupCount < len(wData["wild_encounter_groups"]):
encounterTotalCount.append(0)
encounterCount.append(0)
groupCount += 1
for data in wData["wild_encounter_groups"]:
wEncounters = wData["wild_encounter_groups"][headerIndex]["encounters"]
headerSuffix = structHeader + "s"
if data["label"]:
hLabel = wData["wild_encounter_groups"][headerIndex]["label"]
if headerSuffix in hLabel:
hLabel = hLabel[:len(hLabel) - len(headerSuffix)]
MON_HEADERS.append(hLabel)
if data["for_maps"]:
hForMaps = wData["wild_encounter_groups"][headerIndex]["for_maps"]
# for the encounter rate macros, so we don't worry about hidden mons here
if headerIndex == 0:
wFields = wData["wild_encounter_groups"][headerIndex]["fields"]
for field in wFields:
if field["type"] == LAND_MONS:
eLandMons = field["encounter_rates"]
elif field["type"] == WATER_MONS:
eWaterMons = field["encounter_rates"]
elif field["type"] == ROCK_SMASH_MONS:
eRockSmashMons = field["encounter_rates"]
elif field["type"] == FISHING_MONS:
eFishingMons = field["encounter_rates"]
eFishingMons.append(field["groups"])
PrintGeneratedWarningText()
print('#include "rtc.h"')
print("\n")
PrintEncounterRateMacros()
print("\n")
for encounter in wEncounters:
if "map" in encounter:
structMap = encounter["map"]
else:
structMap = encounter["base_label"]
structLabel = encounter["base_label"]
if encounterTotalCount[headerIndex] != len(wEncounters):
encounterTotalCount[headerIndex] = len(wEncounters)
encounterCount[headerIndex] += 1
headersArray = []
if not IS_ENABLED:
structTime = TIME_DEFAULT_LABEL
elif TIME_MORNING_LABEL in structLabel:
structTime = TIME_MORNING_LABEL
elif TIME_DAY_LABEL in structLabel:
structTime = TIME_DAY_LABEL
elif TIME_EVENING_LABEL in structLabel:
structTime = TIME_EVENING_LABEL
elif TIME_NIGHT_LABEL in structLabel:
structTime = TIME_NIGHT_LABEL
else:
structTime = TIME_MORNING_LABEL
structLabel = structLabel + "_Morning"
landMonsInfo = ""
waterMonsInfo = ""
rockSmashMonsInfo = ""
fishingMonsInfo = ""
hiddenMonsInfo = ""
for areaTable in encounter:
if LAND_MONS in areaTable:
structMonType = LAND_MONS_LABEL
landMonsInfo = f"{structLabel}_{structMonType}{structInfo}"
elif WATER_MONS in areaTable:
structMonType = WATER_MONS_LABEL
waterMonsInfo = f"{structLabel}_{structMonType}{structInfo}"
elif ROCK_SMASH_MONS in areaTable:
structMonType = ROCK_SMASH_MONS_LABEL
rockSmashMonsInfo = f"{structLabel}_{structMonType}{structInfo}"
elif FISHING_MONS in areaTable:
structMonType = FISHING_MONS_LABEL
fishingMonsInfo = f"{structLabel}_{structMonType}{structInfo}"
elif HIDDEN_MONS in areaTable:
structMonType = HIDDEN_MONS_LABEL
hiddenMonsInfo = f"{structLabel}_{structMonType}{structInfo}"
else:
structMonType = ""
continue
baseStructContent = []
for group in encounter[areaTable]:
if "mons" in group:
for mon in encounter[areaTable][group]:
baseStructContent.append(list(mon.values()))
if "encounter_rate" in group:
infoStructRate = encounter[areaTable][group]
baseStructLabel = f"{baseStruct} {structLabel}_{structMonType}{structArrayAssign}"
if printEncounterStructs:
print()
print(baseStructLabel)
print("{")
PrintStructContent(baseStructContent)
print("};")
if printEncounterStructsInfoString:
infoStructString = f"{baseStruct}{structInfo} {structLabel}_{structMonType}{structInfo} = {{ {infoStructRate}, {structLabel}_{structMonType} }};"
print(infoStructString)
AssembleMonHeaderContent()
headerIndex += 1
PrintWildMonHeadersContent()
def PrintStructContent(contentList):
for monList in contentList:
print(f"{tabStr}{{ {monList[0]}, {monList[1]}, {monList[2]} }},")
return
def GetStructLabelWithoutTime(label):
labelLength = len(label)
timeLength = 0
if not IS_ENABLED:
return label
elif TIME_MORNING_LABEL in label:
timeLength = len(TIME_MORNING_LABEL)
elif TIME_DAY_LABEL in label:
timeLength = len(TIME_DAY_LABEL)
elif TIME_EVENING_LABEL in label:
timeLength = len(TIME_EVENING_LABEL)
elif TIME_NIGHT_LABEL in label:
timeLength = len(TIME_NIGHT_LABEL)
return label[:(labelLength - (timeLength + 1))]
def AssembleMonHeaderContent():
global structLabel
SetupMonInfoVars()
tempHeaderLabel = GetWildMonHeadersLabel()
tempHeaderTimeIndex = GetTimeIndexFromString(structTime)
structLabelNoTime = GetStructLabelWithoutTime(structLabel)
if tempHeaderLabel not in headerStructTable:
headerStructTable[tempHeaderLabel] = {}
headerStructTable[tempHeaderLabel]["groupNum"] = headerIndex
if structLabelNoTime not in headerStructTable[tempHeaderLabel]:
headerStructTable[tempHeaderLabel][structLabelNoTime] = {}
headerStructTable[tempHeaderLabel][structLabelNoTime]["headerType"] = GetWildMonHeadersLabel()
headerStructTable[tempHeaderLabel][structLabelNoTime]["mapGroup"] = structMap
headerStructTable[tempHeaderLabel][structLabelNoTime]["mapNum"] = structMap
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounterTotalCount"] = encounterTotalCount[headerIndex]
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"] = []
timeStart = TIME_DEFAULT_INDEX
timeEnd = TIME_NIGHT_INDEX if IS_ENABLED else TIME_DEFAULT_INDEX
while timeStart <= timeEnd:
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"].append([])
timeStart += 1
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(landMonsInfo)
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(waterMonsInfo)
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(rockSmashMonsInfo)
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(fishingMonsInfo)
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(hiddenMonsInfo)
def SetupMonInfoVars():
global landMonsInfo
global waterMonsInfo
global rockSmashMonsInfo
global fishingMonsInfo
global hiddenMonsInfo
if landMonsInfo == "":
landMonsInfo = NULL
else:
landMonsInfo = f"&{landMonsInfo}"
if waterMonsInfo == "":
waterMonsInfo = NULL
else:
waterMonsInfo = f"&{waterMonsInfo}"
if rockSmashMonsInfo == "":
rockSmashMonsInfo = NULL
else:
rockSmashMonsInfo = f"&{rockSmashMonsInfo}"
if fishingMonsInfo == "":
fishingMonsInfo = NULL
else:
fishingMonsInfo = f"&{fishingMonsInfo}"
if hiddenMonsInfo == "":
hiddenMonsInfo = NULL
else:
hiddenMonsInfo = f"&{hiddenMonsInfo}"
def PrintWildMonHeadersContent():
global tabStr
groupCount = 0
for group in headerStructTable:
labelCount = 0
for label in headerStructTable[group]:
if label != "groupNum":
if labelCount == 0:
PrintEncounterHeaders("\n")
PrintEncounterHeaders(headerStructTable[group][label]["headerType"])
PrintEncounterHeaders(tabStr + "{")
for stat in headerStructTable[group][label]:
mapData = headerStructTable[group][label][stat]
if stat == "mapGroup":
PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(mapData)},")
elif stat == "mapNum":
PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(mapData, labelCount + 1)},")
if type(headerStructTable[group][label][stat]) == list:
PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =")
PrintEncounterHeaders(TabStr(2) + "{")
infoCount = 0
for monInfo in headerStructTable[group][label][stat]:
PrintEncounterHeaders(f"{TabStr(3)}[{GetTimeStrFromIndex(infoCount)}] = ")
infoIndex = 0
while infoIndex <= MONS_INFO_TOTAL - 1:
if infoIndex == 0:
PrintEncounterHeaders(TabStr(3) + "{")
if len(monInfo) == 0:
PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = NULL,")
else:
PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = {monInfo[infoIndex]},")
if infoIndex == MONS_INFO_TOTAL - 1:
PrintEncounterHeaders(TabStr(3) + "},")
infoIndex += 1
infoCount += 1
PrintEncounterHeaders(TabStr(2) + "},")
PrintEncounterHeaders(tabStr + "},")
if labelCount + 1 == headerStructTable[group][label]["encounterTotalCount"]:
PrintEncounterHeaders(tabStr + "{")
PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(MAP_UNDEFINED)},")
PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(MAP_UNDEFINED, labelCount + 1)},")
timeEnd = TIME_NIGHT_INDEX if IS_ENABLED else TIME_DEFAULT_INDEX
nullCount = 0
while nullCount <= timeEnd:
if nullCount == 0:
PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =")
PrintEncounterHeaders(TabStr(2)+ "{")
PrintEncounterHeaders(f"{TabStr(3)}[{GetTimeStrFromIndex(nullCount)}] = ")
nullIndex = 0
while nullIndex <= MONS_INFO_TOTAL - 1:
if nullIndex == 0:
PrintEncounterHeaders(TabStr(3) + "{")
PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(nullIndex)} = NULL,")
if nullIndex == MONS_INFO_TOTAL - 1:
PrintEncounterHeaders(TabStr(3) + "},")
nullIndex += 1
nullCount += 1
PrintEncounterHeaders(TabStr(2) + "},")
PrintEncounterHeaders(tabStr + "},")
labelCount += 1
groupCount += 1
PrintEncounterHeaders("};")
def GetWildMonHeadersLabel():
return f"{baseStruct}{structHeader} {MON_HEADERS[headerIndex]}{structHeader}s{structArrayAssign}" + "\n{"
def PrintEncounterHeaders(content):
if printEncounterHeaders:
print(content)
def PrintEncounterRateMacros():
if not printEncounterRateMacros:
return
rateCount = 0
for percent in eLandMons:
if rateCount == 0:
print(f"{define} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount} {percent}")
else:
print(
f"{define} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount - 1} + {percent}"
)
if rateCount + 1 == len(eLandMons):
print(
f"{define} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount})"
)
rateCount += 1
rateCount = 0
for percent in eWaterMons:
if rateCount == 0:
print(f"{define} {ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{SLOT}_{rateCount} {percent}")
else:
print(
f"{define} {ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{SLOT}_{rateCount - 1} + {percent}"
)
if rateCount + 1 == len(eWaterMons):
print(
f"{define} {ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{SLOT}_{rateCount})"
)
rateCount += 1
rateCount = 0
for percent in eRockSmashMons:
if rateCount == 0:
print(f"{define} {ENCOUNTER_CHANCE}_{ROCK_SMASH_MONS.upper()}_{SLOT}_{rateCount} {percent}")
else:
print(
f"{define} {ENCOUNTER_CHANCE}_{ROCK_SMASH_MONS.upper()}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{ROCK_SMASH_MONS.upper()}_{SLOT}_{rateCount - 1} + {percent}"
)
if rateCount + 1 == len(eRockSmashMons):
print(
f"{define} {ENCOUNTER_CHANCE}_{ROCK_SMASH_MONS.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{ROCK_SMASH_MONS.upper()}_{SLOT}_{rateCount})"
)
rateCount += 1
for rodRate in eFishingMons[-1]:
for rodPercentIndex in eFishingMons[-1][rodRate]:
if rodPercentIndex == OLD_ROD_FIRST_INDEX or rodPercentIndex == GOOD_ROD_FIRST_INDEX or rodPercentIndex == SUPER_ROD_FIRST_INDEX:
print(
f"{define} {ENCOUNTER_CHANCE}_{FISHING_MONS.upper()}_{rodRate.upper()}_{SLOT}_{rodPercentIndex} {eFishingMons[rodPercentIndex]}"
)
else:
print(
f"{define} {ENCOUNTER_CHANCE}_{FISHING_MONS.upper()}_{rodRate.upper()}_{SLOT}_{rodPercentIndex} {ENCOUNTER_CHANCE}_{FISHING_MONS.upper()}_{rodRate.upper()}_{SLOT}_{rodPercentIndex - 1} + {eFishingMons[rodPercentIndex]}"
)
if rodPercentIndex == OLD_ROD_LAST_INDEX or rodPercentIndex == GOOD_ROD_LAST_INDEX or rodPercentIndex == SUPER_ROD_LAST_INDEX:
print(
f"{define} {ENCOUNTER_CHANCE}_{FISHING_MONS.upper()}_{rodRate.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{FISHING_MONS.upper()}_{rodRate.upper()}_{SLOT}_{rodPercentIndex})"
)
def GetTimeStrFromIndex(index):
if not IS_ENABLED:
return TIME_DEFAULT
elif index == TIME_MORNING_INDEX:
return TIME_MORNING.upper()
elif index == TIME_DAY_INDEX:
return TIME_DAY.upper()
elif index == TIME_EVENING_INDEX:
return TIME_EVENING.upper()
elif index == TIME_NIGHT_INDEX:
return TIME_NIGHT.upper()
return index
def GetTimeIndexFromString(string):
if not IS_ENABLED:
return TIME_DEFAULT_INDEX
elif string.lower() == TIME_MORNING or string == TIME_MORNING_LABEL:
return TIME_MORNING_INDEX
elif string.lower() == TIME_DAY or string == TIME_DAY_LABEL:
return TIME_DAY_INDEX
elif string.lower() == TIME_EVENING or string == TIME_EVENING_LABEL:
return TIME_EVENING_INDEX
elif string.lower() == TIME_NIGHT or string == TIME_NIGHT_LABEL:
return TIME_NIGHT_INDEX
return string
def GetIMonInfoStringFromIndex(index):
if index == LAND_MONS_INDEX:
return ".landMonsInfo"
elif index == WATER_MONS_INDEX:
return ".waterMonsInfo"
elif index == ROCK_SMASH_MONS_INDEX:
return ".rockSmashMonsInfo"
elif index == FISHING_MONS_INDEX:
return ".fishingMonsInfo"
elif index == HIDDEN_MONS_INDEX:
return ".hiddenMonsInfo"
return index
def GetMapGroupEnum(string, index = 0):
if "MAP_" in string and index == 0:
return "MAP_GROUP(" + string[4:len(string)] + ")"
elif "MAP_" in string and index != 0:
return "MAP_NUM(" + string[4:len(string)] + ")"
return index
"""
get copied lhea :^ )
- next two functions copied almost verbatim from @lhearachel's python scripts in tools/learnset_helpers
"""
def PrintGeneratedWarningText():
print("//")
print("// DO NOT MODIFY THIS FILE! It is auto-generated by tools/wild_encounters/wild_encounters_to_header.py")
print("//")
print("\n")
def IsConfigEnabled():
CONFIG_ENABLED_PAT = re.compile(r"#define OW_TIME_OF_DAY_ENCOUNTERS\s+(?P<cfg_val>[^ ]*)")
with open("./include/config/overworld.h", "r") as overworld_config_file:
config_overworld = overworld_config_file.read()
config_setting = CONFIG_ENABLED_PAT.search(config_overworld)
return config_setting is not None and config_setting.group("cfg_val") in ("TRUE", "1")
def TabStr(amount):
global tabStr
return tabStr * amount
ImportWildEncounterFile()
"""
!!!! EXAMPLE OUTPUT !!!!
- when OW_TIME_OF DAY_ENCOUNTERS is FALSE in configoverworld.h
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 20
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 + 20
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 + 5
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 + 5
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 + 4
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 + 4
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_10 ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 + 1
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_11 ENCOUNTER_CHANCE_LAND_MONS_SLOT_10 + 1
#define ENCOUNTER_CHANCE_LAND_MONS_TOTAL (ENCOUNTER_CHANCE_LAND_MONS_SLOT_11)
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 60
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 + 30
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 + 5
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_3 ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 + 4
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_4 ENCOUNTER_CHANCE_WATER_MONS_SLOT_3 + 1
#define ENCOUNTER_CHANCE_WATER_MONS_TOTAL (ENCOUNTER_CHANCE_WATER_MONS_SLOT_4)
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_0 60
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_1 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_0 + 30
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_2 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_1 + 5
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_3 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_2 + 4
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_4 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_3 + 1
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_TOTAL (ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_4)
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 60
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 + 20
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4 ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 + 20
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4)
#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0 70
#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_1 ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0 + 30
#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_1)
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 40
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 + 40
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 + 15
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 + 4
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 + 1
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9)
const struct WildPokemon gRoute101_LandMons_Day[] =
{
{ 2, 2, SPECIES_WURMPLE },
{ 2, 2, SPECIES_POOCHYENA },
{ 2, 2, SPECIES_WURMPLE },
{ 3, 3, SPECIES_WURMPLE },
{ 3, 3, SPECIES_POOCHYENA },
{ 3, 3, SPECIES_POOCHYENA },
{ 3, 3, SPECIES_WURMPLE },
{ 3, 3, SPECIES_POOCHYENA },
{ 2, 2, SPECIES_ZIGZAGOON },
{ 2, 2, SPECIES_ZIGZAGOON },
{ 3, 3, SPECIES_ZIGZAGOON },
{ 3, 3, SPECIES_ZIGZAGOON },
};
const struct WildPokemonInfo gRoute101_Day_LandMonsInfo= { 20, gRoute101_Day_LandMons };
const struct WildPokemonHeader gWildMonHeaders[] =
{
{
.mapGroup = MAP(ROUTE101),
.mapNum = MAP_NUM(ROUTE101),
.encounterTypes =
[OW_TIME_OF_DAY_DEFAULT] =
{
.landMonsInfo = &gRoute101_LandMonsInfo,
.waterMonsInfo = NULL,
.rockSmashMonsInfo = NULL,
.fishingMonsInfo = NULL,
.hiddenMonsInfo = NULL,
}
},
}
"""