diff --git a/Makefile b/Makefile index 0f973982e5..ccfe64dcf4 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,32 @@ +GAME_VERSION ?= EMERALD +TITLE ?= POKEMON EMER +GAME_CODE ?= BPEE +BUILD_NAME ?= emerald +MAP_VERSION ?= emerald + +ifeq (firered,$(MAKECMDGOALS)) + GAME_VERSION := FIRERED + TITLE := POKEMON FIRE + GAME_CODE := BPRE + BUILD_NAME := firered + MAP_VERSION := firered +else +ifeq (leafgreen,$(MAKECMDGOALS)) + GAME_VERSION := LEAFGREEN + TITLE := POKEMON LEAF + GAME_CODE := BPGE + BUILD_NAME := leafgreen + MAP_VERSION := firered +endif +endif + # GBA rom header -TITLE := POKEMON EMER -GAME_CODE := BPEE MAKER_CODE := 01 REVISION := 0 KEEP_TEMPS ?= 0 # `File name`.gba -FILE_NAME := pokeemerald +FILE_NAME := poke$(BUILD_NAME) BUILD_DIR := build # Compares the ROM to a checksum of the original - only makes sense using when non-modern @@ -75,10 +95,10 @@ ifeq ($(RELEASE),1) endif ROM_NAME := $(FILE_NAME).gba -OBJ_DIR_NAME := $(BUILD_DIR)/modern -OBJ_DIR_NAME_TEST := $(BUILD_DIR)/modern-test -OBJ_DIR_NAME_DEBUG := $(BUILD_DIR)/modern-debug -OBJ_DIR_NAME_RELEASE := $(BUILD_DIR)/modern-release +OBJ_DIR_NAME := $(BUILD_DIR)/$(BUILD_NAME) +OBJ_DIR_NAME_TEST := $(BUILD_DIR)/$(BUILD_NAME)-test +OBJ_DIR_NAME_DEBUG := $(BUILD_DIR)/$(BUILD_NAME)-debug +OBJ_DIR_NAME_RELEASE := $(BUILD_DIR)/$(BUILD_NAME)-release ELF_NAME := $(ROM_NAME:.gba=.elf) MAP_NAME := $(ROM_NAME:.gba=.map) @@ -124,7 +144,7 @@ TEST_BUILDDIR = $(OBJ_DIR)/$(TEST_SUBDIR) SHELL := bash -o pipefail # Set flags for tools -ASFLAGS := -mcpu=arm7tdmi -march=armv4t -meabi=5 --defsym MODERN=1 +ASFLAGS := -mcpu=arm7tdmi -march=armv4t -meabi=5 --defsym MODERN=1 --defsym $(GAME_VERSION)=1 INCLUDE_DIRS := include INCLUDE_CPP_ARGS := $(INCLUDE_DIRS:%=-iquote %) @@ -135,7 +155,7 @@ O_LEVEL ?= g else O_LEVEL ?= 2 endif -CPPFLAGS := $(INCLUDE_CPP_ARGS) -Wno-trigraphs -DMODERN=1 -DTESTING=$(TEST) -std=gnu17 +CPPFLAGS := $(INCLUDE_CPP_ARGS) -Wno-trigraphs -DMODERN=1 -DTESTING=$(TEST) -D$(GAME_VERSION) -std=gnu17 ifeq ($(RELEASE),1) override CPPFLAGS += -DRELEASE ifeq ($(USE_LTO_ON_RELEASE),1) @@ -221,7 +241,7 @@ MISC_TOOL_DIR := $(TOOLS_DIR)/misc AUTO_GEN_TARGETS += $(INCLUDE_DIRS)/constants/script_commands.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 $(INCLUDE_DIRS)/config/dexnav.h - python3 $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py > $@ + python3 $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py $(INCLUDE_DIRS)/constants/script_commands.h: $(MISC_TOOL_DIR)/make_scr_cmd_constants.py $(DATA_ASM_SUBDIR)/script_cmd_table.inc python3 $(MISC_TOOL_DIR)/make_scr_cmd_constants.py @@ -270,7 +290,7 @@ ifeq ($(SETUP_PREREQS),1) $(error Errors occurred while building tools. See error messages above for more details) endif # Oh and also generate mapjson sources before we use `SCANINC`. - $(foreach line, $(shell $(MAKE) generated | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line)))) + $(foreach line, $(shell $(MAKE) MAP_VERSION=$(MAP_VERSION) generated | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line)))) ifneq ($(.SHELLSTATUS),0) $(error Errors occurred while generating map-related sources. See error messages above for more details) endif @@ -480,7 +500,7 @@ ifneq ($(NODEP),1) endif $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.s $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $< @@ -490,7 +510,7 @@ ifneq ($(NODEP),1) endif $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $< @@ -549,6 +569,9 @@ $(ROM): $(ELF) $(OBJCOPY) -O binary $< $@ $(FIX) $@ -p --silent +emerald: all +firered: all +leafgreen: all # Symbol file (`make syms`) $(SYM): $(ELF) $(OBJDUMP) -t $< | sort -u | grep -E "^0[2389]" | $(PERL) -p -e 's/^(\w{8}) (\w).{6} \S+\t(\w{8}) (\S+)$$/\1 \2 \3 \4/g' > $@ diff --git a/include/config/overworld.h b/include/config/overworld.h index 349d643cc4..7b2420c057 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -86,13 +86,13 @@ #define GEN_8_PLA GEN_LATEST + 2 #define TIME_DEBUG GEN_LATEST + 3 -//Time +// 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. TIME_DEBUG is 1:1, and meant for debugging purposes. 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_FALLBACK TIME_MORNING // The time of day that encounter tables fall back to. +#define OW_TIME_OF_DAY_FALLBACK TIME_MORNING // The time of day that encounter tables fall back to. If you set OW_TIMES_OF_DAY to GEN_3, change this to TIME_DAY or you won't have any encounters! // Lighting #define OW_SHADOW_INTENSITY 4 // Ranges from 0 to 16, where 0 is fully transparent and 16 is black. diff --git a/include/constants/rtc.h b/include/constants/rtc.h index 65ee9c35ed..ea0748b506 100644 --- a/include/constants/rtc.h +++ b/include/constants/rtc.h @@ -81,7 +81,7 @@ #define NIGHT_HOUR_END 6 #endif -// TIMES_OF_DAY_COUNT must be last +// TIMES_OF_DAY_COUNT must be last or things will break enum TimeOfDay { TIME_MORNING, @@ -91,6 +91,10 @@ enum TimeOfDay TIMES_OF_DAY_COUNT, }; +// for incrementing/decrementing +#define TIME_FIRST 0 +#define TIME_LAST (TIMES_OF_DAY_COUNT - 1) + #define TIME_OF_DAY_DEFAULT 0 #endif // GUARD_CONSTANTS_RTC_H diff --git a/include/rtc.h b/include/rtc.h index 8ee3071615..d0bb6a43de 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -43,6 +43,7 @@ u16 GetFullYear(void); enum Month GetMonth(void); u8 GetDay(void); enum Weekday GetDayOfWeek(void); +enum TimeOfDay GenConfigTimeOfDay(enum TimeOfDay timeOfDay); enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay); enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay); diff --git a/migration_scripts/add_time_based_encounters.py b/migration_scripts/add_time_based_encounters.py index aebdafc2b2..b036e46e41 100644 --- a/migration_scripts/add_time_based_encounters.py +++ b/migration_scripts/add_time_based_encounters.py @@ -7,7 +7,7 @@ try: print("Please run this script from the project's root folder.") quit() sys.path.append("./tools/wild_encounters/") - from wild_encounters_to_header import TimeOfDay, SetupUserTimeEnum + from wild_encounters_to_header import Config except ImportError: print("Could not import the file tools/wild_encounters/wild_encounters_to_header.py") quit() @@ -24,11 +24,13 @@ def GetWildEncounterFile(): print("Please run this script from the project's root folder.") quit() - timeOfDay = SetupUserTimeEnum(TimeOfDay()) - wFile = open("src/data/wild_encounters.json") wData = json.load(wFile) + config = Config('include/config/overworld.h', 'include/constants/rtc.h', wData) + timeOfDay = config.times_of_day + + wBackupData = json.dumps(wData, indent=2) wBackupFile = open("src/data/wild_encounters.json.bak", mode="w", encoding="utf-8") wBackupFile.write(wBackupData) @@ -49,7 +51,7 @@ def GetWildEncounterFile(): wEncounters_New = list() for map in wEncounters: - for suffix in timeOfDay.fvals: + for suffix in timeOfDay.values(): tempSuffix = "_" + suffix if tempSuffix in map["base_label"]: editMap = False @@ -59,7 +61,7 @@ def GetWildEncounterFile(): if editMap: k = 0 - for suffix in timeOfDay.fvals: + for suffix in timeOfDay.values(): tempDict = dict() if k == TIME_OF_DAY_DEFAULT or COPY_FULL_ENCOUNTER: tempDict = map.copy() diff --git a/src/pokedex_area_screen.c b/src/pokedex_area_screen.c index f48db5eacb..76e3b71c6c 100644 --- a/src/pokedex_area_screen.c +++ b/src/pokedex_area_screen.c @@ -248,7 +248,7 @@ static const struct WindowTemplate sTimeOfDayWindowLabelTemplates[] = .baseBlock = 0x16C }, - [DEX_AREA_LABEL_AREA_UNKNOWN] = + [DEX_AREA_LABEL_AREA_UNKNOWN] = { .bg = LABEL_WINDOW_BG, .tilemapLeft = 12, diff --git a/src/rtc.c b/src/rtc.c index fb2518f210..555c86b87e 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -334,7 +334,8 @@ enum TimeOfDay GetTimeOfDay(void) enum TimeOfDay GetTimeOfDayForDex(void) { - return OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : TIME_OF_DAY_DEFAULT; + enum TimeOfDay timeOfDay = OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : TIME_OF_DAY_DEFAULT; + return GenConfigTimeOfDay(timeOfDay); } void RtcInitLocalTimeOffset(s32 hour, s32 minute) @@ -456,12 +457,24 @@ enum Weekday GetDayOfWeek(void) return dateTime.dayOfWeek; } +enum TimeOfDay GenConfigTimeOfDay(enum TimeOfDay timeOfDay) +{ + if ((((timeOfDay == TIME_MORNING || timeOfDay == TIME_EVENING) && OW_TIMES_OF_DAY == GEN_3) + || (timeOfDay == TIME_EVENING && OW_TIMES_OF_DAY == GEN_4)) + && timeOfDay < TIME_LAST) + timeOfDay++; + + return timeOfDay; +} + enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay) { - return timeOfDay == TIME_NIGHT ? TIME_MORNING : timeOfDay + 1; + timeOfDay = timeOfDay == TIME_LAST ? TIME_FIRST : timeOfDay + 1; + return GenConfigTimeOfDay(timeOfDay); } enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay) { - return timeOfDay == TIME_MORNING ? TIME_NIGHT : timeOfDay - 1; + timeOfDay = timeOfDay == TIME_FIRST ? TIME_LAST : timeOfDay - 1; + return GenConfigTimeOfDay(timeOfDay); } diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 29f6554b1a..4c81fa371c 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -415,36 +415,32 @@ enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area return TIME_OF_DAY_DEFAULT; if (InBattlePike() || CurrentBattlePyramidLocation() != PYRAMID_LOCATION_NONE) - { return OW_TIME_OF_DAY_FALLBACK; - } - else + + switch (area) { - 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; - } + 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; + return GenConfigTimeOfDay(timeOfDay); } u8 PickWildMonNature(void) diff --git a/tools/wild_encounters/wild_encounters_to_header.py b/tools/wild_encounters/wild_encounters_to_header.py index 375dda3ecf..2fca4623e7 100644 --- a/tools/wild_encounters/wild_encounters_to_header.py +++ b/tools/wild_encounters/wild_encounters_to_header.py @@ -1,720 +1,277 @@ import json import re -import os - -IS_ENABLED = False -DEXNAV_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 -fieldData = [] -fieldInfoStrings = [] -fieldStrings = [] - -# time of day encounter data -TIME_DEFAULT = "" -TIME_DEFAULT_LABEL = "TIME_OF_DAY_DEFAULT" -TIME_DEFAULT_INDEX = 0 -TIMES_OF_DAY_COUNT = TIME_DEFAULT_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] - -# debug output control -mainSwitch = True -printWarningAndInclude = mainSwitch -printEncounterHeaders = mainSwitch -printEncounterRateMacros = mainSwitch -printEncounterStructsInfoString = mainSwitch -printEncounterStructs = mainSwitch - - -class TimeOfDay(): - def __init__(self): - self.vals = [] - self.lvals = [] - self.fvals = [] - self.count = 0 - - def __len__(self): - return self.count - - # for debugging purposes - def __str__(self): - return str([self.vals, self.lvals, self.fvals, self.count]) - - def add(self, val): - self.vals.append(val) - self.lvals.append(val.lower()) - self.fvals.append(GetTimeLabelFromString(val).capitalize()) - self.count += 1 - - def indexOf(self, val): - tempArr = [self.vals, self.lvals, self.fvals] - - for tvals in tempArr: - i = 0 - for time in tvals: - if val in time: - return i - - i += 1 - # return -1 here so it returns a consistent type and can be checked against < 0 - return -1 - - -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 TIME_OF_DAY - TIME_OF_DAY = SetupUserTimeEnum(TimeOfDay()) - - global IS_ENABLED - global TIMES_OF_DAY_COUNT - if IsConfigEnabled(): - IS_ENABLED = True - TIMES_OF_DAY_COUNT = len(TIME_OF_DAY) - - global DEXNAV_ENABLED - DEXNAV_ENABLED = IsDexnavEnabled() - - global fieldInfoStrings - global fieldStrings - 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 encounterTotalCount - global encounterCount - global headerIndex - global fieldData - global tabStr - tabStr = " " - - 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"] - - if headerIndex == 0: - wFields = wData["wild_encounter_groups"][headerIndex]["fields"] - fieldCounter = 0 - for field in wFields: - if not CheckFieldDataDupes(field["type"]): - AddFieldData(fieldCounter, field["type"], field["encounter_rates"]) - - if "groups" in field: - fieldData[fieldCounter]["groups"] = field["groups"] - - """ - hidden mons need a special bit of logic since they're not in the vanilla - wild_encounters.json file, but the code expects them to be there - """ - hidden_mons = "hidden_mons" - if (fieldCounter == len(wFields) - 1) and not CheckFieldDataDupes(hidden_mons): - hidden_dummy_rates = [1, 0] - AddFieldData(fieldCounter + 1, hidden_mons, hidden_dummy_rates) - - fieldCounter += 1 - - if printWarningAndInclude: - PrintGeneratedWarningText() - print('#include "rtc.h"') - print("\n") - - PrintEncounterRateMacros() - - 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 = [] - - structTime = TIME_DEFAULT_INDEX - if IS_ENABLED: - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - tempfTime = f"_{TIME_OF_DAY.fvals[timeCounter]}" - tempTime = TIME_OF_DAY.vals[timeCounter] - if tempfTime in structLabel or tempTime in structLabel: - structTime = timeCounter - - timeCounter += 1 - - fieldCounter = 0 - fieldInfoStrings = [] - while fieldCounter < len(fieldData): - fieldInfoStrings.append("") - fieldStrings.append("") - fieldCounter += 1 - - fieldCounter = 0 - while fieldCounter < len(fieldData): - for areaTable in encounter: - if fieldData[fieldCounter]["name"] in areaTable: - structMonType = fieldData[fieldCounter]["pascalName"] - if f"_{TIME_OF_DAY.fvals[structTime]}" in structLabel: - fieldInfoStrings[fieldCounter] = f"{structLabel}_{structMonType}{structInfo}" - fieldStrings[fieldCounter] = f"{structLabel}_{structMonType}" - else: - fieldInfoStrings[fieldCounter] = f"{structLabel}_{TIME_OF_DAY.fvals[structTime]}_{structMonType}{structInfo}" - fieldStrings[fieldCounter] = f"{structLabel}_{TIME_OF_DAY.fvals[structTime]}_{structMonType}" - 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} {fieldStrings[fieldCounter]}{structArrayAssign}" - if printEncounterStructs: - print() - print(baseStructLabel) - print("{") - PrintStructContent(baseStructContent) - print("};") - - if printEncounterStructsInfoString: - infoStructString = f"{baseStruct}{structInfo} {fieldInfoStrings[fieldCounter]} = {{ {infoStructRate}, {fieldStrings[fieldCounter]} }};" - print(infoStructString) - - fieldCounter += 1 - 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 - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - tempTime = TIME_OF_DAY.fvals[timeCounter] - if tempTime in label: - timeLength = len(tempTime) - return label[:(labelLength - (timeLength + 1))] - - timeCounter += 1 - return label - - -def GetStructTimeWithoutLabel(label): - if not IS_ENABLED: - return TIME_DEFAULT_INDEX - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - tempTime = f"_{TIME_OF_DAY.fvals[timeCounter]}" - if tempTime in label: - return timeCounter - - timeCounter += 1 - return TIME_DEFAULT_INDEX - - -def AssembleMonHeaderContent(): - SetupMonInfoVars() - - tempHeaderLabel = GetWildMonHeadersLabel() - tempHeaderTimeIndex = GetStructTimeWithoutLabel(structLabel) - 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"] = [] - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"].append([]) - timeCounter += 1 - - fieldCounter = 0 - while fieldCounter < len(fieldData): - headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(fieldInfoStrings[fieldCounter]) - fieldCounter += 1 - - -def SetupMonInfoVars(): - i = 0 - while i < len(fieldData): - fieldData[i]["infoStringBase"] = "." + fieldData[i]["snakeName"] + structInfo - if CheckEmpty(fieldInfoStrings[i]): - fieldInfoStrings[i] = NULL - else: - fieldInfoStrings[i] = "&" + fieldInfoStrings[i] - - i += 1 - - -def PrintWildMonHeadersContent(): - 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) + "{") - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - monInfo = headerStructTable[group][label][stat][timeCounter] - PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[timeCounter]}] = ") - - infoIndex = 0 - while infoIndex < len(fieldData): - 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 == len(fieldData) - 1: - PrintEncounterHeaders(TabStr(3) + "},") - - infoIndex += 1 - timeCounter += 1 - PrintEncounterHeaders(TabStr(2) + "},") - PrintEncounterHeaders(tabStr + "},") - labelCount += 1 - PrintEncounterHeaders(tabStr + "{") - PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(MAP_UNDEFINED)},") - PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(MAP_UNDEFINED, labelCount + 1)},") - - nullCount = 0 - while nullCount < TIMES_OF_DAY_COUNT: - if nullCount == 0: - PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =") - PrintEncounterHeaders(TabStr(2)+ "{") - - PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[nullCount]}] = ") - - nullIndex = 0 - while nullIndex <= len(fieldData) - 1: - if nullIndex == 0: - PrintEncounterHeaders(TabStr(3) + "{") - - PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(nullIndex)} = NULL,") - - if nullIndex == len(fieldData) - 1: - PrintEncounterHeaders(TabStr(3) + "},") - - nullIndex += 1 - nullCount += 1 - PrintEncounterHeaders(TabStr(2) + "},") - PrintEncounterHeaders(tabStr + "},") - 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 - - fieldCounter = 0 - while fieldCounter < len(fieldData): - tempName = fieldData[fieldCounter]["name"].upper() - if "groups" not in fieldData[fieldCounter]: - rateCount = 0 - if fieldData[fieldCounter]["encounter_rates"]: - for percent in fieldData[fieldCounter]["encounter_rates"]: - if not DEXNAV_ENABLED and tempName == "HIDDEN_MONS": - break - - if rateCount == 0: - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount} {percent}") - else: - print( - f"{define} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount - 1} + {percent}" - ) - - if rateCount + 1 == len(fieldData[fieldCounter]["encounter_rates"]): - print( - f"{define} {ENCOUNTER_CHANCE}_{tempName}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount})" - ) - - rateCount += 1 - else: - rates = fieldData[fieldCounter]["encounter_rates"] - groups = fieldData[fieldCounter]["groups"] - - for method in groups: - method_indices = groups[method] - if not method_indices: +class Config: + def __init__(self, config_file_name, rtc_constants_file_name, encounters_json_data): + self.times_of_day = None + self.mon_types = None + self.time_encounters = None + self.disable_time_fallback = None + self.time_fallback = None + + self.ParseTimeEnum(rtc_constants_file_name) + if self.times_of_day == None: + raise Exception(f"Failed to parse 'enum TimeOfDay' in '{rtc_constants_file_name}'") + + self.ParseMonTypes(encounters_json_data) + if self.mon_types == None: + raise Exception("No fields defined in 'wild_encounters.json'") + + with open(config_file_name, 'r') as config_file: + lines = config_file.readlines() + for line in lines: + self.ParseTimeConfig(line) + + if self.time_encounters == None: + raise Exception("OW_TIME_OF_DAY_ENCOUNTERS not defined.") + if self.disable_time_fallback == None: + raise Exception("OW_TIME_OF_DAY_DISABLE_FALLBACK not defined.") + if self.time_fallback == None: + raise Exception("OW_TIME_OF_DAY_FALLBACK not defined.") + + def ParseTimeEnum(self, rtc_constants_file_name): + with open(rtc_constants_file_name, 'r') as rtc_constants_file: + DEFAULT_TIME_PAT = re.compile(r"enum\s+TimeOfDay\s*\{(?P[\s*\w+,\=\d*]+)\s*\}\s*\;") + file = rtc_constants_file.read() + + m = DEFAULT_TIME_PAT.search(file) + if m: + txt = m.group('rtc_val') + values = re.findall(r'TIME_\w+', txt) + self.times_of_day = {} + for value in values: + self.times_of_day[value] = value.title().replace("Time_", "").replace("_", "") + + def ParseMonTypes(self, encounters_json_data): + for group in encounters_json_data["wild_encounter_groups"]: + if "fields" in group: + for field in group["fields"]: + field_type = field["type"] + if not self.mon_types: + self.mon_types = [] + self.mon_types.append(field_type) + + def ParseTimeConfig(self, line): + m = re.search(r'#define OW_TIME_OF_DAY_ENCOUNTERS\s+(\w+)', line) + if m: + self.time_encounters = m.group(1) == "TRUE" + + m = re.search(r'#define OW_TIME_OF_DAY_DISABLE_FALLBACK\s+(\w+)', line) + if m: + self.disable_time_fallback = m.group(1) == "TRUE" + + m = re.search(r'#define OW_TIME_OF_DAY_FALLBACK\s+(\w+)', line) + if m: + self.time_fallback = m.group(1) + + +class WildEncounterAssembler: + def __init__(self, output_file, json_data, config): + self.output_file = output_file + self.json_data = json_data + self.config = config + + def WriteLine(self, line="", indents = 0): + self.output_file.write(4 * indents * " " + line + "\n") + + def WriteHeader(self): + self.WriteLine("//") + self.WriteLine("// DO NOT MODIFY THIS FILE! It is auto-generated by tools/wild_encounters/wild_encounters_to_header.py") + self.WriteLine("//") + self.output_file.write("\n\n") + + def WriteMacro(self, macro, value): + self.output_file.write("#define " + macro + " " + value + "\n") + + def WriteMacros(self): + wild_encounter_groups = self.json_data["wild_encounter_groups"] + for wild_encounter_group in wild_encounter_groups: + if "fields" in wild_encounter_group: + fields = wild_encounter_group["fields"] + for field in fields: + field_type = field["type"] + macro_base = "ENCOUNTER_CHANCE_" + field_type.upper() + previous_group = None + previous_macro = None + encounter_rates = field["encounter_rates"] + + group_name_mapping = len(encounter_rates) * [""] + if "groups" in field: + groups = field["groups"] + for group_name, indices in groups.items(): + for index in indices: + group_name_mapping[index] = "_" + group_name.upper() + + for idx, rate in enumerate(encounter_rates): + macro_name = macro_base + group_name_mapping[idx] + "_SLOT_" + str(idx) + macro_value = str(rate) + if previous_group == group_name_mapping[idx]: + macro_value = "(" + previous_macro + " + " + macro_value + ")" + elif idx > 0: + macro_total_name = macro_base + group_name_mapping[idx - 1] + "_TOTAL" + self.WriteMacro(macro_total_name, "(" + previous_macro + ")") + self.WriteMacro(macro_name, macro_value) + previous_group = group_name_mapping[idx] + previous_macro = macro_name + if idx == len(encounter_rates) - 1: + macro_total_name = macro_base + group_name_mapping[idx] + "_TOTAL" + self.WriteMacro(macro_total_name, "(" + previous_macro + ")") + macro_total_name = macro_base + group_name_mapping[-1] + "_TOTAL" + self.WriteLine() + + def WriteMonInfos(self, name, mons, encounter_rate): + info_name = name + "Info" + self.WriteLine(f"const struct WildPokemon {name}[] =") + self.WriteLine("{") + for mon in mons: + species = mon["species"] + min_level = 2 if "min_level" not in mon else mon["min_level"] + max_level = 100 if "max_level" not in mon else mon["max_level"] + self.WriteLine(f"{{ {min_level}, {max_level}, {species} }},", 1) + + self.WriteLine("};") + self.WriteLine() + self.WriteLine(f"const struct WildPokemonInfo {info_name} = {{ {encounter_rate}, {name} }};") + self.WriteLine() + + def WriteTerminator(self): + self.WriteLine("{", 1) + self.WriteLine(".mapGroup = MAP_GROUP(MAP_UNDEFINED),", 2) + self.WriteLine(".mapNum = MAP_NUM(MAP_UNDEFINED),", 2) + self.WriteLine(".encounterTypes =", 2) + self.WriteLine("{", 2) + for time in self.config.times_of_day: + if not self.config.time_encounters and time != self.config.time_fallback: + continue + self.WriteLine(f"[{time}] =", 3) + self.WriteLine("{", 3) + for mon_type in self.config.mon_types: + member_name = mon_type.title().replace("_", "") + member_name = member_name[0].lower() + member_name[1:] + "Info" + self.WriteLine(f".{member_name} = NULL,", 4) + self.WriteLine("},", 3) + self.WriteLine("},", 2) + self.WriteLine("},", 1) + + def WritePokemonHeaders(self, headers): + label = headers["label"] + self.WriteLine(f"const struct WildPokemonHeader {label}[] =") + self.WriteLine("{") + for shared_label in headers["data"]: + self.WriteLine() + map_data = headers["data"][shared_label] + encounter_data = map_data + map_group = map_data["mapGroup"] + map_num = map_data["mapNum"] + version = "EMERALD" + if "FireRed" in shared_label: + version = "FIRERED" + elif "LeafGreen" in shared_label: + version = "LEAFGREEN" + + self.WriteLine(f"#ifdef {version}") + + self.WriteLine("{", 1) + self.WriteLine(f".mapGroup = {map_group},", 2) + self.WriteLine(f".mapNum = {map_num},", 2) + self.WriteLine(".encounterTypes =", 2) + self.WriteLine("{", 2) + for time in self.config.times_of_day: + if not self.config.time_encounters and time != self.config.time_fallback: continue + self.WriteLine(f"[{time}] =", 3) + self.WriteLine("{", 3) + for mon_type in self.config.mon_types: + member_name = mon_type.title().replace("_", "") + member_name = member_name[0].lower() + member_name[1:] + "Info" + value = "NULL" + if time in encounter_data and mon_type in encounter_data[time]: + value = encounter_data[time][mon_type] + if value != "NULL": + value = "&" + value + self.WriteLine(f".{member_name} = {value},", 4) - for i, methodPercentIndex in enumerate(method_indices): - if methodPercentIndex < 0 or methodPercentIndex >= len(rates): - print(f"#error Invalid fishing encounter rate index {methodPercentIndex} for {method.upper()}") + self.WriteLine("},", 3) + + self.WriteLine("},", 2) + self.WriteLine("},", 1) + self.WriteLine(f"#endif") + self.WriteTerminator() + self.WriteLine("};") + + + def WriteEncounters(self): + wild_encounter_groups = self.json_data["wild_encounter_groups"] + for wild_encounter_group in wild_encounter_groups: + headers = {} + headers["label"] = wild_encounter_group["label"] + headers["data"] = {} + for_maps = False + map_num_counter = 1 + if "for_maps" in wild_encounter_group: + for_maps = wild_encounter_group["for_maps"] + encounters = wild_encounter_group["encounters"] + + for map_encounters in encounters: + map_group = "0" + map_num = str(map_num_counter) + if for_maps: + map_name = map_encounters["map"] + map_group = f"MAP_GROUP({map_name})" + map_num = f"MAP_NUM({map_name})" + map_num_counter += 1 + base_label = map_encounters["base_label"] + shared_label = base_label + time = self.config.time_fallback + + for time_ident in self.config.times_of_day: + if self.config.times_of_day[time_ident] in base_label: + time = time_ident + shared_label = shared_label.replace('_' + self.config.times_of_day[time_ident], '') + + if shared_label not in headers["data"]: + headers["data"][shared_label] = {} + if time not in headers["data"][shared_label]: + headers["data"][shared_label][time] = {} + headers["data"][shared_label]["mapGroup"] = map_group + headers["data"][shared_label]["mapNum"] = map_num + + version = "EMERALD" + if "FireRed" in shared_label: + version = "FIRERED" + elif "LeafGreen" in shared_label: + version = "LEAFGREEN" + self.WriteLine(f"#ifdef {version}") + for mon_type in self.config.mon_types: + if mon_type not in map_encounters: + headers["data"][shared_label][mon_type] = "NULL" continue - rate_value = rates[methodPercentIndex] - if i == 0: - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex} {rate_value}") - else: - previous_method_index = method_indices[i - 1] - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{previous_method_index} + {rate_value}") + mons_entry = map_encounters[mon_type] + encounter_rate = mons_entry["encounter_rate"] + mons = mons_entry["mons"] - if i == len(method_indices) - 1: - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex})") + mon_array_name = base_label + "_" + mon_type.title().replace("_", "") + self.WriteMonInfos(mon_array_name, mons, encounter_rate) + headers["data"][shared_label][time][mon_type] = mon_array_name + "Info" + self.WriteLine(f"#endif") - fieldCounter += 1 - print() + self.WritePokemonHeaders(headers) -def GetTimeLabelFromString(string): - time = "TIME" - time_ = "TIME_" - - if string == "TIMES_OF_DAY_COUNT": - return string - - if time_ in string.upper(): - return string[len(time_):len(string)] - elif time in string.upper(): - return string[len(time):len(string)] - return string - - -def GetIMonInfoStringFromIndex(index): - return fieldData[index]["infoStringBase"] - - -def GetMapGroupEnum(string, index = 0): - if "MAP_" in string and index == 0: - return "MAP_GROUP(" + string + ")" - elif "MAP_" in string and index != 0: - return "MAP_NUM(" + string + ")" - return index - - -""" -get copied lhea :^ ) -- next four 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[^ ]*)") - - 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 IsDexnavEnabled(): - CONFIG_ENABLED_PAT = re.compile(r"#define DEXNAV_ENABLED\s+(?P[^ ]*)") - - with open("./include/config/dexnav.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 GetTimeEnum(): - DEFAULT_TIME_PAT = re.compile(r"enum\s+TimeOfDay\s*\{(?P[\s*\w+,\=\d*]+)\s*\}\s*\;") - - with open("./include/constants/rtc.h", "r") as rtc_include_file: - include_rtc = rtc_include_file.read() - include_enum = DEFAULT_TIME_PAT.search(include_rtc) - return include_enum.group("rtc_val") - - -def CheckEmpty(string): - return string == "" or string.isspace() or string == "\n" - - -def SetupUserTimeEnum(timeOfDay): - enum_string = GetTimeEnum() - enum_string = enum_string.split(",") - - # check for extra element from trailing comma - if CheckEmpty(enum_string[-1]): - enum_string.pop(-1) - - # we don't need the `TIMES_OF_DAY_COUNT` value, so - 1 from the value of len(enum_string) - strCount = 0 - while strCount < len(enum_string) - 1: - tempStr = enum_string[strCount].strip("\n ") - - """ - we need to ignore any value assignments, as the times will need to correspond - with the elements in the array. - """ - if "=" in tempStr: - tempStr = tempStr[0:tempStr.index("=")] - tempStr = tempStr.strip(" ") - - #double check we didn't catch any empty values - if not CheckEmpty(enum_string[strCount]): - timeOfDay.add(tempStr) - - strCount += 1 - return timeOfDay - - -def TabStr(amount): - return tabStr * amount - - -def GetPascalCase(string): - stringArray = string.split("_") - pascalString = "" - - for string in stringArray: - pascalString += string.capitalize() - return pascalString - - -def GetSnakeCase(string): - stringArray = string.split("_") - snakeString = "" - - i = 0 - for string in stringArray: - if i == 0: - snakeString += string - else: - snakeString += string.capitalize() - - i += 1 - return snakeString - - -def CheckFieldDataDupes(name): - for field in fieldData: - if field["name"] == name: - return True - return False - - -def AddFieldData(index, fieldType, fieldRates): - fieldData.append({}) - fieldData[index]["name"] = fieldType - fieldData[index]["pascalName"] = GetPascalCase(fieldType) - fieldData[index]["snakeName"] = GetSnakeCase(fieldType) - fieldData[index]["encounter_rates"] = fieldRates - +def ConvertToHeaderFile(json_data): + with open('src/data/wild_encounters.h', 'w') as output_file: + config = Config('include/config/overworld.h', 'include/constants/rtc.h', json_data) + assembler = WildEncounterAssembler(output_file, json_data, config) + assembler.WriteHeader() + assembler.WriteMacros() + assembler.WriteEncounters() def main(): - pass + with open('src/data/wild_encounters.json', 'r') as json_file: + json_data = json.load(json_file) + ConvertToHeaderFile(json_data) -if __name__ == "__main__": - 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) - -- if DEXNAV_ENABLED is TRUE -- these macros are 1 and 0, respectively if hidden_mons isn't in the encounter - rate list at the top of wild_encounters.json -#define ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_0 1 -#define ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_1 ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_0 + 0 -#define ENCOUNTER_CHANCE_HIDDEN_MONS_TOTAL (ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_1) - -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, - } - }, -} -""" +if __name__ == '__main__': + main()