diff --git a/docs/tutorials/how_to_time_of_day_encounters.md b/docs/tutorials/how_to_time_of_day_encounters.md index 6e38c16f90..85cd2ac09a 100644 --- a/docs/tutorials/how_to_time_of_day_encounters.md +++ b/docs/tutorials/how_to_time_of_day_encounters.md @@ -2,11 +2,11 @@ ## Table of Contents: - [What is the Time-Based Encounters feature?](#what-is-the-time-based-encounters-feature) -- [Sounds rad, how do I add them to my romhack?](#sounds-rad-how-do-i-add-them-to-my-romhack) -- [I've never added one by hand, but I want to!](#ive-never-added-one-by-hand-but-i-want-to) -- [What are "supported suffixes?"](#what-are-supported-suffixes) -- [That's a lot of manual editing.](#thats-a-lot-of-manual-editing) -- [That's *still* a lot of editing.](#thats-still-a-lot-of-editing) + - [Sounds rad, how do I add it to my romhack?](#sounds-rad-how-do-i-add-it-to-my-romhack) + - [I've never added one by hand, but I want to!](#ive-never-added-one-by-hand-but-i-want-to) + - [What are "supported suffixes?"](#what-are-supported-suffixes) + - [That's a lot of manual editing.](#thats-a-lot-of-manual-editing) + - [That's *still* a lot of editing.](#thats-still-a-lot-of-editing) - [So what are the `#define` options in `overworld.h`?](#so-what-are-the-define-options-in-overworldh) - [Examples](#examples) @@ -15,91 +15,111 @@ Time-Based Encounters lets you pick which Pokémon appear based on the in-game c Gen 2 had this feature, and Gen 4 brought it back- for instance, in Sinnoh's Route 201 you have a higher chance of catching a Bidoof than a Starly at night. -### Sounds rad, how do I add them to my romhack? -There are a couple of ways! The system is built to handle your unchanged [`wild_encounters.json`](../../src/data/wild_encounters.json) file by default, so the most basic solution is to add an encounter group by editing that (by hand or [with Porymap](https://huderlem.github.io/porymap/manual/editing-wild-encounters.html)), and then add a supported suffix to the end of whatever name you give it. +### Sounds rad, how do I add it to my romhack? +There are a couple of ways! The system is built to handle your unchanged [`wild_encounters.json`](../../src/data/wild_encounters.json) file by default, so the most basic solution is to add an encounter group by editing that (by hand or [with Porymap](https://huderlem.github.io/porymap/manual/editing-wild-encounters.html)), and then add a [supported suffix](#what-are-supported-suffixes) to the end of whatever name you give it. + + +> **NOTE**: if you haven't specified or added any encounters, or have the option turned off, Expansion puts them into the `TIME_MORNING` (or whatever your first time enum is set to in the `TimeOfDay` `enum` in [`rtc.h`](../../include/rtc.h)) slot to keep vanilla behavior. This means any map `"base_label"` without a [supported suffix](#what-are-supported-suffixes) is automatically set to the first time slot when `OW_TIME_OF_DAY_ENCOUNTERS` is `TRUE`. When `OW_TIME_OF_DAY_ENCOUNTERS` is `FALSE`, everything regardless of any extant suffixes gets the first time slot suffix (ie `_Morning` for `TIME_MORNING`) so it matches with the 0th index of the [`encounterTypes` array](../../include/wild_encounter.h) in `struct WildMonHeader`. -- NOTE: if you haven't specified/added any encounters, or have the option turned off, Expansion puts them into the `TIME_MORNING` slot to keep vanilla behavior. ### I've never added one by hand, but I want to! Great attitude bestie! It's very simple- all you need is to find your [`wild_encounters.json`](../../src/data/wild_encounters.json) file and open it up in your text/code editor of choice; I recommend VSCodium, but any will work. To get started, we'll use Route 101 as an example: -``` +```json { - "map": "MAP_ROUTE101", - "base_label": "gRoute101", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } - }, + "map": "MAP_ROUTE101", + "base_label": "gRoute101", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } +}, ``` That's it! That's the entire encounter group for Route 101. In other Routes or maps, you'll likely see other encounters listed; here we have only have `land_mons`, but vanilla emerald supports three more types of encounters, for a total of four: - `land_mons`, your standard grass or cave or sand encounter. - `water_mons`, used for surfing -- `fishing_mons`, for fishing - `rock_smash_mons`, for when you get jumpscared by a Geodude in Route 111 after using Rock Smash. +- `fishing_mons`, for fishing + + +> **NOTE**: You can also have more of these encounter types- in fact, expansion has a fifth type of encounter for the Dexnav feature called `hidden_mons`, and some people have entries for `honey_mons` and `headbutt_mons` in their personal hacks as well! This system supports those too, you just need to make sure to update your [`WildEncounters` struct](../../include/wild_encounter.h) definition. You need to keep the order consistent, so as a standard, any custom encounter types should go before `hidden_mons` but after `fishing_mons`. To use the earlier examples: + +```c +struct WildEncounterTypes +{ + const struct WildPokemonInfo *landMonsInfo; + const struct WildPokemonInfo *waterMonsInfo; + const struct WildPokemonInfo *rockSmashMonsInfo; + const struct WildPokemonInfo *fishingMonsInfo; + const struct WildPokemonInfo *honeyMonsInfo; + const struct WildPokemonInfo *headbuttMonsInfo; + const struct WildPokemonInfo *hiddenMonsInfo; +}; +``` +> You can see that the two new entries, `honeyMonsInfo` and `headbuttMonsInfo` (corresponding with `honey_mons` and `headbutt_mons`) are slotted in between `fishingMonsInfo` and `hiddenMonsInfo`. Structs in the C programming language rely on consistent placement with their members, so this is the order that every other instance of these encounter types should maintain. In my ~~expert~~ opinion, the easiest way to add these is again [with Porymap](https://huderlem.github.io/porymap/manual/editing-wild-encounters.html). Okay, take a breath, stretch, and we'll get back to the tutorial! + For the sake of simplicity, I'll show you how to add another encounter group here and pop a supported prefix on it. I want my new encounter group to: - have a fishing table (I'm adding a fishin hole to Route 101) @@ -108,243 +128,243 @@ For the sake of simplicity, I'll show you how to add another encounter group her - only occur at night With all of these things in mind, let's craft an encounter! We'll start off by copying the one we have, called `gRoute101`. -``` +```json { - "map": "MAP_ROUTE101", - "base_label": "gRoute101", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } - }, + "map": "MAP_ROUTE101", + "base_label": "gRoute101", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } +}, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Night", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } - }, + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Night", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } +}, ``` Okay, we have it duplicated. We leave the value for "map": the same as the original so the game knows that both of these encounters are for Route 101. You can see I changed the name of the copy to `gRoute101_Night`; that's one bullet point down! If we enable `OW_TIME_BASED_ENCOUNTERS` in [`overworld.h`](../../include/config/overworld.h), the game will recognize this encounter group goes in the `Night` slot and will switch which group is used to generate the encounters when the in-game clock changes to `TIME_NIGHT`. Next, let's add Spiky Eared Pichu and our two new encounter tables (`fishing_mons` and `rock_smash_mons`). -``` +```json { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Night", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_PICHU_SPIKY_EARED" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - }, - "fishing_mons": { - "encounter_rate": 30, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_MAGIKARP" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_MARILL" - }, - ] - }, - "rock_smash_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_GEODUDE" - }, - ] - } - }, + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Night", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_PICHU_SPIKY_EARED" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + }, + "fishing_mons": { + "encounter_rate": 30, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_MAGIKARP" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_MARILL" + } + ] + }, + "rock_smash_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_GEODUDE" + } + ] + } +}, ``` And there we go! It has the `_Night` suffix, has Spiky Eared Pichu right up at the top of the list, has a couple of fishing encounters, and will jumpscare us with about a 20% chance every time we break a rock with rock smash. That's what the `encounter_rate` line means, by the way- the overall percentage you have of encountering *any* of the Pokémon listed. Congrats! You've just created a brand new encounter group, set its time, and adjusted the encounters! I'd highly recommend doing this [with Porymap](https://huderlem.github.io/porymap/manual/editing-wild-encounters.html)- the interface is very useful for editing maps, including wild encounters! @@ -362,13 +382,17 @@ So, the "supported suffixes" are just: - `_Evening` - `_Night` -### That's a lot of manual editing. + +> **NOTE**: You can add more than just these by changing the `TimeOfDay` `enum` in [`rtc.h`](../../include/rtc.h). If you'd like to do this, I'd recommend making a backup of your [`wild_encounters.json`](../../src/data/wild_encounters.json) somewhere outside your project folder, just so you can have a baseline to return to if something goes wrong. The [migration script](../../migration_scripts/add_time_based_encounters.py) makes a backup of the file ***each time it runs***, so it's essentially a one step undo button- if you plan on or think you might make lots of edits to [`wild_encounters.json`](../../src/data/wild_encounters.json), ***it is a very good idea to make a baseline backup***. + + +### That's a lot of manual editing. You're so right bestie! Luckily for you, there's a python script that can help you out! The script is at [`migration_scripts/add_time_based_encounters.py`](../../migration_scripts/add_time_based_encounters.py). It, in order: -- Checks to make sure you're running it from the [root folder](../../) of your expansion project (specifically, wherever the project's [`Makefile`](../../Makefile) is) -- Makes a backup of your [`wild_encounters.json`](../../src/data/wild_encounters.json) file called `wild_encounters.json.bak` -- Runs through `wild_encounters.json` and adds dummy encounter groups for each time denomination to each group - - ie, `gRoute101` becomes `gRoute101_Morning`, `gRoute101_Day`, `gRoute101_Evening`, and `gRoute101_Night` +1. Checks to make sure you're running it from the [root folder](../../) of your expansion project (specifically, wherever the project's [`Makefile`](../../Makefile) is) +2. Makes a backup of your [`wild_encounters.json`](../../src/data/wild_encounters.json) file called `wild_encounters.json.bak` +3. Runs through `wild_encounters.json` and adds dummy encounter groups for each time denomination to each group + - ie, `gRoute101` becomes `gRoute101_Morning`, `gRoute101_Day`, `gRoute101_Evening`, and `gRoute101_Night` This script works kind of like a "template" feature- when you open it up to edit either in Porymap or a text editor, you will see the encounter groups, but they won't be filled out with encounters. This lets you add Pokémon with your own encounter rates however you want. @@ -376,32 +400,29 @@ This script works kind of like a "template" feature- when you open it up to edit You're *still* so right bestie! Luckily for you, there's an optional argument you can add when you run the script: `--copy`. This duplicates the encounter group's encounters as well as their labels/map group values. When you open [`wild_encounters.json`](../../src/data/wild_encounters.json) for editing either in Porymap or a text editor, you'll notice that each group (`gRoute101_Morning`, `gRoute101_Day`, `gRoute101_Evening`, and `gRoute101_Night`) now all have the same encounters as `gRoute101` did. If you only want to add a couple of Pokémon here and there for each time of day, this is probably the easier option. -- NOTE: the `--copy` option will use up an additional 9kb of ROM space. Obviously that's not much even for a GBA ROM, but it's something to keep in mind. + +> **NOTE**: the `--copy` option will use up at least an additional 9kb of ROM space. Obviously that's not much even for a GBA ROM, but it's something to keep in mind. + ## So what are the `#define` options in [`overworld.h`](../../include/config/overworld.h)? Great questie bestie! Here's a rundown, with more information than what's in the comments at [`overworld.h`](../../include/config/overworld.h) and their default values: - ``` -- OW_TIME_OF_DAY_ENCOUNTERS FALSE - ``` +``` +OW_TIME_OF_DAY_ENCOUNTERS FALSE +``` - **Acceptable values**: `TRUE` or `FALSE` - this option enables or disables the feature. You'll notice your used ROM space changing when this is enabled or disabled, as the [json->C header conversion file](../../tools/wild_encounters/wild_encounters_to_header.py) will generate the `encounterTypes` array in [`wild_encounter.h`](../../include/wild_encounter.h) with different sizes based on whether this value is `TRUE` or `FALSE`. - ``` -- OW_TIME_OF_DAY_DISABLE_FALLBACK FALSE - ``` +``` +OW_TIME_OF_DAY_DISABLE_FALLBACK FALSE +``` - **Acceptable values**: `TRUE` or `FALSE` - - this option controls the behavior of the game when an encounter table isn't populated. If this is set to `TRUE`, whenever the game detects that you're in a time of day (Morning/Day/Evening/Night) on a map without any encounters for that time, you won't encounter any mons. If this is set to `FALSE`, the game will look for encounters at the time specified in the `OW_TIME_OF_DAY_FALLBACK` option at the bottom. - ``` -- OW_TIME_OF_DAY_DEFAULT TIME_MORNING - ``` + - this option controls the behavior of the game when an encounter table isn't populated. If this is set to `TRUE`, whenever the game detects that you're in a time of day (Morning/Day/Evening/Night) on a map without any encounters for that time, you won't encounter any mons. If this is set to `FALSE`, the game will look for encounters at the time specified in the `OW_TIME_OF_DAY_FALLBACK` option below. +``` +OW_TIME_OF_DAY_FALLBACK TIME_MORNING +``` - **Acceptable values**: any value from the [`TimesOfDay`](../../include/rtc.h) enum, so by default `TIME_MORNING`, `TIME_DAY`, `TIME_EVENING`, and `TIME_NIGHT`. - - this option specifies what time is the first value in the [`TimesOfDay`](../../include/rtc.h) enum. This should always be the first value there (`TIME_MORNING` by default), because it's how both the [migration script](../../migration_scripts/add_time_based_encounters.py) and the [json->C header conversion file](../../tools/wild_encounters/wild_encounters_to_header.py) determine what elements go where when the encounters are converted. - ``` -- OW_TIME_OF_DAY_FALLBACK OW_TIME_OF_DAY_DEFAULT - ``` - - **Acceptable values**: any value from the [`TimesOfDay`](../../include/rtc.h) enum, so by default `TIME_MORNING`, `TIME_DAY`, `TIME_EVENING`, and `TIME_NIGHT`. - - this option controls which time is used when `OW_TIME_OF_DAY_DISABLE_FALLBACK` is `FALSE`. It's set to the same value as `OW_TIME_OF_DAY_DEFAULT` by... default. Keep in mind that if you enable `OW_TIME_OF_DAY_ENCOUNTERS` and set this to something other than `TIME_MORNING`, you should make sure that time has encounters, or you won't encounter anything. + - this option controls which time is used when `OW_TIME_OF_DAY_DISABLE_FALLBACK` is `FALSE`. Keep in mind that if you enable `OW_TIME_OF_DAY_ENCOUNTERS` and set this to something other than `TIME_MORNING`, you should make sure that time has encounters, or you won't encounter anything. ## Examples @@ -414,91 +435,90 @@ python3 migration_scripts/add_time_based_encounters.py ``` #### Result: -``` +```json "encounters": [ + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Morning", + "land_mons": { + "encounter_rate": 20, + "mons": [ { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Morning", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" }, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Day" + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" }, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Evening" + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" }, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Night" + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } + }, + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Day" + }, + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Evening" + }, + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Night" + }, ] - ``` As you can see, the names change, but the encounters aren't touched, so you're free to add your own, piecemeal style. If you don't have any encounters for a map and time, the game will use `OW_TIME_OF_DAY_FALLBACK` *if* `OW_TIME_OF_DAY_DISABLE_FALLBACK` is `FALSE`; otherwise, you won't encounter anything. @@ -510,284 +530,284 @@ python3 migration_scripts/add_time_based_encounters.py --copy ``` #### Result: -``` +```json "encounters": [ + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Morning", + "land_mons": { + "encounter_rate": 20, + "mons": [ { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Morning", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" }, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Day", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" }, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Evening", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" }, { - "map": "MAP_ROUTE101", - "base_label": "gRoute101_Night", - "land_mons": { - "encounter_rate": 20, - "mons": [ - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_WURMPLE" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_POOCHYENA" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 2, - "max_level": 2, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - }, - { - "min_level": 3, - "max_level": 3, - "species": "SPECIES_ZIGZAGOON" - } - ] - } + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" }, - ] + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } + }, + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Day", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } + }, + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Evening", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } + }, + { + "map": "MAP_ROUTE101", + "base_label": "gRoute101_Night", + "land_mons": { + "encounter_rate": 20, + "mons": [ + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_WURMPLE" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_POOCHYENA" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 2, + "max_level": 2, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + }, + { + "min_level": 3, + "max_level": 3, + "species": "SPECIES_ZIGZAGOON" + } + ] + } + }, +] ``` -As you can see, the group `gRoute101` and all its encounters were copied into groups that correspond with the four vanilla times of day (Morning/Day/Evening/Night). \ No newline at end of file +As you can see, the group `gRoute101` and all its encounters were copied into groups that correspond with the four vanilla times of day (Morning/Day/Evening/Night). \ No newline at end of file diff --git a/include/config/overworld.h b/include/config/overworld.h index d3382913de..739aaeee77 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -90,8 +90,7 @@ #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. +#define OW_TIME_OF_DAY_FALLBACK TIME_MORNING // The time of day that encounter tables fall back to. // Lighting #define OW_SHADOW_INTENSITY 4 // Ranges from 0 to 16, where 0 is fully transparent and 16 is black. diff --git a/include/rtc.h b/include/rtc.h index 549ab9019b..13a1207b56 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -95,7 +95,7 @@ enum TimeOfDay TIMES_OF_DAY_COUNT, }; -STATIC_ASSERT(OW_TIME_OF_DAY_DEFAULT == 0, TimeOfDayDefaultMustBeFirstElementInTimeOfDayEnum) +#define TIME_OF_DAY_DEFAULT 0 extern struct Time gLocalTime; extern const s32 sNumDaysInMonths[12]; diff --git a/migration_scripts/add_time_based_encounters.py b/migration_scripts/add_time_based_encounters.py index c26d86019e..aebdafc2b2 100644 --- a/migration_scripts/add_time_based_encounters.py +++ b/migration_scripts/add_time_based_encounters.py @@ -2,29 +2,21 @@ 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" -] +try: + if not os.path.exists("./tools/wild_encounters/"): + 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 +except ImportError: + print("Could not import the file tools/wild_encounters/wild_encounters_to_header.py") + quit() 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 +TIME_OF_DAY_DEFAULT = 0 def GetWildEncounterFile(): @@ -32,6 +24,8 @@ 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) @@ -48,14 +42,14 @@ def GetWildEncounterFile(): if arg == ARGS[0]: COPY_FULL_ENCOUNTER = True - j = 0 + encounterCount = 0 for group in wData["wild_encounter_groups"]: - wEncounters = wData["wild_encounter_groups"][j]["encounters"] + wEncounters = wData["wild_encounter_groups"][encounterCount]["encounters"] editMap = True wEncounters_New = list() for map in wEncounters: - for suffix in ENCOUNTER_GROUP_SUFFIX: + for suffix in timeOfDay.fvals: tempSuffix = "_" + suffix if tempSuffix in map["base_label"]: editMap = False @@ -65,9 +59,9 @@ def GetWildEncounterFile(): if editMap: k = 0 - for suffix in ENCOUNTER_GROUP_SUFFIX: + for suffix in timeOfDay.fvals: tempDict = dict() - if k == OW_TIME_OF_DAY_DEFAULT or COPY_FULL_ENCOUNTER: + if k == TIME_OF_DAY_DEFAULT or COPY_FULL_ENCOUNTER: tempDict = map.copy() tempMapLabel = "" @@ -86,8 +80,8 @@ def GetWildEncounterFile(): else: wEncounters_New.append(map.copy()) - wData["wild_encounter_groups"][j]["encounters"] = wEncounters_New - j += 1 + wData["wild_encounter_groups"][encounterCount]["encounters"] = wEncounters_New + encounterCount += 1 wNewData = json.dumps(wData, indent=2) wNewFile = open("src/data/wild_encounters.json", mode="w", encoding="utf-8") diff --git a/src/rtc.c b/src/rtc.c index 178e6b24ad..a0d85b2701 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -334,7 +334,7 @@ enum TimeOfDay GetTimeOfDay(void) enum TimeOfDay GetTimeOfDayForDex(void) { - return OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : OW_TIME_OF_DAY_DEFAULT; + return OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : TIME_OF_DAY_DEFAULT; } void RtcInitLocalTimeOffset(s32 hour, s32 minute) diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 3db2402d2f..dfb63e82d2 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -381,7 +381,7 @@ enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area enum TimeOfDay timeOfDay = GetTimeOfDay(); if (!OW_TIME_OF_DAY_ENCOUNTERS) - return OW_TIME_OF_DAY_DEFAULT; + return TIME_OF_DAY_DEFAULT; if (InBattlePike()) { diff --git a/tools/wild_encounters/wild_encounters_to_header.py b/tools/wild_encounters/wild_encounters_to_header.py index 0ea958de9c..38c62d5cc7 100644 --- a/tools/wild_encounters/wild_encounters_to_header.py +++ b/tools/wild_encounters/wild_encounters_to_header.py @@ -18,51 +18,15 @@ MAP_UNDEFINED = "MAP_UNDEFINED" 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 +fieldData = [] +fieldInfoStrings = [] +fieldStrings = [] # time of day encounter data -TIME_DEFAULT = "OW_TIME_OF_DAY_DEFAULT" -TIME_DEFAULT_LABEL = "" +TIME_DEFAULT = "" +TIME_DEFAULT_LABEL = "TIME_OF_DAY_DEFAULT" 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 +TIMES_OF_DAY_COUNT = TIME_DEFAULT_INDEX + 1 # struct building blocks baseStruct = "const struct WildPokemon" @@ -90,24 +54,49 @@ 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 +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(): @@ -117,11 +106,18 @@ def ImportWildEncounterFile(): quit() global MON_HEADERS - global landMonsInfo - global waterMonsInfo - global rockSmashMonsInfo - global fishingMonsInfo - global hiddenMonsInfo + + 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 fieldInfoStrings + global fieldStrings global structLabel global structMonType global structTime @@ -134,19 +130,13 @@ def ImportWildEncounterFile(): global headerStructContent global hLabel global headersArray - global eLandMons - global eWaterMons - global eRockSmashMons - global eFishingMons global encounterTotalCount global encounterCount global headerIndex + global fieldData global tabStr tabStr = " " - global IS_ENABLED - IS_ENABLED = IsConfigEnabled() - wFile = open("src/data/wild_encounters.json") wData = json.load(wFile) @@ -174,97 +164,101 @@ def ImportWildEncounterFile(): # for the encounter rate macros, so we don't worry about hidden mons here if headerIndex == 0: wFields = wData["wild_encounter_groups"][headerIndex]["fields"] + fieldCounter = 0 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"]) + fieldData.append({}) + fieldData[fieldCounter]["name"] = field["type"] + fieldData[fieldCounter]["pascalName"] = GetPascalCase(field["type"]) + fieldData[fieldCounter]["snakeName"] = GetSnakeCase(field["type"]) + fieldData[fieldCounter]["encounter_rates"] = field["encounter_rates"] - PrintGeneratedWarningText() + if "groups" in field: + fieldData[fieldCounter]["groups"] = field["groups"] - print('#include "rtc.h"') - print("\n") + if fieldCounter == len(wFields) - 1: + fieldData.append({}) + fieldData[fieldCounter + 1]["name"] = "hidden_mons" + fieldData[fieldCounter + 1]["pascalName"] = GetPascalCase("hidden_mons") + fieldData[fieldCounter + 1]["snakeName"] = GetSnakeCase("hidden_mons") + + fieldCounter += 1 + + if printWarningAndInclude: + 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 = [] + + 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 - 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" + timeCounter += 1 + + fieldCounter = 0 + fieldInfoStrings = [] + while fieldCounter < len(fieldData): + fieldInfoStrings.append("") + fieldStrings.append("") + fieldCounter += 1 - 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 + 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())) + 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 "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} {structLabel}_{structMonType}{structInfo} = {{ {infoStructRate}, {structLabel}_{structMonType} }};" - print(infoStructString) + if printEncounterStructsInfoString: + infoStructString = f"{baseStruct}{structInfo} {fieldInfoStrings[fieldCounter]} = {{ {infoStructRate}, {fieldStrings[fieldCounter]} }};" + print(infoStructString) + fieldCounter += 1 AssembleMonHeaderContent() headerIndex += 1 PrintWildMonHeadersContent() @@ -282,24 +276,37 @@ def GetStructLabelWithoutTime(label): 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))] + + 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(): - global structLabel - SetupMonInfoVars() tempHeaderLabel = GetWildMonHeadersLabel() - tempHeaderTimeIndex = GetTimeIndexFromString(structTime) + tempHeaderTimeIndex = GetStructTimeWithoutLabel(structLabel) structLabelNoTime = GetStructLabelWithoutTime(structLabel) if tempHeaderLabel not in headerStructTable: @@ -314,55 +321,30 @@ def AssembleMonHeaderContent(): 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: + timeCounter = 0 + while timeCounter < TIMES_OF_DAY_COUNT: headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"].append([]) - timeStart += 1 + timeCounter += 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) + fieldCounter = 0 + while fieldCounter < len(fieldData): + headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(fieldInfoStrings[fieldCounter]) + fieldCounter += 1 def SetupMonInfoVars(): - global landMonsInfo - global waterMonsInfo - global rockSmashMonsInfo - global fishingMonsInfo - global hiddenMonsInfo + 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] - if landMonsInfo == "": - landMonsInfo = NULL - else: - landMonsInfo = f"&{landMonsInfo}" + i += 1 - 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 @@ -386,12 +368,13 @@ def PrintWildMonHeadersContent(): PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =") PrintEncounterHeaders(TabStr(2) + "{") - infoCount = 0 - for monInfo in headerStructTable[group][label][stat]: - PrintEncounterHeaders(f"{TabStr(3)}[{GetTimeStrFromIndex(infoCount)}] = ") + 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 <= MONS_INFO_TOTAL - 1: + while infoIndex < len(fieldData): if infoIndex == 0: PrintEncounterHeaders(TabStr(3) + "{") @@ -400,11 +383,11 @@ def PrintWildMonHeadersContent(): else: PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = {monInfo[infoIndex]},") - if infoIndex == MONS_INFO_TOTAL - 1: + if infoIndex == len(fieldData) - 1: PrintEncounterHeaders(TabStr(3) + "},") infoIndex += 1 - infoCount += 1 + timeCounter += 1 PrintEncounterHeaders(TabStr(2) + "},") PrintEncounterHeaders(tabStr + "},") @@ -413,23 +396,22 @@ def PrintWildMonHeadersContent(): 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: + while nullCount < TIMES_OF_DAY_COUNT: if nullCount == 0: PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =") PrintEncounterHeaders(TabStr(2)+ "{") - PrintEncounterHeaders(f"{TabStr(3)}[{GetTimeStrFromIndex(nullCount)}] = ") + PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[nullCount]}] = ") nullIndex = 0 - while nullIndex <= MONS_INFO_TOTAL - 1: + while nullIndex <= len(fieldData) - 1: if nullIndex == 0: PrintEncounterHeaders(TabStr(3) + "{") PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(nullIndex)} = NULL,") - if nullIndex == MONS_INFO_TOTAL - 1: + if nullIndex == len(fieldData) - 1: PrintEncounterHeaders(TabStr(3) + "},") nullIndex += 1 @@ -454,108 +436,70 @@ 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}") + fieldCounter = 0 + # len(fieldData) - 1 here so we skip hidden_mons + while fieldCounter < len(fieldData) - 1: + tempName = fieldData[fieldCounter]["name"].upper() + if "groups" not in fieldData[fieldCounter]: + rateCount = 0 + for percent in fieldData[fieldCounter]["encounter_rates"]: + 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: - print( - f"{define} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount - 1} + {percent}" - ) + rates = fieldData[fieldCounter]["encounter_rates"] + groups = fieldData[fieldCounter]["groups"] - if rateCount + 1 == len(eLandMons): - print( - f"{define} {ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{LAND_MONS.upper()}_{SLOT}_{rateCount})" - ) - rateCount += 1 + for method in groups: + method_indices = groups[method] + if not method_indices: + continue - 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}" - ) + 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()}") + continue - if rateCount + 1 == len(eWaterMons): - print( - f"{define} {ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{WATER_MONS.upper()}_{SLOT}_{rateCount})" - ) - rateCount += 1 + 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}") - 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 i == len(method_indices) - 1: + print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex})") - 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})" - ) + fieldCounter += 1 + print() -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 GetTimeLabelFromString(string): + time = "TIME" + time_ = "TIME_" + if string == "TIMES_OF_DAY_COUNT": + return string -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 + 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): - 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 + return fieldData[index]["infoStringBase"] def GetMapGroupEnum(string, index = 0): @@ -568,7 +512,7 @@ def GetMapGroupEnum(string, index = 0): """ get copied lhea :^ ) -- next two functions copied almost verbatim from @lhearachel's python scripts in tools/learnset_helpers +- next three functions copied almost verbatim from @lhearachel's python scripts in tools/learnset_helpers """ def PrintGeneratedWarningText(): print("//") @@ -586,12 +530,82 @@ def IsConfigEnabled(): 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/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): - global tabStr return tabStr * amount -ImportWildEncounterFile() +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 main(): + pass + + +if __name__ == "__main__": + ImportWildEncounterFile() """