diff --git a/.flipcorg/gallery/1.png b/.flipcorg/gallery/1.png index f8dc9a79417..a3d07c75ca4 100644 Binary files a/.flipcorg/gallery/1.png and b/.flipcorg/gallery/1.png differ diff --git a/.flipcorg/gallery/2.png b/.flipcorg/gallery/2.png index 6c535fae6e3..b84acaacdc9 100644 Binary files a/.flipcorg/gallery/2.png and b/.flipcorg/gallery/2.png differ diff --git a/.flipcorg/gallery/4.png b/.flipcorg/gallery/4.png index 3d3cc24a1a1..96639abe3f4 100644 Binary files a/.flipcorg/gallery/4.png and b/.flipcorg/gallery/4.png differ diff --git a/.flipcorg/gallery/5.png b/.flipcorg/gallery/5.png index 3922a48ac2c..758fa86ad3a 100644 Binary files a/.flipcorg/gallery/5.png and b/.flipcorg/gallery/5.png differ diff --git a/.flipcorg/gallery/6.png b/.flipcorg/gallery/6.png index 6ea07c08021..426457d8c15 100644 Binary files a/.flipcorg/gallery/6.png and b/.flipcorg/gallery/6.png differ diff --git a/.gitignore b/.gitignore index 94f1119ef02..d06ba491174 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store .vscode +dist/ diff --git a/README.md b/README.md index ca985a15c50..958cdc53f81 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,79 @@ # GAME BOY Pokemon Trading MALVEKE -

- - Flipper Zero - Pokemon Trading Game Boy - -
-

+## Watch it in Action +The video below trades a Bulbasaur from the Flipper to a Game Boy Color with Pokemon Silver. The Game Boy trades its Cyndaquil. The Flipper is then used to modify the Cyndaquil to infect it with Pokerus, modify its EVs and IVs, and have the Cyndaquil hold an Antidote before it is traded back to the Game Boy. + +[![Watch a Trade in Action](docs/images/yt-vid-preview-frame.png)](http://www.youtube.com/watch?v=zONctHIPgEo "Trade in action") -
+## Contents +- [Introduction](#introduction) +- [Hardware Interface](#hardware-interface) +- [Installation Directions](#installation-directions) +- [Instructions for Use](#instructions-for-use) + - [Main Menu](#main-menu) + - [Pinout](#pinout) + - [Customizing Pokemon](#customizing-pokemon) + - [Trade](#trade-pkmn) + - [Modifying Traded Pokemon](#modifying-traded-pokemon) +- [How it Works / Build your own Interface](#how-does-it-work) -**FW Official** | **FW Unleashed** | **FW RogueMaster** | **FW Xtreme** -:- | :- | :- | :- -[![FlipC.org](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/badge?branch=main)](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading?branch=main)|[![FlipC.org](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/badge?branch=main&firmware=unleashed)](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading?branch=main&firmware=unleashed)|[![FlipC.org](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/badge?branch=main&firmware=roguemaster)](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading?branch=main&firmware=roguemaster)|[![FlipC.org](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/badge?branch=main&firmware=xtreme)](https://flipc.org/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading?branch=main&firmware=xtreme) -
## Introduction -This is a Pokemon exchange application from Flipper Zero to Game Boy [(Generaction I)](https://bulbapedia.bulbagarden.net/wiki/Generation_I). Flipper Zero emulates a "Slave" Game Boy connected to a Game Link Cable to be able to exchange any Pokemon from the First Generation (Red, Blue, Yellow) to a real Game Boy. +This is a Pokemon exchange application from Flipper Zero to Game Boy supporting Generation I and II games; Red, Blue, Yellow, Gold, Silver, and Crystal (all non-Japanese regions[^JPN]). It allows trading Pokemon to and from a Game Boy; allowing for customization and/or modification of Pokemon. + +[^JPN]: Japanese releases of all Generation I and II games use a different data layout, this application implements the data layout used in all other global regions. Attempting to trade between a Japanese cartridge and the Flipper [risks corrupting or erasing save data](https://web.archive.org/web/20221009111851/http://www.nintendo.com/consumer/systems/gameboy/trouble_specificgame.jsp#erasing) + +Generation I customization options: -It currently trades a Pokemon based on your choice of Pokemon, Level, Stats and 4 Moves. +- Pokemon +- Nickname +- Level +- Move set +- Types[^TYPES] +- EV/IV[^EVIV] +- OT ID Number[^OT] +- OT Name[^OT] + +Generation II customization options: + +- Pokemon +- Nickname +- Level +- Held item +- Move set +- EV/IV[^EVIV] +- Shininess[^IV] +- Gender[^IV] +- Pokerus +- Unown form[^IV] +- OT ID Number[^OT] +- OT Name[^OT] + +Once a Pokemon is traded between the Flipper and a Game Boy the Pokemon is kept in memory on the Flipper. This allows a user to back out of the trade screen on the Flipper, modify the Pokemon, and trade it back. Any of the above customization can be modified and the Pokemon traded back to the Game Boy for updated game play. Want a Pokemon to learn a move before it should? Make a Pokemon Shiny? Change its OT ID/Name to get an exp boost? This is how you do it! + +[^TYPES]: Types are overwritten with the defaults when a Pokemon evolves or at the end of a battle where a Pokemon used a move that would temporarily change its types +[^EVIV]: EV/IV can be configured in combinations of the following: Random IV, Max IV, Max EV, Max EV for the current level, Zero EV +[^OT]: Setting this to match the trainer details of the Pokemon game will cause the game to treat the Pokemon as if it were caught by the player rather than traded +[^IV]: Changing this option will modify the Pokemon's IVs and may affect other attributes that are calculated from IVs ## Hardware Interface The Game Boy is connected to the Flipper Zero's GPIO pins via a GBC style Game Link Cable. The [Flipper GB Link module](https://www.tindie.com/products/kbembedded/game-link-gpio-module-for-flipper-zero-game-boy/) is an easy way to connect a Game Boy via a Game Link Cable to the Flipper Zero.

-Flipper GB Link module +Flipper GB Link module

I sell on Tindie

-Additionally, the [MALVEKE - GAME BOY Tools for Flipper Zero](https://www.tindie.com/products/efuentealba/malveke-game-boy-tools-for-flipper-zero/) is supported by this tool. +Additionally, the [MALVEKE - GAME BOY Tools for Flipper Zero](https://www.tindie.com/products/efuentealba/malveke-game-boy-tools-for-flipper-zero/) is supported by this tool. As of version 2.0 of the Pokemon Trading tool, older style MALVEKE pinouts can be used without affecting the OK button after a trade -- this allows users to customize and modify traded Pokemon and there is no need to hard reset the flipper after a trade!

-MALVEKE +MALVEKE

@@ -47,236 +84,303 @@ Details on the hardware interface, as well as how to create your own adapter boa ## Installation Directions -This project is intended to be overlaid on top of an existing firmware repo, in my case the **Release 0.79.1** version. - -- Clone the [Flipper Zero firmware repository](https://github.com/flipperdevices/flipperzero-firmware). Refer to [this tutorial](https://github.com/jamisonderek/flipper-zero-tutorials/tree/main/firmware/updating/README.md) for updating the firmware. -- Copy the "pokemon" folder into the `/applications_user/pokemon` folder in your firmware. -- Run the command `fbt launch` to run it on your Flipper Zero. +This application can be installed through the [Flipper Application Catalog](https://lab.flipper.net/apps/pokemon), the [Flipper Mobile Application](https://docs.flipper.net/mobile-app), or a pre-compiled application binary can be found on the [Releases](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/releases) page of this repo. -```bash -./fbt launch APPSRC=pokemon -``` +The application can also be built from source using [ufbt](https://github.com/flipperdevices/flipperzero-ufbt) or compiling the application against a firmware of choice using [fbt](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppsOnSDCard.md). This will install the application to the `apps/GPIO/` folder on the Flipper's SD card. -- NOTE: If you only want to generate the fap file, you must run the following command. +Manually built application can be copied to the SD card using [qFlipper](https://docs.flipper.net/qflipper). -```bash -./fbt fap_pokemon -``` +

+
+

-And use [**qFlipper**](https://flipperzero.one/update) to copy the generated **pokemon.fap** file to the `SD Card/apps/Game Boy` folder. +## Instructions for Use +### Main Menu +From the main menu, select the generation of Pokemon game to trade with, first changing the `Pinout` if needed. Note that Gen I can trade with Gen I games as well as to Gen II games using Time Capsule trade. Gen II can only trade with Gen II games.

-
+
+ +

-## Instructions for use. +### Pinout -These instructions assume that you are starting at the Flipper Zero desktop. Otherwise, press the Back button until you are at the desktop. +If you're using a MALVEKE PCB that is Rev. 2.5.1 or newer, a Flipper-GB-Link PCB, or a custom wired interface based on the [wiring diagram listed here](#how-does-it-work), then there is no need to worry about setting the pinout; the application default is for these devices. If you're using a MALVEKE PCB Rev. 2.5 or older, select the `MLVK2.5` pinout. For custom wired interfaces that don't follow either standard, select the `Custom` pinout and set each pin individually. - If you're using a MALVEKE PCB version, verify the **Pinout** configuration:


- +

- - MALVEKE **2.5** PCB Version: If you're using this version, select the `MALVEKE` configuration. + - MALVEKE **2.5** PCB Version: If you're using this version, select the `MLVK2.5` configuration.


- +

- MALVEKE **2.5.1** PCB Version: If you're using this version, select the `ORIGINAL`


- +

-- Press the `OK` button on the Flipper to open the main menu. -- Choose `Applications` from the menu. -- Choose `GPIO` from the submenu. -- Choose `Pokemon Trading` -- The Flipper Zero will show the main menu of the application. The first option is to select the Pokemon to trade. +### Customizing Pokemon +- [Select Pokemon](#select-pokemon-gen-i--gen-ii) (Gen I & II) +- [Nickname](#nickname-gen-i--gen-ii) (Gen I & II) +- [Level](#level-gen-i--gen-ii) (Gen I & II) +- [Held Item](#held-item-gen-ii-only) (Gen II only) +- [Select Moves](#select-moves-gen-i--gen-ii) (Gen I & II) +- [Select Types](#select-types-gen-i-only) (Gen I only) +- [Stats](#stats-gen-i--gen-ii) (Gen I & II) +- [Shiny](#shiny-gen-ii-only) (Gen II only) +- [Gender](#gender-gen-ii-only) (Gen II only) +- [Pokerus](#pokerus-gen-ii-only) (Gen II only) +- [Unown Form](#unown-form-gen-ii-only) (Gen II only) +- [OT ID# / Name](#ot-id--name-gen-i--gen-ii) (Gen I & II) + +#### Select Pokemon (Gen I / Gen II) +To select a Pokemon, use `LEFT` and `RIGHT` buttons to select the Pokemon; `UP` and `DOWN` are used to page up/down by 10 Pokemon. Press `OK` to confirm selection, or `BACK` to cancel selection. If a different Pokemon is selected, the remaining customization options are set to the default for that Pokemon. -

-
- -
-

+

+
+ +
+

-- Press the `LEFT`/`RIGHT` buttons to paginate the selection of Pokemon by 1. -- Press the `UP`/`DOWN` buttons to paginate the selection of Pokemon by 10. -- Press the `OK` button to select the Pokemon to trade and return to the main menu +

+
+
+

-

-
-
-

+--- -- The traded Pokemon's nickname can be set. When a Pokemon is selected, the nickname defaults to the species name in all caps. This mimics a Pokemon without a customized nickname. In order to reset this nickname to its default, clear the text entry field, press `OK` on the `Save` button. This will fill the text box with the default name. Press `Save` again to set this name. - - **Note:** The Nidoran♀ and Nidoran♂ names will not properly render. This is because the Flipper currently cannot print unicode characters to screen. Following the above instructions will fill the text entry field with `NIDORAN ` with a space after it. This space is the unrenderable ♀/♂ symbol. Once traded, it will be correctly named. - - **Note:** Only alphanumeric characters are supported in the Pokemon's nickname at this time. +#### Nickname (Gen I / Gen II) +The selected Pokemon's nickname can be set. When a Pokemon is selected, the nickname defaults to the species name in all caps. This mimics a Pokemon without a customized nickname. In order to reset this nickname to its default, clear the text entry field, press `OK` on the `Save` button. This will fill the text box with the default name. Press `Save` again to set this name. -

-
- -
-

+> [!IMPORTANT] +> Nidoran♀ and Nidoran♂ names will not properly render. This is because the Flipper currently cannot print Unicode characters to screen. Following the above instructions will fill the text entry field with `NIDORAN ` with a space after it. This space is the unrenderable ♀/♂ symbol. Once traded, it will be correctly named. -- The Pokemon's level can be adjusted as well by hitting `OK` on the level option. The minimum level is `2` and the maximum is `100`. The level is input via a text box. (Levels below 2 cause an underflow glitch in Gen I games that would cause the level to jump to 100, so if you want this just set the Pokemon's level to 100) - -

-
- -
-

+> [!NOTE] +> (Gen II only) The hyphen in `HO-OH` cannot be selected on the Flipper's keyboard input; however resetting the name as noted above will restore the default name. -- The `Select Moves` menu is used to pick the set the traded Pokemon's moves. They are pre-populated with the moveset that the Pokemon would know at level 1. Selecting a move slot will bring up an alphabetical index of moves. Additionally, `No Move` and `Default` can be quickly selected. Note that any move after the first `No Move` is ignored. +> [!NOTE] +> Only English alphabetical characters are supported in the Pokemon's nickname at this time. -

-
- -
-

+

+
+ +
+

-

-
- -
-

+--- -- The `Select Types` menu can change the traded Pokemon's types. The type(s) are pre-set to what the selected Pokemon normally is. - - Pokemon with a single type will have the same type set for both types. - - **Note:** Unlike other menus, changing either type immediately saves it. Pressing `Back` will keep any changes. This will be addressed in a later version. If you need to revert to the default types, a different Pokemon can be selected and the desired Pokemon re-selected. - - **Note:** When changing the type(s), the Pokemon's in-game stats will _NOT_ reflect the chosen type(s). Additionally, these may be overwritten back to default in-game if the Pokemon uses a move that affects types (e.g. `Transform`) or the Pokemon evolves. +#### Level (Gen I / Gen II) +Set the Pokemon's level from `2` to `100`. This will recalculate the Pokemon's stats based on the new level and the current EV/IV settings. -

-
- -
-

+> [!TIP] +> Levels below 2 cause an underflow glitch in Gen I and II games that would cause the level to jump to 100, so if you want this just set the Pokemon's level to 100. + +

+
+ +
+

+ +--- + +#### Held Item (Gen II only) +The traded Pokemon can be given an item to hold. All of the valid items (including items a Pokemon can normally not be given to hold) are listed in alphabetical order. + +

+
+ +
+

+ +--- + +#### Select Moves (Gen I / Gen II) +The `Select Moves` menu is used to modify the traded Pokemon's moves. They are pre-populated with the moveset that the Pokemon would know at level 1. Selecting a move slot will bring up an alphabetical index of moves. Additionally, `No Move` and `Default` can be quickly selected. + +> [!NOTE] +> Any move in the moveset after the first `No Move` is ignored and is treated as `No Move` by the game. -- The Pokemon's stats can also be influenced. The current settings are: - - `Random IV, Zero EV` Mimics stats of a caught wild Pokemon. - - `Random IV, Max EV / Level` IV is randomized, but EV is set to the maximum a trained Pokemon could be for its current level. - - `Randon IV, Max EV` IV is randomized, EV is set to the absolute max for a perfectly trained Pokemon. - - `Max IV, Zero EV` Mimics stats of a caught wild Pokemon, but with the maximum IV possible. - - `Max IV, Max EV / Level` IV is max, EV is set to the maximum a trained Pokemon could be for its current level. - - `Max IV, Max EV` Absolutely perfect and overly powerful Pokemon. +

+
+ +
+

+ +

+
+ +
+

+ +--- + +#### Select Types (Gen I only) +The `Select Types` menu can change the traded Pokemon's types. The type(s) are pre-set to what the selected Pokemon normally is. Gen II games do not store temporary types alongside the Pokemon, therefore they are not kept during trades. + +> [!NOTE] +> Unlike other menus, changing either type immediately saves it. Pressing `Back` will keep any changes. This will be addressed in a later version. If you need to revert to the default types, a different Pokemon can be selected and the desired Pokemon re-selected. + +> [!NOTE] +> When changing the type(s), the Pokemon's in-game stats will _NOT_ reflect the chosen type(s). Additionally, these will be overwritten back to default in-game if the Pokemon uses a move that affects types (e.g. `Transform`) or the Pokemon evolves. + +> [!TIP] +> Pokemon with a single type will have the same type set for both types. + +

+
+ +
+

+ +--- + +#### Stats (Gen I / Gen II) + +The Pokemon's stats can also be influenced. The current settings are: +- `Random IV, Zero EV` Mimics stats of a caught wild Pokemon. +- `Random IV, Max EV / Level` IV is randomized, but EV is set to the maximum a trained Pokemon could be for its current level. +- `Random IV, Max EV` IV is randomized, EV is set to the absolute max for a perfectly trained Pokemon. +- `Max IV, Zero EV` Mimics stats of a caught wild Pokemon, but with the maximum IV possible. +- `Max IV, Max EV / Level` IV is max, EV is set to the maximum a trained Pokemon could be for its current level. +- `Max IV, Max EV` Absolutely perfect and overly powerful Pokemon. -

-
- -
-

+

+
+ +
+

-- The `OT ID#` and `OT Name` of the Pokemon can also be set. The `OT ID#` must be between `0` and `65535`. Setting the `OT ID#` and `OT Name` to the same as your current trainer's causes the game to believe it was a wild caught Pokemon and not one that was traded. This means high level Pokemon will still obey you without badges, but, will not get the experience boost of a traded Pokemon. +--- -

-
-
-

+#### Shiny (Gen II only) +The Pokemon can be modified to be shiny or not. -

-
-
-

+> [!NOTE] +> Modifying this option will affect the IV, but this will not be visible anywhere in the current application. For example, if any of the `Max IV` settings are selected, this will never result in a shiny Pokemon; but modifying the Pokemon to be shiny will adjust the IVs until the Pokemon is shiny. The Stats will still list `Max IV` however. -- Finally, select `Trade PKMN` to start the trade process. +

+
+ +
+

-

-
-
-

+--- -

-
-
-

- -- On your Game Boy, you should connect the **Game Link Cable** to the Game Boy and in the game, go to the nearest **Pokemon Center**. +#### Gender (Gen II only) +The Pokemon's gender can be selected. -

-
-
-

+> [!NOTE] +> Modifying this option will affect the IV, but this will not be visible anywhere in the current application. For example, if any of the `Max IV` settings are selected and the Pokemon's gender is modified, the IVs will be adjusted so the Pokemon is the desired gender. The Stats will still list `Max IV` however. -- Talk to the girl at the counter on the right. The girl will tell us that we have to save the game before playing, we will answer **YES** by pressing the **A** button. +> [!TIP] +> Some Pokemon are always a specific gender, `Miltank` for example is always female. Other Pokemon are gender-less (officially stated in-game as `Unknown`) and this is reflected if such a Pokemon is selected. In both of these cases, it is not possible to modify the Pokemon's gender. -

-
-
-

+

+
+ +
+

-- The Flipper Zero will show that we are connected. +--- -

-
-
-

+#### Pokerus (Gen II only) -- On the Game Boy, we will be asked which option we want, and we select **TRADE CENTER**. +The traded Pokemon can have its [Pokerus](https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9ru) status modified. There are 4 in-game strains, the only effect is their default infection days remaining. However, it is possible to select an arbitrary strain, or none, as well as the number of days remaining. The days remaining can be set all the way up to `15`, which is not naturally occurring. In-game, strain `D` randomly infecting a Pokemon has the highest number of days remaining, `4`. If a strain is set and the number of days remaining is `0`, the Pokemon is cured and will no longer infect other Pokemon. -

-
-
-

+The three states listed in the trade menu are `Clean` (having never been infected), `Infected` (any strain with a non-zero number of days remaining and is infectious), and `Cured` (any strain with 0 days remaining and is no longer infectious). -- You will enter the Trade Center where you must press the A button on the Game Boy on your side of the table. +

+
+ +
+

-

-
-
-

+

+
+ +
+

-- Flipper Zero will remain on a waiting screen with the Pokemon you selected. +--- -

-
-
-

+#### Unown Form (Gen II only) +When the Pokemon `Unown` is selected, this option appears. The Pokemon can be set to any single letter of the English alphabet. -- You will see your Pokemon and the Pokemon you selected on the Flipper Zero, in this case, `Mew`. You must select the Pokemon you want to trade and press **TRADE**. -

-
-
-

+> [!NOTE] +> Modifying this option will affect the IV, but this will not be visible anywhere in the current application. For example, if any of the `Max IV` settings are selected and Unown's form is modified, the IVs will be adjusted so the Pokemon is the desired form. The Stats will still list `Max IV` however. -- You must confirm the selected trade by selecting **TRADE**. +> [!TIP] +> In Gen II games, only two Unown forms, `I` and `V` are able to be shiny due to how both the form and shininess are based on the Pokemon's IVs. -

-
-
-

+

+
+ +
+

-- Flipper Zero will remain on a waiting screen with the Pokemon you selected. +--- -

-
-
-

+#### OT ID# / Name (Gen I / Gen II) -- Finally, the Pokemon exchange will start from **Flipper Zero** to the **Game Boy**. +The `OT ID#` and `OT Name` of the Pokemon can also be set. The `OT ID#` must be between `0` and `65535`. Setting the `OT ID#` and `OT Name` to the same as your current trainer's causes the game to believe it was a wild caught Pokemon and not one that was traded. This means high level Pokemon will still obey you without badges, but, will not get the experience boost of a traded Pokemon. -

-
-
-

+> [!NOTE] +> Only English alphabetical characters are supported in the OT Name at this time. -- Once the trade is complete, both the **Game Boy** and the **Flipper Zero** will return to the `WAITING` state. If the **Game Boy** selects `CANCEL`, the **Flipper Zero** will return to the `READY` state. The BACK button can be pressed to return to the main menu. The traded Pokemon can be modified, or completely changed, if desired. Once the **Flipper Zero** Re-enters the Trade screen, and the **Game Boy** re-selects the trade table in-game, another trade can be completed. This allows for trading multiple Pokemon without having to reset the **Game Boy** each time. +

+
+
+

- If the Flipper Zero gets stuck at the end of the exchange, you must reboot it by pressing the LEFT + BACK key combination. +

+
+
+

+ +--- + +### Trade PKMN +The last option in both generations is to start the trade. The first time this is entered the Flipper will prompt to connect a Link Cable to the Game Boy. On the Game Boy, enter a **Pokemon Center** and speak with the NPC at the **Cable Club** to start a trade. Once the Game Boy goes through the prompts to enter a trade, the Flipper will say `READY` and the Game Boy will enter the trade room. + +> [!NOTE] +> At any point the Flipper says `READY`, the back button on the Flipper can be pressed to go back to the customization menu. Re-entering the trade screen from there will remain connected to the Game Boy. + +On the Game Boy, approaching the trade table and pressing `A` will start a trade. The Flipper will display `WAITING` while the Game Boy is on the screen showing both parties. + +> [!NOTE] +> At any point the Flipper says `WAITING`, the `BACK` button on the Flipper can be pressed to request to cancel the trade. The Flipper will display `CANCEL` and will remain there until the Game Boy selects `CANCEL` as well (attempts to trade from the Game Boy will just be aborted) and the Flipper will revert to the `READY` state. If the Flipper displays `WAITING` and the Game Boy selects `CANCEL`, the Flipper will return to the `READY` state. + +On the Game Boy, select a Pokemon to trade with the Flipper. Confirming the trade will begin the trade animation on both the Flipper and Game Boy. Once the trade is complete, both the Game Boy and the Flipper will return to the `WAITING` state. If the Game Boy selects `CANCEL` at this point, the Flipper will return to the `READY` state. The `BACK` button can be pressed to return to the main menu. + +> [!WARNING] +> At any point while on the trade screen on the Flipper, it is possible to return to the customization menu by holding the `BACK` button. However doing this risks desyncing the trade state between the Flipper and Game Boy. + +--- + +#### Modifying Traded Pokemon +Once a trade is complete, the Pokemon traded from the Game Boy to the Flipper is kept in the Flipper's memory. It is possible to go back from the trade screen to the Gen I/II customization menu. There, the Pokemon can be modified; e.g. adjust the EV/IV, levels, move set, nickname, OT ID#/Name, etc. and traded back by re-entering the `Trade PKMN` option. + +The Game Boy should remain on and in the trade room. When the Flipper re-enters the `Trade PKMN` option, the Game Boy can re-select the trade table by pressing `A` at it and the whole trade process can be restarted. If the Game Boy is turned off, then the Flipper currently must back all the way out to reset the trade status so the Game Boy can re-establish the initial connection. + +--- + +#### Special Note on MALVEKE PCB Rev. <= 2.5 +Version 2.0 of the Pokemon Trade tool fixes a bug on MALVEKE boards that are Rev. 2.5 or lower where after a trade is completed the `OK` button no longer functions. However, while on the trade screen the `OK` button will continue to not function. For example, if you try to press the `OK` button to turn the backlight on, the Flipper will not respond. The `OK` button functionality will be restored once the Flipper leaves the Trade screen. -

-
-
-

-## How does it work? +## How Does it Work? The method used to communicate 2 Game Boys is based on the SPI protocol, which is a very simple serial communication protocol in which a master device communicates with one or more slave devices. The protocol is bidirectional and synchronous, and uses three basic signals: @@ -362,13 +466,15 @@ It's possible to cut a cable directly without using a socket, but it's important ## GUI -To generate the graphical interface, the [**FUI-Editor**](https://ilin.pt/stuff/fui-editor/) tool was used. Additionally, the original sprites from the game Pokemon Yellow, which are found in the [**Disassembly of Pokemon Yellow**](https://github.com/pret/pokeyellow/tree/master/gfx/pokemon/front) repository, were used. +To generate the graphical interface, the [**FUI-Editor**](https://ilin.pt/stuff/fui-editor/) tool was used. -For each image, the color `#aaa` was transformed to `#fff` so that Flipper Zero would render it correctly. To do this, a batch process was used in [Photopea](https://www.photopea.com/), the online image editor. +The sprites for each Pokemon were hand-made for the monochrome screen of the Flipper. The source models are based on sprites from a selection of all Gen I and Gen II games; the ones used we're our favorites. Huge thanks to [ProteanReverie](https://github.com/ProteanReverie) for all of the help and support! ## Tested In - Game Boy Color (GBC) - Game Boy Advance (GBA) +- Game Boy Advance SP (GBA SP) +- Analogue Pocket ## Contributors [![Contributors](https://contrib.rocks/image?repo=EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading)](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/graphs/contributors) diff --git a/README_catalog.md b/README_catalog.md index 82d3bdd6fa2..0135da02d83 100644 --- a/README_catalog.md +++ b/README_catalog.md @@ -2,16 +2,17 @@ ## Introduction -Now supports MALVEKE board! +Tool for trading Pokemon from the Flipper Zero to Generation I and II Game Boy games (Red, Blue, Yellow, Gold, Silver, and Crystal). In addition to creating and trading Pokemon to a Game Boy game, the Flipper can be used to modify an existing Pokemon traded to the Flipper and trading it back to the Game Boy! -This is a Pokemon exchange application from Flipper Zero to Game Boy (Generación I). Flipper Zero emulates a "Slave" Game Boy connected to a Game Link Cable to be able to exchange any Pokemon from the First Generation (Red, Blue, Yellow) to a real Game Boy. - -If a MALVEKE board is plugged in to GPIO before starting the app, the app will default to using the MALVEKE EXT1 interface. +No longer causes the OK button to break when using the pinout for older MALVEKE (MLVK2.5) PCBs! Users of MALVEKE PCBs Rev. <= 2.5 no longer need to reset the Flipper after a trade and are able to modify the traded Pokemon! +See the project's [README on GitHub](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/blob/main/README.md) for more detailed instructions on the application and all of the customization options for Pokemon. ## Connection: Flipper Zero GPIO - Game Boy -The original pinout is as follows: +See the project's [README on GitHub](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/blob/main/README.md) for Link Cable interface adapters available on Tindie. + +The Original pinout is as follows: | Cable Game Link (Socket) | Flipper Zero GPIO | | ------------------------ | ----------------- | @@ -20,22 +21,21 @@ The original pinout is as follows: | 3 (SI) | 7 (C3) | | 2 (SO) | 5 (B3) | -Using the "Select Pinout" option, the Original, MALVEKE, or any custom pin configuration can be selected. +Using the "Select Pinout" option, the Original, MALVEKE (MLVK2.5), or any custom pin configuration can be selected as well. -## How does it work? +## How Does it Work? -The method used to communicate 2 Game Boys is based on the SPI protocol, which is a very simple serial communication protocol in which a master device communicates with one or more slave devices. The protocol is bidirectional and synchronous, and uses three basic signals: +Game Boy and Game Boy color games communicate using a synchronous serial protocol; similar to SPI without a chip select line. The Pokemon games themselves arbitrate which unit is driving the clock; this application lets the Game Boy drive the clock every time. Like SPI, data is full-duplex bidirectional, and uses 3 signals: - A clock signal (CLK). - An output signal (Serial Out or SO). - An input signal (Serial In or SI). -In the Game Boy, games store data in an internal shift register that is used to send and receive information. The SPI protocol used by the Game Boy uses the clock signal to indicate when data is being transferred. - -The Game Boy link protocol is synchronous and requires the slave device to respond at the same rate as the master device. The master device supplies an 8KHz clock (data transfer rate of 1KB/s). The time window for responding is only **~120μs**. However, the slave device has no restrictions and can respond when it receives data. The clock can vary and there is no lower limit. - +The Game Boy itself uses a shift register to clock data in and out. -## Tested In +## Tested to Support Game Boy models - Game Boy Color (GBC) - Game Boy Advance (GBA) +- Game Boy Advance SP (GBA SP) +- Analogue Pocket diff --git a/README_es.md b/README_es.md index bb5f1325839..a21e118d850 100644 --- a/README_es.md +++ b/README_es.md @@ -54,7 +54,7 @@ Estas instrucciones asumen que estás comenzando desde el escritorio de Flipper


- +

- Presiona los botones `IZQUIERDA`/`DERECHA` para paginar la selección de Pokémon de a 1. @@ -63,7 +63,7 @@ Estas instrucciones asumen que estás comenzando desde el escritorio de Flipper


-
+

- El nombre del Pokémon intercambiado se puede establecer. Cuando se selecciona un Pokémon, el nombre por defecto es el nombre de la especie en mayúsculas. Esto imita a un Pokémon sin un nombre personalizado. Para restablecer este nombre a su valor predeterminado, borra el campo de entrada de texto, presiona `OK` en el botón `Save`. Esto llenará el cuadro de texto con el nombre predeterminado. Presiona `Save` nuevamente para establecer este nombre. @@ -73,26 +73,26 @@ Estas instrucciones asumen que estás comenzando desde el escritorio de Flipper


- +

- También se puede ajustar el nivel del Pokémon presionando `OK` en la opción de nivel. El nivel mínimo es `2` y el máximo es `100`. El nivel se ingresa a través de un cuadro de texto. (Los niveles por debajo de 2 causan una falla de desbordamiento en los juegos de Gen I que haría que el nivel saltara a 100, así que si deseas esto, simplemente establece el nivel del Pokémon en 100).


- +

- El menú `Select Moves` se utiliza para elegir los movimientos del Pokémon intercambiado. Están predefinidos con el conjunto de movimientos que el Pokémon conocería al nivel 1. Seleccionar una ranura de movimiento mostrará un índice alfabético de movimientos. Además, se pueden seleccionar rápidamente `No Move` y `Default`. Ten en cuenta que cualquier movimiento después del primer `No Move` se ignora.


- +


- +

- El menú `Select Types` puede cambiar los tipos del Pokémon intercambiado. Los tipos están predefinidos según lo que normalmente es el Pokémon seleccionado. @@ -105,21 +105,21 @@ Estas instrucciones asumen que estás comenzando desde el escritorio de Flipper


- +

- Las estadísticas del Pokémon también se pueden influir. Las configuraciones actuales son: - `Random IV, Zero EV` Imita las estadísticas de un Pokémon salvaje atrapado. - `Random IV, Max EV / Level` IV es aleatorio, pero EV se establece en el máximo que un Pokémon entrenado podría tener para su nivel actual. - - `Randon IV, Max EV` IV es aleatorio, EV se establece en el máximo absoluto para un Pokémon perfectamente entrenado. + - `Random IV, Max EV` IV es aleatorio, EV se establece en el máximo absoluto para un Pokémon perfectamente entrenado. - `Max IV, Zero EV` Imita las estadísticas de un Pokémon salvaje atrapado, pero con el IV máximo posible. - `Max IV, Max EV / Level` IV es máximo, EV se establece en el máximo que un Pokémon entrenado podría tener para su nivel actual. - `Max IV, Max EV` Máximo Pokémon absolutamente perfectos y poderosos.


- +

@@ -127,11 +127,11 @@ Estas instrucciones asumen que estás comenzando desde el escritorio de Flipper


-
+


-
+

- Finalmente, selecciona Intercambiar PKMN para iniciar el proceso de intercambio. diff --git a/application.fam b/application.fam index cbcf16d97f0..46a60f2a0a6 100644 --- a/application.fam +++ b/application.fam @@ -5,17 +5,17 @@ App( entry_point="pokemon_app", requires=["gui"], stack_size=2 * 1024, - fap_version=[1,6], + fap_version=[2,0], fap_category="GPIO", fap_icon="pokemon_10px.png", fap_icon_assets="assets", - fap_author="Esteban Fuentealba, Kris Bahnsen, Darryn Cull", + fap_file_assets="files", + fap_author="Esteban Fuentealba, Kris Bahnsen, Darryn Cull, ProteanReverie", fap_weburl="https://github.com/EstebanFuentealba", - fap_description="Pokemon exchange from Flipper Zero to Game Boy for Generation I (Pokemon Red, Blue, Yellow)", + fap_description="Pokemon exchange from Flipper Zero to Game Boy, supports Generation I & II non-Japanese games", fap_private_libs=[ Lib( name="flipper-gblink", - sources=["gblink.c"], ), ], ) diff --git a/assets/Background.png b/assets/Background.png deleted file mode 100644 index 3cb1eb3b0b7..00000000000 Binary files a/assets/Background.png and /dev/null differ diff --git a/assets/Button_18x18.png b/assets/Button_18x18.png deleted file mode 100644 index 30a5b4fab23..00000000000 Binary files a/assets/Button_18x18.png and /dev/null differ diff --git a/assets/Connect_me_62x31.png b/assets/Connect_me_62x31.png deleted file mode 100644 index 68c48c0e681..00000000000 Binary files a/assets/Connect_me_62x31.png and /dev/null differ diff --git a/assets/Connected_62x31.png b/assets/Connected_62x31.png deleted file mode 100644 index eeaf660b12e..00000000000 Binary files a/assets/Connected_62x31.png and /dev/null differ diff --git a/assets/Space_100x18.png b/assets/Space_100x18.png deleted file mode 100644 index 09feb8d345b..00000000000 Binary files a/assets/Space_100x18.png and /dev/null differ diff --git a/assets/Space_95x18.png b/assets/Space_95x18.png deleted file mode 100644 index bd3ba44d218..00000000000 Binary files a/assets/Space_95x18.png and /dev/null differ diff --git a/assets/abra.png b/assets/abra.png deleted file mode 100644 index b25b423dc3e..00000000000 Binary files a/assets/abra.png and /dev/null differ diff --git a/assets/aerodactyl.png b/assets/aerodactyl.png deleted file mode 100644 index 2c7c25df09a..00000000000 Binary files a/assets/aerodactyl.png and /dev/null differ diff --git a/assets/alakazam.png b/assets/alakazam.png deleted file mode 100644 index 1420491d3c7..00000000000 Binary files a/assets/alakazam.png and /dev/null differ diff --git a/assets/arbok.png b/assets/arbok.png deleted file mode 100644 index 146af780397..00000000000 Binary files a/assets/arbok.png and /dev/null differ diff --git a/assets/arcanine.png b/assets/arcanine.png deleted file mode 100644 index b99c9189f92..00000000000 Binary files a/assets/arcanine.png and /dev/null differ diff --git a/assets/articuno.png b/assets/articuno.png deleted file mode 100644 index fdb319097d7..00000000000 Binary files a/assets/articuno.png and /dev/null differ diff --git a/assets/beedrill.png b/assets/beedrill.png deleted file mode 100644 index af467aab35d..00000000000 Binary files a/assets/beedrill.png and /dev/null differ diff --git a/assets/bellsprout.png b/assets/bellsprout.png deleted file mode 100644 index c1c550d7c77..00000000000 Binary files a/assets/bellsprout.png and /dev/null differ diff --git a/assets/blastoise.png b/assets/blastoise.png deleted file mode 100644 index 24ab98bc190..00000000000 Binary files a/assets/blastoise.png and /dev/null differ diff --git a/assets/bulbasaur.png b/assets/bulbasaur.png deleted file mode 100644 index 8916cd48452..00000000000 Binary files a/assets/bulbasaur.png and /dev/null differ diff --git a/assets/butterfree.png b/assets/butterfree.png deleted file mode 100644 index 405e1f1a4da..00000000000 Binary files a/assets/butterfree.png and /dev/null differ diff --git a/assets/caterpie.png b/assets/caterpie.png deleted file mode 100644 index 3f531ea3bb5..00000000000 Binary files a/assets/caterpie.png and /dev/null differ diff --git a/assets/chansey.png b/assets/chansey.png deleted file mode 100644 index 390d475bda7..00000000000 Binary files a/assets/chansey.png and /dev/null differ diff --git a/assets/charizard.png b/assets/charizard.png deleted file mode 100644 index 5a16559330c..00000000000 Binary files a/assets/charizard.png and /dev/null differ diff --git a/assets/charmander.png b/assets/charmander.png deleted file mode 100644 index d6f03fbbd2f..00000000000 Binary files a/assets/charmander.png and /dev/null differ diff --git a/assets/charmeleon.png b/assets/charmeleon.png deleted file mode 100644 index 6d59fe99c84..00000000000 Binary files a/assets/charmeleon.png and /dev/null differ diff --git a/assets/clefable.png b/assets/clefable.png deleted file mode 100644 index fddbc7e1a0b..00000000000 Binary files a/assets/clefable.png and /dev/null differ diff --git a/assets/clefairy.png b/assets/clefairy.png deleted file mode 100644 index 92b56c37cf4..00000000000 Binary files a/assets/clefairy.png and /dev/null differ diff --git a/assets/cloyster.png b/assets/cloyster.png deleted file mode 100644 index 949e419e0d8..00000000000 Binary files a/assets/cloyster.png and /dev/null differ diff --git a/assets/cubone.png b/assets/cubone.png deleted file mode 100644 index 49ff652c737..00000000000 Binary files a/assets/cubone.png and /dev/null differ diff --git a/assets/dewgong.png b/assets/dewgong.png deleted file mode 100644 index 1089099c004..00000000000 Binary files a/assets/dewgong.png and /dev/null differ diff --git a/assets/diglett.png b/assets/diglett.png deleted file mode 100644 index e12c92ac712..00000000000 Binary files a/assets/diglett.png and /dev/null differ diff --git a/assets/ditto.png b/assets/ditto.png deleted file mode 100644 index fb377a536d9..00000000000 Binary files a/assets/ditto.png and /dev/null differ diff --git a/assets/dodrio.png b/assets/dodrio.png deleted file mode 100644 index 6f5cc3c1c37..00000000000 Binary files a/assets/dodrio.png and /dev/null differ diff --git a/assets/doduo.png b/assets/doduo.png deleted file mode 100644 index 9ff1d840e0b..00000000000 Binary files a/assets/doduo.png and /dev/null differ diff --git a/assets/dolphin.png b/assets/dolphin.png new file mode 100644 index 00000000000..87e9bc2b757 Binary files /dev/null and b/assets/dolphin.png differ diff --git a/assets/dragonair.png b/assets/dragonair.png deleted file mode 100644 index 92e610c2750..00000000000 Binary files a/assets/dragonair.png and /dev/null differ diff --git a/assets/dragonite.png b/assets/dragonite.png deleted file mode 100644 index a0c7dc0dccc..00000000000 Binary files a/assets/dragonite.png and /dev/null differ diff --git a/assets/dratini.png b/assets/dratini.png deleted file mode 100644 index b3e78961898..00000000000 Binary files a/assets/dratini.png and /dev/null differ diff --git a/assets/drowzee.png b/assets/drowzee.png deleted file mode 100644 index 898be979e65..00000000000 Binary files a/assets/drowzee.png and /dev/null differ diff --git a/assets/dugtrio.png b/assets/dugtrio.png deleted file mode 100644 index 5ed1e0fd377..00000000000 Binary files a/assets/dugtrio.png and /dev/null differ diff --git a/assets/eevee.png b/assets/eevee.png deleted file mode 100644 index 393246272e0..00000000000 Binary files a/assets/eevee.png and /dev/null differ diff --git a/assets/ekans.png b/assets/ekans.png deleted file mode 100644 index 529d5b4a310..00000000000 Binary files a/assets/ekans.png and /dev/null differ diff --git a/assets/electabuzz.png b/assets/electabuzz.png deleted file mode 100644 index 6827c9093e6..00000000000 Binary files a/assets/electabuzz.png and /dev/null differ diff --git a/assets/electrode.png b/assets/electrode.png deleted file mode 100644 index 757446c1864..00000000000 Binary files a/assets/electrode.png and /dev/null differ diff --git a/assets/exeggcute.png b/assets/exeggcute.png deleted file mode 100644 index b58d83f26e0..00000000000 Binary files a/assets/exeggcute.png and /dev/null differ diff --git a/assets/exeggutor.png b/assets/exeggutor.png deleted file mode 100644 index ea8360877b3..00000000000 Binary files a/assets/exeggutor.png and /dev/null differ diff --git a/assets/farfetchd.png b/assets/farfetchd.png deleted file mode 100644 index cc01fae59e7..00000000000 Binary files a/assets/farfetchd.png and /dev/null differ diff --git a/assets/fearow.png b/assets/fearow.png deleted file mode 100644 index 3d514764743..00000000000 Binary files a/assets/fearow.png and /dev/null differ diff --git a/assets/flareon.png b/assets/flareon.png deleted file mode 100644 index b103b454882..00000000000 Binary files a/assets/flareon.png and /dev/null differ diff --git a/assets/fossilaerodactyl.png b/assets/fossilaerodactyl.png deleted file mode 100644 index b2c7d5e3201..00000000000 Binary files a/assets/fossilaerodactyl.png and /dev/null differ diff --git a/assets/fossilkabutops.png b/assets/fossilkabutops.png deleted file mode 100644 index f2eb21ef8f4..00000000000 Binary files a/assets/fossilkabutops.png and /dev/null differ diff --git a/assets/gastly.png b/assets/gastly.png deleted file mode 100644 index 24e880930f9..00000000000 Binary files a/assets/gastly.png and /dev/null differ diff --git a/assets/gengar.png b/assets/gengar.png deleted file mode 100644 index 41c58af829b..00000000000 Binary files a/assets/gengar.png and /dev/null differ diff --git a/assets/geodude.png b/assets/geodude.png deleted file mode 100644 index 087a19bdd75..00000000000 Binary files a/assets/geodude.png and /dev/null differ diff --git a/assets/gloom.png b/assets/gloom.png deleted file mode 100644 index 7a589421ddc..00000000000 Binary files a/assets/gloom.png and /dev/null differ diff --git a/assets/golbat.png b/assets/golbat.png deleted file mode 100644 index 8036d3b28f6..00000000000 Binary files a/assets/golbat.png and /dev/null differ diff --git a/assets/goldeen.png b/assets/goldeen.png deleted file mode 100644 index 95a9186b752..00000000000 Binary files a/assets/goldeen.png and /dev/null differ diff --git a/assets/golduck.png b/assets/golduck.png deleted file mode 100644 index 829c3ac4526..00000000000 Binary files a/assets/golduck.png and /dev/null differ diff --git a/assets/golem.png b/assets/golem.png deleted file mode 100644 index 4f73c05e9b7..00000000000 Binary files a/assets/golem.png and /dev/null differ diff --git a/assets/graveler.png b/assets/graveler.png deleted file mode 100644 index 920d90f1634..00000000000 Binary files a/assets/graveler.png and /dev/null differ diff --git a/assets/grimer.png b/assets/grimer.png deleted file mode 100644 index d715f1b7092..00000000000 Binary files a/assets/grimer.png and /dev/null differ diff --git a/assets/growlithe.png b/assets/growlithe.png deleted file mode 100644 index 75f61edd48e..00000000000 Binary files a/assets/growlithe.png and /dev/null differ diff --git a/assets/gyarados.png b/assets/gyarados.png deleted file mode 100644 index d2cc65265aa..00000000000 Binary files a/assets/gyarados.png and /dev/null differ diff --git a/assets/hand_cable.png b/assets/hand_cable.png new file mode 100644 index 00000000000..2c13e8dba6e Binary files /dev/null and b/assets/hand_cable.png differ diff --git a/assets/hand_thumbsup.png b/assets/hand_thumbsup.png new file mode 100644 index 00000000000..91ab62ca51a Binary files /dev/null and b/assets/hand_thumbsup.png differ diff --git a/assets/haunter.png b/assets/haunter.png deleted file mode 100644 index 516f09e5f4f..00000000000 Binary files a/assets/haunter.png and /dev/null differ diff --git a/assets/hitmonchan.png b/assets/hitmonchan.png deleted file mode 100644 index 8f9f427bc07..00000000000 Binary files a/assets/hitmonchan.png and /dev/null differ diff --git a/assets/hitmonlee.png b/assets/hitmonlee.png deleted file mode 100644 index 1d129796182..00000000000 Binary files a/assets/hitmonlee.png and /dev/null differ diff --git a/assets/horsea.png b/assets/horsea.png deleted file mode 100644 index 82dd5adbe39..00000000000 Binary files a/assets/horsea.png and /dev/null differ diff --git a/assets/hypno.png b/assets/hypno.png deleted file mode 100644 index af36499d051..00000000000 Binary files a/assets/hypno.png and /dev/null differ diff --git a/assets/ivysaur.png b/assets/ivysaur.png deleted file mode 100644 index 141c0211cd2..00000000000 Binary files a/assets/ivysaur.png and /dev/null differ diff --git a/assets/jigglypuff.png b/assets/jigglypuff.png deleted file mode 100644 index 1c0fb506833..00000000000 Binary files a/assets/jigglypuff.png and /dev/null differ diff --git a/assets/jolteon.png b/assets/jolteon.png deleted file mode 100644 index 24f981caf1d..00000000000 Binary files a/assets/jolteon.png and /dev/null differ diff --git a/assets/jynx.png b/assets/jynx.png deleted file mode 100644 index 236f21bceb6..00000000000 Binary files a/assets/jynx.png and /dev/null differ diff --git a/assets/kabuto.png b/assets/kabuto.png deleted file mode 100644 index 07d16aa01b4..00000000000 Binary files a/assets/kabuto.png and /dev/null differ diff --git a/assets/kabutops.png b/assets/kabutops.png deleted file mode 100644 index c8c7c09b4a6..00000000000 Binary files a/assets/kabutops.png and /dev/null differ diff --git a/assets/kadabra.png b/assets/kadabra.png deleted file mode 100644 index a6a817e8626..00000000000 Binary files a/assets/kadabra.png and /dev/null differ diff --git a/assets/kakuna.png b/assets/kakuna.png deleted file mode 100644 index 63e34da3740..00000000000 Binary files a/assets/kakuna.png and /dev/null differ diff --git a/assets/kangaskhan.png b/assets/kangaskhan.png deleted file mode 100644 index 6757a5c69f3..00000000000 Binary files a/assets/kangaskhan.png and /dev/null differ diff --git a/assets/kingler.png b/assets/kingler.png deleted file mode 100644 index 66af12fcba8..00000000000 Binary files a/assets/kingler.png and /dev/null differ diff --git a/assets/koffing.png b/assets/koffing.png deleted file mode 100644 index bfefab2f8fe..00000000000 Binary files a/assets/koffing.png and /dev/null differ diff --git a/assets/krabby.png b/assets/krabby.png deleted file mode 100644 index 1bdb9a4c1f9..00000000000 Binary files a/assets/krabby.png and /dev/null differ diff --git a/assets/lapras.png b/assets/lapras.png deleted file mode 100644 index 3023253da42..00000000000 Binary files a/assets/lapras.png and /dev/null differ diff --git a/assets/lickitung.png b/assets/lickitung.png deleted file mode 100644 index 3bf3ead82ca..00000000000 Binary files a/assets/lickitung.png and /dev/null differ diff --git a/assets/machamp.png b/assets/machamp.png deleted file mode 100644 index cf6e7170758..00000000000 Binary files a/assets/machamp.png and /dev/null differ diff --git a/assets/machoke.png b/assets/machoke.png deleted file mode 100644 index da4f0e0a8c2..00000000000 Binary files a/assets/machoke.png and /dev/null differ diff --git a/assets/machop.png b/assets/machop.png deleted file mode 100644 index 52c46840aab..00000000000 Binary files a/assets/machop.png and /dev/null differ diff --git a/assets/magikarp.png b/assets/magikarp.png deleted file mode 100644 index 46fcf0921fa..00000000000 Binary files a/assets/magikarp.png and /dev/null differ diff --git a/assets/magmar.png b/assets/magmar.png deleted file mode 100644 index 69352078ba1..00000000000 Binary files a/assets/magmar.png and /dev/null differ diff --git a/assets/magnemite.png b/assets/magnemite.png deleted file mode 100644 index f4a03a61b03..00000000000 Binary files a/assets/magnemite.png and /dev/null differ diff --git a/assets/magneton.png b/assets/magneton.png deleted file mode 100644 index b460ad749bc..00000000000 Binary files a/assets/magneton.png and /dev/null differ diff --git a/assets/mankey.png b/assets/mankey.png deleted file mode 100644 index 5d2240e8f0f..00000000000 Binary files a/assets/mankey.png and /dev/null differ diff --git a/assets/marowak.png b/assets/marowak.png deleted file mode 100644 index 7950f721c53..00000000000 Binary files a/assets/marowak.png and /dev/null differ diff --git a/assets/meowth.png b/assets/meowth.png deleted file mode 100644 index 0a2a94e3b40..00000000000 Binary files a/assets/meowth.png and /dev/null differ diff --git a/assets/metapod.png b/assets/metapod.png deleted file mode 100644 index dcf3b6ecbbb..00000000000 Binary files a/assets/metapod.png and /dev/null differ diff --git a/assets/mew.png b/assets/mew.png deleted file mode 100644 index b78fb63b3a9..00000000000 Binary files a/assets/mew.png and /dev/null differ diff --git a/assets/mewtwo.png b/assets/mewtwo.png deleted file mode 100644 index 4d0c670d210..00000000000 Binary files a/assets/mewtwo.png and /dev/null differ diff --git a/assets/moltres.png b/assets/moltres.png deleted file mode 100644 index c260503e548..00000000000 Binary files a/assets/moltres.png and /dev/null differ diff --git a/assets/mr.mime.png b/assets/mr.mime.png deleted file mode 100644 index 8210d106ce8..00000000000 Binary files a/assets/mr.mime.png and /dev/null differ diff --git a/assets/muk.png b/assets/muk.png deleted file mode 100644 index ae1a15c69c4..00000000000 Binary files a/assets/muk.png and /dev/null differ diff --git a/assets/nidoking.png b/assets/nidoking.png deleted file mode 100644 index 447fabc5e53..00000000000 Binary files a/assets/nidoking.png and /dev/null differ diff --git a/assets/nidoqueen.png b/assets/nidoqueen.png deleted file mode 100644 index fb1773e7100..00000000000 Binary files a/assets/nidoqueen.png and /dev/null differ diff --git a/assets/nidoranf.png b/assets/nidoranf.png deleted file mode 100644 index 63aef252795..00000000000 Binary files a/assets/nidoranf.png and /dev/null differ diff --git a/assets/nidoranm.png b/assets/nidoranm.png deleted file mode 100644 index 10eb35206e1..00000000000 Binary files a/assets/nidoranm.png and /dev/null differ diff --git a/assets/nidorina.png b/assets/nidorina.png deleted file mode 100644 index 300f572a52a..00000000000 Binary files a/assets/nidorina.png and /dev/null differ diff --git a/assets/nidorino.png b/assets/nidorino.png deleted file mode 100644 index d177f65a46a..00000000000 Binary files a/assets/nidorino.png and /dev/null differ diff --git a/assets/ninetales.png b/assets/ninetales.png deleted file mode 100644 index 5a06cb812a8..00000000000 Binary files a/assets/ninetales.png and /dev/null differ diff --git a/assets/oddish.png b/assets/oddish.png deleted file mode 100644 index 1277f57201c..00000000000 Binary files a/assets/oddish.png and /dev/null differ diff --git a/assets/omanyte.png b/assets/omanyte.png deleted file mode 100644 index 516fef8f093..00000000000 Binary files a/assets/omanyte.png and /dev/null differ diff --git a/assets/omastar.png b/assets/omastar.png deleted file mode 100644 index 82936671e35..00000000000 Binary files a/assets/omastar.png and /dev/null differ diff --git a/assets/onix.png b/assets/onix.png deleted file mode 100644 index fae97b087b1..00000000000 Binary files a/assets/onix.png and /dev/null differ diff --git a/assets/paras.png b/assets/paras.png deleted file mode 100644 index c0f6bc1f3f1..00000000000 Binary files a/assets/paras.png and /dev/null differ diff --git a/assets/parasect.png b/assets/parasect.png deleted file mode 100644 index 0f721c18a23..00000000000 Binary files a/assets/parasect.png and /dev/null differ diff --git a/assets/persian.png b/assets/persian.png deleted file mode 100644 index ee15c4b02f6..00000000000 Binary files a/assets/persian.png and /dev/null differ diff --git a/assets/pidgeot.png b/assets/pidgeot.png deleted file mode 100644 index 53bfca82f36..00000000000 Binary files a/assets/pidgeot.png and /dev/null differ diff --git a/assets/pidgeotto.png b/assets/pidgeotto.png deleted file mode 100644 index 776933ff8e1..00000000000 Binary files a/assets/pidgeotto.png and /dev/null differ diff --git a/assets/pidgey.png b/assets/pidgey.png deleted file mode 100644 index 4273ef65db4..00000000000 Binary files a/assets/pidgey.png and /dev/null differ diff --git a/assets/pikachu.png b/assets/pikachu.png deleted file mode 100644 index 77c9cff9bee..00000000000 Binary files a/assets/pikachu.png and /dev/null differ diff --git a/assets/pinsir.png b/assets/pinsir.png deleted file mode 100644 index dc7848f3cdb..00000000000 Binary files a/assets/pinsir.png and /dev/null differ diff --git a/assets/poliwag.png b/assets/poliwag.png deleted file mode 100644 index 81910be38e9..00000000000 Binary files a/assets/poliwag.png and /dev/null differ diff --git a/assets/poliwhirl.png b/assets/poliwhirl.png deleted file mode 100644 index 11cffa8d56b..00000000000 Binary files a/assets/poliwhirl.png and /dev/null differ diff --git a/assets/poliwrath.png b/assets/poliwrath.png deleted file mode 100644 index 068b2b74c82..00000000000 Binary files a/assets/poliwrath.png and /dev/null differ diff --git a/assets/ponyta.png b/assets/ponyta.png deleted file mode 100644 index 2e3d338b96c..00000000000 Binary files a/assets/ponyta.png and /dev/null differ diff --git a/assets/porygon.png b/assets/porygon.png deleted file mode 100644 index 07d3ff0e0bd..00000000000 Binary files a/assets/porygon.png and /dev/null differ diff --git a/assets/primeape.png b/assets/primeape.png deleted file mode 100644 index b2956602d2b..00000000000 Binary files a/assets/primeape.png and /dev/null differ diff --git a/assets/psyduck.png b/assets/psyduck.png deleted file mode 100644 index ba4f86ad486..00000000000 Binary files a/assets/psyduck.png and /dev/null differ diff --git a/assets/raichu.png b/assets/raichu.png deleted file mode 100644 index f76be753236..00000000000 Binary files a/assets/raichu.png and /dev/null differ diff --git a/assets/rapidash.png b/assets/rapidash.png deleted file mode 100644 index 272a684fb5b..00000000000 Binary files a/assets/rapidash.png and /dev/null differ diff --git a/assets/raticate.png b/assets/raticate.png deleted file mode 100644 index a0e760e9bc2..00000000000 Binary files a/assets/raticate.png and /dev/null differ diff --git a/assets/rattata.png b/assets/rattata.png deleted file mode 100644 index 76d834182e0..00000000000 Binary files a/assets/rattata.png and /dev/null differ diff --git a/assets/red.png b/assets/red.png deleted file mode 100644 index 050ca22a5c7..00000000000 Binary files a/assets/red.png and /dev/null differ diff --git a/assets/rhydon.png b/assets/rhydon.png deleted file mode 100644 index bbe5427fe55..00000000000 Binary files a/assets/rhydon.png and /dev/null differ diff --git a/assets/rhyhorn.png b/assets/rhyhorn.png deleted file mode 100644 index 006dc889d74..00000000000 Binary files a/assets/rhyhorn.png and /dev/null differ diff --git a/assets/sandshrew.png b/assets/sandshrew.png deleted file mode 100644 index 5e665643e86..00000000000 Binary files a/assets/sandshrew.png and /dev/null differ diff --git a/assets/sandslash.png b/assets/sandslash.png deleted file mode 100644 index 571081b3226..00000000000 Binary files a/assets/sandslash.png and /dev/null differ diff --git a/assets/scyther.png b/assets/scyther.png deleted file mode 100644 index 165bcff4396..00000000000 Binary files a/assets/scyther.png and /dev/null differ diff --git a/assets/seadra.png b/assets/seadra.png deleted file mode 100644 index 295dbf1a0fe..00000000000 Binary files a/assets/seadra.png and /dev/null differ diff --git a/assets/seaking.png b/assets/seaking.png deleted file mode 100644 index 0f854066f4f..00000000000 Binary files a/assets/seaking.png and /dev/null differ diff --git a/assets/seel.png b/assets/seel.png deleted file mode 100644 index 3043fe253b2..00000000000 Binary files a/assets/seel.png and /dev/null differ diff --git a/assets/shellder.png b/assets/shellder.png deleted file mode 100644 index cf5195556c7..00000000000 Binary files a/assets/shellder.png and /dev/null differ diff --git a/assets/slowbro.png b/assets/slowbro.png deleted file mode 100644 index 9843ec8accc..00000000000 Binary files a/assets/slowbro.png and /dev/null differ diff --git a/assets/slowpoke.png b/assets/slowpoke.png deleted file mode 100644 index d6e8ca12fa0..00000000000 Binary files a/assets/slowpoke.png and /dev/null differ diff --git a/assets/snorlax.png b/assets/snorlax.png deleted file mode 100644 index f7456033909..00000000000 Binary files a/assets/snorlax.png and /dev/null differ diff --git a/assets/spearow.png b/assets/spearow.png deleted file mode 100644 index 084686c931e..00000000000 Binary files a/assets/spearow.png and /dev/null differ diff --git a/assets/squirtle.png b/assets/squirtle.png deleted file mode 100644 index be4849ee564..00000000000 Binary files a/assets/squirtle.png and /dev/null differ diff --git a/assets/starmie.png b/assets/starmie.png deleted file mode 100644 index 9ce96a941b2..00000000000 Binary files a/assets/starmie.png and /dev/null differ diff --git a/assets/staryu.png b/assets/staryu.png deleted file mode 100644 index d97faad4816..00000000000 Binary files a/assets/staryu.png and /dev/null differ diff --git a/assets/surprised_pika.png b/assets/surprised_pika.png new file mode 100644 index 00000000000..929e1f25520 Binary files /dev/null and b/assets/surprised_pika.png differ diff --git a/assets/tangela.png b/assets/tangela.png deleted file mode 100644 index 73c2dbad838..00000000000 Binary files a/assets/tangela.png and /dev/null differ diff --git a/assets/tauros.png b/assets/tauros.png deleted file mode 100644 index 7700582275f..00000000000 Binary files a/assets/tauros.png and /dev/null differ diff --git a/assets/tentacool.png b/assets/tentacool.png deleted file mode 100644 index 117c03379d4..00000000000 Binary files a/assets/tentacool.png and /dev/null differ diff --git a/assets/tentacruel.png b/assets/tentacruel.png deleted file mode 100644 index c05e55441f6..00000000000 Binary files a/assets/tentacruel.png and /dev/null differ diff --git a/assets/vaporeon.png b/assets/vaporeon.png deleted file mode 100644 index f35e7423121..00000000000 Binary files a/assets/vaporeon.png and /dev/null differ diff --git a/assets/venomoth.png b/assets/venomoth.png deleted file mode 100644 index aab5e3de341..00000000000 Binary files a/assets/venomoth.png and /dev/null differ diff --git a/assets/venonat.png b/assets/venonat.png deleted file mode 100644 index fcfdb8aef2c..00000000000 Binary files a/assets/venonat.png and /dev/null differ diff --git a/assets/venusaur.png b/assets/venusaur.png deleted file mode 100644 index fc6855f4ba1..00000000000 Binary files a/assets/venusaur.png and /dev/null differ diff --git a/assets/victreebel.png b/assets/victreebel.png deleted file mode 100644 index 39ab7e7c517..00000000000 Binary files a/assets/victreebel.png and /dev/null differ diff --git a/assets/vileplume.png b/assets/vileplume.png deleted file mode 100644 index dc4964682ff..00000000000 Binary files a/assets/vileplume.png and /dev/null differ diff --git a/assets/voltorb.png b/assets/voltorb.png deleted file mode 100644 index 17255260c67..00000000000 Binary files a/assets/voltorb.png and /dev/null differ diff --git a/assets/vulpix.png b/assets/vulpix.png deleted file mode 100644 index 55030c587de..00000000000 Binary files a/assets/vulpix.png and /dev/null differ diff --git a/assets/wartortle.png b/assets/wartortle.png deleted file mode 100644 index 66eb1f14874..00000000000 Binary files a/assets/wartortle.png and /dev/null differ diff --git a/assets/weedle.png b/assets/weedle.png deleted file mode 100644 index a1a7c530d48..00000000000 Binary files a/assets/weedle.png and /dev/null differ diff --git a/assets/weepinbell.png b/assets/weepinbell.png deleted file mode 100644 index 33de83487ab..00000000000 Binary files a/assets/weepinbell.png and /dev/null differ diff --git a/assets/weezing.png b/assets/weezing.png deleted file mode 100644 index f07c40d10ed..00000000000 Binary files a/assets/weezing.png and /dev/null differ diff --git a/assets/wigglytuff.png b/assets/wigglytuff.png deleted file mode 100644 index ed51e8df80b..00000000000 Binary files a/assets/wigglytuff.png and /dev/null differ diff --git a/assets/zapdos.png b/assets/zapdos.png deleted file mode 100644 index ce452afad3a..00000000000 Binary files a/assets/zapdos.png and /dev/null differ diff --git a/assets/zubat.png b/assets/zubat.png deleted file mode 100644 index fd1bb19baac..00000000000 Binary files a/assets/zubat.png and /dev/null differ diff --git a/changelog.md b/changelog.md index 21b0fb07e8f..406dc0f17df 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,22 @@ # Changelog - Patch Notes +## Version 2.0 +**Bug Fixes** +- Older MALVEKE style pinout no longer breaks OK button, MALVEKE users now able to modify traded Pokemon + +**New Features** +- Generation II support (Gold, Silver, Crystal) + - Ability to configure name, level, held item, moveset, EV/IV, shininess, gender, pokerus, Unown form, OT ID/name +- Custom Sprite Art for all Pokemon, all sprites are the full 56x56 px size +- Better state synchronization during trades, able to request canceling a trade +- Exit confirmation to prevent accidentally losing configuration +- Add main menu to select generation and pinout +- Adjust Trade and Select views to show full sprite, with proper transparency + +**Refactor** +- Sprites moved to file on SD card +- Create accessors for generically modifying Pokemon struct data + ## Version 1.6 - **Change Name:** All the application names for GAME BOY/MALVEKE were standardized for better readability on the screen. diff --git a/docs/images/flipper-zero-flat-01.png b/docs/images/flipper-zero-flat-01.png deleted file mode 100644 index 7fddccd34f4..00000000000 Binary files a/docs/images/flipper-zero-flat-01.png and /dev/null differ diff --git a/docs/images/flipper-zero-flat-1-1.png b/docs/images/flipper-zero-flat-1-1.png deleted file mode 100644 index cf9789daa83..00000000000 Binary files a/docs/images/flipper-zero-flat-1-1.png and /dev/null differ diff --git a/docs/images/flipper-zero-flat-1.png b/docs/images/flipper-zero-flat-1.png deleted file mode 100644 index 5c9b6e14179..00000000000 Binary files a/docs/images/flipper-zero-flat-1.png and /dev/null differ diff --git a/docs/images/flipper-zero-flat-2.png b/docs/images/flipper-zero-flat-2.png deleted file mode 100644 index ed2c10a7ec6..00000000000 Binary files a/docs/images/flipper-zero-flat-2.png and /dev/null differ diff --git a/docs/images/flipper-zero-flat.xcf b/docs/images/flipper-zero-flat.xcf index d92f3e3e32d..100e01cac02 100644 Binary files a/docs/images/flipper-zero-flat.xcf and b/docs/images/flipper-zero-flat.xcf differ diff --git a/docs/images/flipper-zero-gender.png b/docs/images/flipper-zero-gender.png new file mode 100644 index 00000000000..2a0c5f133d7 Binary files /dev/null and b/docs/images/flipper-zero-gender.png differ diff --git a/docs/images/flipper-zero-held-item.png b/docs/images/flipper-zero-held-item.png new file mode 100644 index 00000000000..364eac34b35 Binary files /dev/null and b/docs/images/flipper-zero-held-item.png differ diff --git a/docs/images/flipper-zero-flat-3.png b/docs/images/flipper-zero-level.png similarity index 100% rename from docs/images/flipper-zero-flat-3.png rename to docs/images/flipper-zero-level.png diff --git a/docs/images/flipper-zero-main-menu.png b/docs/images/flipper-zero-main-menu.png new file mode 100644 index 00000000000..f3d5a4b9658 Binary files /dev/null and b/docs/images/flipper-zero-main-menu.png differ diff --git a/docs/images/flipper-zero-flat-7.png b/docs/images/flipper-zero-move-1.png similarity index 100% rename from docs/images/flipper-zero-flat-7.png rename to docs/images/flipper-zero-move-1.png diff --git a/docs/images/flipper-zero-flat-8.png b/docs/images/flipper-zero-move-2.png similarity index 100% rename from docs/images/flipper-zero-flat-8.png rename to docs/images/flipper-zero-move-2.png diff --git a/docs/images/flipper-zero-nickname.png b/docs/images/flipper-zero-nickname.png new file mode 100644 index 00000000000..815e4d37458 Binary files /dev/null and b/docs/images/flipper-zero-nickname.png differ diff --git a/docs/images/flipper-zero-flat-6.png b/docs/images/flipper-zero-ot-id.png similarity index 100% rename from docs/images/flipper-zero-flat-6.png rename to docs/images/flipper-zero-ot-id.png diff --git a/docs/images/flipper-zero-flat-6-1.png b/docs/images/flipper-zero-ot-name.png similarity index 100% rename from docs/images/flipper-zero-flat-6-1.png rename to docs/images/flipper-zero-ot-name.png diff --git a/docs/images/flipper-zero-pinout-malveke.png b/docs/images/flipper-zero-pinout-malveke.png new file mode 100644 index 00000000000..472125e2980 Binary files /dev/null and b/docs/images/flipper-zero-pinout-malveke.png differ diff --git a/docs/images/flipper-zero-flat-02.png b/docs/images/flipper-zero-pinout-original.png similarity index 100% rename from docs/images/flipper-zero-flat-02.png rename to docs/images/flipper-zero-pinout-original.png diff --git a/docs/images/flipper-zero-flat-00.png b/docs/images/flipper-zero-pinout-select.png similarity index 100% rename from docs/images/flipper-zero-flat-00.png rename to docs/images/flipper-zero-pinout-select.png diff --git a/docs/images/flipper-zero-pokemon-select-1.png b/docs/images/flipper-zero-pokemon-select-1.png new file mode 100644 index 00000000000..e013d6ddeef Binary files /dev/null and b/docs/images/flipper-zero-pokemon-select-1.png differ diff --git a/docs/images/flipper-zero-pokemon-select-2.png b/docs/images/flipper-zero-pokemon-select-2.png new file mode 100644 index 00000000000..e7c41808af3 Binary files /dev/null and b/docs/images/flipper-zero-pokemon-select-2.png differ diff --git a/docs/images/flipper-zero-pokerus-infected.png b/docs/images/flipper-zero-pokerus-infected.png new file mode 100644 index 00000000000..354f8112ec5 Binary files /dev/null and b/docs/images/flipper-zero-pokerus-infected.png differ diff --git a/docs/images/flipper-zero-pokerus-setup.png b/docs/images/flipper-zero-pokerus-setup.png new file mode 100644 index 00000000000..1f1312338e7 Binary files /dev/null and b/docs/images/flipper-zero-pokerus-setup.png differ diff --git a/docs/images/flipper-zero-shiny.png b/docs/images/flipper-zero-shiny.png new file mode 100644 index 00000000000..8ec5ef13f2d Binary files /dev/null and b/docs/images/flipper-zero-shiny.png differ diff --git a/docs/images/flipper-zero-flat-5.png b/docs/images/flipper-zero-stats.png similarity index 100% rename from docs/images/flipper-zero-flat-5.png rename to docs/images/flipper-zero-stats.png diff --git a/docs/images/flipper-zero-flat-8-1.png b/docs/images/flipper-zero-type.png similarity index 100% rename from docs/images/flipper-zero-flat-8-1.png rename to docs/images/flipper-zero-type.png diff --git a/docs/images/flipper-zero-unown-form.png b/docs/images/flipper-zero-unown-form.png new file mode 100644 index 00000000000..467c0a4f8e7 Binary files /dev/null and b/docs/images/flipper-zero-unown-form.png differ diff --git a/docs/images/yt-vid-preview-frame.png b/docs/images/yt-vid-preview-frame.png new file mode 100644 index 00000000000..7a3d97a0bc2 Binary files /dev/null and b/docs/images/yt-vid-preview-frame.png differ diff --git a/files/all_sprites.fxbm b/files/all_sprites.fxbm new file mode 100644 index 00000000000..a0aace622ec Binary files /dev/null and b/files/all_sprites.fxbm differ diff --git a/item_nl.c b/item_nl.c new file mode 100644 index 00000000000..b709f7fe5f1 --- /dev/null +++ b/item_nl.c @@ -0,0 +1,231 @@ +#include +#include + +const NamedList item_list[] = { + {"No Item", 0x00, GEN_II}, + {"Amulet Coin", 0x5B, GEN_II}, + {"Antidote", 0x09, GEN_II}, + {"Awakening", 0x0C, GEN_II}, + {"Basement Key", 0x85, GEN_II}, + {"Berry", 0xAD, GEN_II}, + {"Berry Juice", 0x8B, GEN_II}, + {"Berserk Gene", 0x98, GEN_II}, + {"Bicycle", 0x07, GEN_II}, + {"Big Mushroom", 0x57, GEN_II}, + {"Big Pearl", 0x6F, GEN_II}, + {"Bitter Berry", 0x53, GEN_II}, + {"Blackbelt", 0x62, GEN_II}, + {"Black Glasses", 0x66, GEN_II}, + {"Blk Apricorn", 0x63, GEN_II}, + {"Blu Apricorn", 0x59, GEN_II}, + {"Blue Card (C Only)", 0x74, GEN_II}, + {"Bluesky Mail", 0xBB, GEN_II}, + {"Brick Piece", 0xB4, GEN_II}, + {"Bright Powder", 0x03, GEN_II}, + {"Burn Heal", 0x0A, GEN_II}, + {"Burnt Berry", 0x4F, GEN_II}, + {"Calcium", 0x1F, GEN_II}, + {"Carbos", 0x1D, GEN_II}, + {"Card Key", 0x7F, GEN_II}, + {"Charcoal", 0x8A, GEN_II}, + {"Cleanse Tag", 0x5E, GEN_II}, + {"Clear Bell (C Only)", 0x46, GEN_II}, + {"Coin Case", 0x36, GEN_II}, + {"Dire Hit", 0x2C, GEN_II}, + {"Dragon Fang", 0x90, GEN_II}, + {"Dragon Scale", 0x97, GEN_II}, + {"Egg Ticket (C Only)", 0x81, GEN_II}, + {"Elixir", 0x41, GEN_II}, + {"Energy Powder", 0x79, GEN_II}, + {"Energy Root", 0x7A, GEN_II}, + {"Eon Mail", 0xB9, GEN_II}, + {"Escape Rope", 0x13, GEN_II}, + {"Ether", 0x3F, GEN_II}, + {"Everstone", 0x70, GEN_II}, + {"Exp. Share", 0x39, GEN_II}, + {"Fast Ball", 0xA1, GEN_II}, + {"Fire Stone", 0x16, GEN_II}, + {"Flower Mail", 0x9E, GEN_II}, + {"Focus Band", 0x77, GEN_II}, + {"Fresh Water", 0x2E, GEN_II}, + {"Friend Ball", 0xA4, GEN_II}, + {"Full Heal", 0x26, GEN_II}, + {"Full Restore", 0x0E, GEN_II}, + {"Gold Berry", 0xAE, GEN_II}, + {"Gold Leaf", 0x4B, GEN_II}, + {"Good Rod", 0x3B, GEN_II}, + {"Gorgeous Box", 0xA8, GEN_II}, + {"Great Ball", 0x04, GEN_II}, + {"Grn Apricorn", 0x5D, GEN_II}, + {"GS Ball (C Only)", 0x73, GEN_II}, + {"Guard Spec.", 0x29, GEN_II}, + {"Hard Stone", 0x7D, GEN_II}, + {"Heal Powder", 0x7B, GEN_II}, + {"Heavy Ball", 0x9D, GEN_II}, + {"HM01", 0xF3, GEN_II}, + {"HM02", 0xF4, GEN_II}, + {"HM03", 0xF5, GEN_II}, + {"HM04", 0xF6, GEN_II}, + {"HM05", 0xF7, GEN_II}, + {"HM06", 0xF8, GEN_II}, + {"HM07", 0xF9, GEN_II}, + {"HP Up", 0x1A, GEN_II}, + {"Hyper Potion", 0x10, GEN_II}, + {"Ice Berry", 0x50, GEN_II}, + {"Ice Heal", 0x0B, GEN_II}, + {"Iron", 0x1C, GEN_II}, + {"Itemfinder", 0x37, GEN_II}, + {"King's Rock", 0x52, GEN_II}, + {"Leaf Stone", 0x22, GEN_II}, + {"Leftovers", 0x92, GEN_II}, + {"Lemonade", 0x30, GEN_II}, + {"Level Ball", 0x9F, GEN_II}, + {"Light Ball", 0xA3, GEN_II}, + {"Litebluemail", 0xB6, GEN_II}, + {"Lost Item", 0x82, GEN_II}, + {"Love Ball", 0xA6, GEN_II}, + {"Lovely Mail", 0xB8, GEN_II}, + {"Lucky Egg", 0x7E, GEN_II}, + {"Lucky Punch", 0x1E, GEN_II}, + {"Lure Ball", 0xA0, GEN_II}, + {"Machine Part", 0x80, GEN_II}, + {"Magnet", 0x6C, GEN_II}, + {"Master Ball", 0x01, GEN_II}, + {"Max Elixir", 0x15, GEN_II}, + {"Max Ether", 0x40, GEN_II}, + {"Max Potion", 0x0F, GEN_II}, + {"Max Repel", 0x2B, GEN_II}, + {"Max Revive", 0x28, GEN_II}, + {"Metal Coat", 0x8F, GEN_II}, + {"Metal Powder", 0x23, GEN_II}, + {"Mint Berry", 0x54, GEN_II}, + {"MiracleBerry", 0x6D, GEN_II}, + {"Miracle Seed", 0x75, GEN_II}, + {"Mirage Mail", 0xBD, GEN_II}, + {"Moomoo Milk", 0x48, GEN_II}, + {"Moon Ball", 0xA5, GEN_II}, + {"Moon Stone", 0x08, GEN_II}, + {"Morph Mail", 0xBA, GEN_II}, + {"Music Mail", 0xBC, GEN_II}, + {"Mystery Berry", 0x96, GEN_II}, + {"Mystery Egg", 0x45, GEN_II}, + {"Mystic Water", 0x5F, GEN_II}, + {"Never-Melt Ice", 0x6B, GEN_II}, + {"Normal Box", 0xA7, GEN_II}, + {"Nugget", 0x24, GEN_II}, + {"Old Rod", 0x3A, GEN_II}, + {"Paralyze Heal", 0x0D, GEN_II}, + {"Park Ball", 0xB1, GEN_II}, + {"Pass", 0x86, GEN_II}, + {"Pear l", 0x6E, GEN_II}, + {"Pink Bow", 0x68, GEN_II}, + {"Pnk Apricorn", 0x65, GEN_II}, + {"Poison Barb", 0x51, GEN_II}, + {"Poke Ball", 0x05, GEN_II}, + {"Poke Doll", 0x25, GEN_II}, + {"Polkadot Bow", 0xAA, GEN_II}, + {"Portraitmail", 0xB7, GEN_II}, + {"Potion", 0x12, GEN_II}, + {"PP Up", 0x3E, GEN_II}, + {"Protein", 0x1B, GEN_II}, + {"PRZCureBerry", 0x4E, GEN_II}, + {"PSNCureBerry", 0x4A, GEN_II}, + {"Quick Claw", 0x49, GEN_II}, + {"Rage Candy Bar", 0x72, GEN_II}, + {"Rainbow Wing", 0xB2, GEN_II}, + {"Rare Candy", 0x20, GEN_II}, + {"Red Apricorn", 0x55, GEN_II}, + {"Red Scale", 0x42, GEN_II}, + {"Repel", 0x14, GEN_II}, + {"Revival Herb", 0x7C, GEN_II}, + {"Revive", 0x27, GEN_II}, + {"Sacred Ash", 0x9C, GEN_II}, + {"Scope Lens", 0x8C, GEN_II}, + {"Secret Potion", 0x43, GEN_II}, + {"Sharp Beak", 0x4D, GEN_II}, + {"Silver Leaf", 0x3C, GEN_II}, + {"Silver Powder", 0x58, GEN_II}, + {"Silver Wing", 0x47, GEN_II}, + {"Slowpoke Tail", 0x67, GEN_II}, + {"Smoke Ball", 0x6A, GEN_II}, + {"Soda Pop", 0x2F, GEN_II}, + {"Soft Sand", 0x4C, GEN_II}, + {"Spell Tag", 0x71, GEN_II}, + {"Squirt Bottle", 0xAF, GEN_II}, + {"S.S. Ticket", 0x44, GEN_II}, + {"Stardust", 0x83, GEN_II}, + {"Star Piece", 0x84, GEN_II}, + {"Stick", 0x69, GEN_II}, + {"Sun Stone", 0xA9, GEN_II}, + {"Super Potion", 0x11, GEN_II}, + {"Super Repel", 0x2A, GEN_II}, + {"Super Rod", 0x3D, GEN_II}, + {"Surf Mail", 0xB5, GEN_II}, + {"Teru-sama", 0x5A, GEN_II}, + {"Teru-sama", 0x78, GEN_II}, + {"Thick Club", 0x76, GEN_II}, + {"Thunder Stone", 0x17, GEN_II}, + {"Tiny Mushroom", 0x56, GEN_II}, + {"TM01", 0xBF, GEN_II}, + {"TM02", 0xC0, GEN_II}, + {"TM03", 0xC1, GEN_II}, + {"TM04", 0xC2, GEN_II}, + {"TM05", 0xC4, GEN_II}, + {"TM06", 0xC5, GEN_II}, + {"TM07", 0xC6, GEN_II}, + {"TM08", 0xC7, GEN_II}, + {"TM09", 0xC8, GEN_II}, + {"TM10", 0xC9, GEN_II}, + {"TM11", 0xCA, GEN_II}, + {"TM12", 0xCB, GEN_II}, + {"TM13", 0xCC, GEN_II}, + {"TM14", 0xCD, GEN_II}, + {"TM15", 0xCE, GEN_II}, + {"TM16", 0xCF, GEN_II}, + {"TM17", 0xD0, GEN_II}, + {"TM18", 0xD1, GEN_II}, + {"TM19", 0xD2, GEN_II}, + {"TM20", 0xD3, GEN_II}, + {"TM21", 0xD4, GEN_II}, + {"TM22", 0xD5, GEN_II}, + {"TM23", 0xD6, GEN_II}, + {"TM24", 0xD7, GEN_II}, + {"TM25", 0xD8, GEN_II}, + {"TM26", 0xD9, GEN_II}, + {"TM27", 0xDA, GEN_II}, + {"TM28", 0xDB, GEN_II}, + {"TM29", 0xDD, GEN_II}, + {"TM30", 0xDE, GEN_II}, + {"TM31", 0xDF, GEN_II}, + {"TM32", 0xE0, GEN_II}, + {"TM33", 0xE1, GEN_II}, + {"TM34", 0xE2, GEN_II}, + {"TM35", 0xE3, GEN_II}, + {"TM36", 0xE4, GEN_II}, + {"TM37", 0xE5, GEN_II}, + {"TM38", 0xE6, GEN_II}, + {"TM39", 0xE7, GEN_II}, + {"TM40", 0xE8, GEN_II}, + {"TM41", 0xE9, GEN_II}, + {"TM42", 0xEA, GEN_II}, + {"TM43", 0xEB, GEN_II}, + {"TM44", 0xEC, GEN_II}, + {"TM45", 0xED, GEN_II}, + {"TM46", 0xEE, GEN_II}, + {"TM47", 0xEF, GEN_II}, + {"TM48", 0xF0, GEN_II}, + {"TM49", 0xF1, GEN_II}, + {"TM50", 0xF2, GEN_II}, + {"Twisted Spoon", 0x60, GEN_II}, + {"Ultra Ball", 0x02, GEN_II}, + {"Up-Grade", 0xAC, GEN_II}, + {"Water Stone", 0x18, GEN_II}, + {"Wht Apricorn", 0x61, GEN_II}, + {"X Accuracy", 0x21, GEN_II}, + {"X Attack", 0x31, GEN_II}, + {"X Defend", 0x33, GEN_II}, + {"X Special", 0x35, GEN_II}, + {"X Speed", 0x34, GEN_II}, + {"Ylw Apricorn", 0x5C, GEN_II}, + {}, +}; diff --git a/item_nl.h b/item_nl.h new file mode 100644 index 00000000000..3c60c4e81af --- /dev/null +++ b/item_nl.h @@ -0,0 +1,8 @@ +#ifndef __ITEM_NL_H__ +#define __ITEM_NL_H__ + +#pragma once + +extern const NamedList item_list[]; + +#endif // __ITEM_NL_H__ diff --git a/lib/flipper-gblink b/lib/flipper-gblink index 91c64228207..93931d71fff 160000 --- a/lib/flipper-gblink +++ b/lib/flipper-gblink @@ -1 +1 @@ -Subproject commit 91c64228207b2312289c67a83e321084381ebe50 +Subproject commit 93931d71fffd0476a591dc18d3263a02e93a169a diff --git a/missingno_i.h b/missingno_i.h new file mode 100644 index 00000000000..3b0fc7fa6ef --- /dev/null +++ b/missingno_i.h @@ -0,0 +1,28 @@ +unsigned char __000_fxbm[] = { + 0x90, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xc0, + 0x1f, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x03, 0xfe, + 0xc0, 0x0f, 0x00, 0x00, 0xf8, 0x81, 0xff, 0x81, 0x1f, 0x00, 0x00, 0xf8, 0xe0, 0xff, 0x07, 0x1f, + 0x00, 0x00, 0x7c, 0xf0, 0xc3, 0x0f, 0x3e, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x1f, 0x3e, 0x00, 0x00, + 0x3e, 0x7c, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x3e, 0x3c, 0x18, 0x3c, 0x7c, 0x00, 0x00, 0x1f, 0x3e, + 0x3c, 0x7c, 0xf8, 0x00, 0x00, 0x1f, 0x3e, 0x3c, 0x7c, 0xf8, 0x00, 0x00, 0x1f, 0x3f, 0x3c, 0xfc, + 0xf8, 0x00, 0x00, 0x1f, 0x3f, 0x1c, 0xfc, 0xf8, 0x00, 0x00, 0x1f, 0x7f, 0x0e, 0xfe, 0xf8, 0x00, + 0x00, 0x1f, 0xff, 0x07, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0x83, 0xff, 0xf8, 0x00, 0x00, 0x1f, + 0xff, 0xc3, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xfe, 0xe7, 0x7f, 0xf8, 0x00, 0x00, 0x1f, 0xfe, 0xff, + 0x7f, 0xf8, 0x00, 0x00, 0x3e, 0xfc, 0xc3, 0x3f, 0x7c, 0x00, 0x00, 0x3e, 0xfc, 0x81, 0x3f, 0x7c, + 0x00, 0x00, 0x7c, 0xf8, 0x81, 0x1f, 0x3e, 0x00, 0x00, 0x7c, 0xf0, 0xc3, 0x0f, 0x3e, 0x00, 0x00, + 0xf8, 0xe1, 0xff, 0x07, 0x1f, 0x00, 0x00, 0xf8, 0x81, 0xff, 0x81, 0x1f, 0x00, 0x00, 0xf0, 0x03, + 0x7e, 0xc0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0xf8, + 0x03, 0x00, 0x00, 0x80, 0x7f, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; +unsigned int __000_fxbm_len = 404; diff --git a/move_nl.c b/move_nl.c new file mode 100644 index 00000000000..5cb938e6a15 --- /dev/null +++ b/move_nl.c @@ -0,0 +1,258 @@ +#include +#include + +const NamedList move_list[] = { + {"No Move", 0x00, (GEN_I | GEN_II)}, + {"Absorb", 0x47, (GEN_I | GEN_II)}, + {"Acid", 0x33, (GEN_I | GEN_II)}, + {"Acid Armor", 0x97, (GEN_I | GEN_II)}, + {"Aeroblast", 0xB1, GEN_II}, + {"Agility", 0x61, (GEN_I | GEN_II)}, + {"Amnesia", 0x85, (GEN_I | GEN_II)}, + {"Ancient Power", 0xF6, GEN_II}, + {"Attract", 0xD5, GEN_II}, + {"Aurora Beam", 0x3E, (GEN_I | GEN_II)}, + {"Barrage", 0x8C, (GEN_I | GEN_II)}, + {"Barrier", 0x70, (GEN_I | GEN_II)}, + {"Baton Pass", 0xE2, GEN_II}, + {"Beat Up", 0xFB, GEN_II}, + {"Belly Drum", 0xBB, GEN_II}, + {"Bide", 0x75, (GEN_I | GEN_II)}, + {"Bind", 0x14, (GEN_I | GEN_II)}, + {"Bite", 0x2C, (GEN_I | GEN_II)}, + {"Blizzard", 0x3B, (GEN_I | GEN_II)}, + {"Body Slam", 0x22, (GEN_I | GEN_II)}, + {"Bone Club", 0x7D, (GEN_I | GEN_II)}, + {"Bone Rush", 0xC6, GEN_II}, + {"Boomerang", 0x9B, (GEN_I | GEN_II)}, + {"Bubble", 0x91, (GEN_I | GEN_II)}, + {"Bubblebeam", 0x3D, (GEN_I | GEN_II)}, + {"Charm", 0xCC, GEN_II}, + {"Clamp", 0x80, (GEN_I | GEN_II)}, + {"Comet Punch", 0x04, (GEN_I | GEN_II)}, + {"Confuse Ray", 0x6D, (GEN_I | GEN_II)}, + {"Confusion", 0x5D, (GEN_I | GEN_II)}, + {"Constrict", 0x84, (GEN_I | GEN_II)}, + {"Conversion", 0xA0, (GEN_I | GEN_II)}, + {"Conversion 2", 0xB0, GEN_II}, + {"Cotton Spore", 0xB2, GEN_II}, + {"Counter", 0x44, (GEN_I | GEN_II)}, + {"Crabhammer", 0x98, (GEN_I | GEN_II)}, + {"Cross Chop", 0xEE, GEN_II}, + {"Crunch", 0xF2, GEN_II}, + {"Curse", 0xAE, GEN_II}, + {"Cut", 0x0F, (GEN_I | GEN_II)}, + {"Defense Curl", 0x6F, (GEN_I | GEN_II)}, + {"Destiny Bond", 0xC2, GEN_II}, + {"Detect", 0xC5, GEN_II}, + {"Dig", 0x5B, (GEN_I | GEN_II)}, + {"Disable", 0x32, (GEN_I | GEN_II)}, + {"Dizzy Punch", 0x92, (GEN_I | GEN_II)}, + {"Double-Edge", 0x26, (GEN_I | GEN_II)}, + {"Double Kick", 0x18, (GEN_I | GEN_II)}, + {"Doubleslap", 0x03, (GEN_I | GEN_II)}, + {"Double Team", 0x68, (GEN_I | GEN_II)}, + {"Dragon Breath", 0xE1, GEN_II}, + {"Dragon Rage", 0x52, (GEN_I | GEN_II)}, + {"Dream Eater", 0x8A, (GEN_I | GEN_II)}, + {"Drill Peck", 0x41, (GEN_I | GEN_II)}, + {"Dynamic Punch", 0xDF, GEN_II}, + {"Earthquake", 0x59, (GEN_I | GEN_II)}, + {"Egg Bomb", 0x79, (GEN_I | GEN_II)}, + {"Ember", 0x34, (GEN_I | GEN_II)}, + {"Encore", 0xE3, GEN_II}, + {"Endure", 0xCB, GEN_II}, + {"Explosion", 0x99, (GEN_I | GEN_II)}, + {"Extreme Speed", 0xF5, GEN_II}, + {"False Swipe", 0xCE, GEN_II}, + {"Feint Attack", 0xB9, GEN_II}, + {"Fire Blast", 0x7E, (GEN_I | GEN_II)}, + {"Fire Punch", 0x07, (GEN_I | GEN_II)}, + {"Fire Spin", 0x53, (GEN_I | GEN_II)}, + {"Fissure", 0x5A, (GEN_I | GEN_II)}, + {"Flail", 0xAF, GEN_II}, + {"Flamethrower", 0x35, (GEN_I | GEN_II)}, + {"Flame Wheel", 0xAC, GEN_II}, + {"Flash", 0x94, (GEN_I | GEN_II)}, + {"Fly", 0x13, (GEN_I | GEN_II)}, + {"Focus Energy", 0x74, (GEN_I | GEN_II)}, + {"Foresight", 0xC1, GEN_II}, + {"Frustration", 0xDA, GEN_II}, + {"Fury Attack", 0x1F, (GEN_I | GEN_II)}, + {"Fury Cutter", 0xD2, GEN_II}, + {"Fury Swipes", 0x9A, (GEN_I | GEN_II)}, + {"Future Sight", 0xF8, GEN_II}, + {"Giga Drain", 0xCA, GEN_II}, + {"Glare", 0x89, (GEN_I | GEN_II)}, + {"Growl", 0x2D, (GEN_I | GEN_II)}, + {"Growth", 0x4A, (GEN_I | GEN_II)}, + {"Guillotine", 0x0C, (GEN_I | GEN_II)}, + {"Gust", 0x10, (GEN_I | GEN_II)}, + {"Harden", 0x6A, (GEN_I | GEN_II)}, + {"Haze", 0x72, (GEN_I | GEN_II)}, + {"Headbutt", 0x1D, (GEN_I | GEN_II)}, + {"Heal Bell", 0xD7, GEN_II}, + {"Hidden Power", 0xED, GEN_II}, + {"Hi Jump Kick", 0x88, (GEN_I | GEN_II)}, + {"Horn Attack", 0x1E, (GEN_I | GEN_II)}, + {"Horn Drill", 0x20, (GEN_I | GEN_II)}, + {"Hydro Pump", 0x38, (GEN_I | GEN_II)}, + {"Hyper Beam", 0x3F, (GEN_I | GEN_II)}, + {"Hyper Fang", 0x9E, (GEN_I | GEN_II)}, + {"Hypnosis", 0x5F, (GEN_I | GEN_II)}, + {"Ice Beam", 0x3A, (GEN_I | GEN_II)}, + {"Ice Punch", 0x08, (GEN_I | GEN_II)}, + {"Icy Wind", 0xC4, GEN_II}, + {"Iron Tail", 0xE7, GEN_II}, + {"Jump Kick", 0x1A, (GEN_I | GEN_II)}, + {"Karate Chop", 0x02, (GEN_I | GEN_II)}, + {"Kinesis", 0x86, (GEN_I | GEN_II)}, + {"Leech Life", 0x8D, (GEN_I | GEN_II)}, + {"Leech Seed", 0x49, (GEN_I | GEN_II)}, + {"Leer", 0x2B, (GEN_I | GEN_II)}, + {"Lick", 0x7A, (GEN_I | GEN_II)}, + {"Light Screen", 0x71, (GEN_I | GEN_II)}, + {"Lock-On", 0xC7, GEN_II}, + {"Lovely Kiss", 0x8E, (GEN_I | GEN_II)}, + {"Low Kick", 0x43, (GEN_I | GEN_II)}, + {"Mach Punch", 0xB7, GEN_II}, + {"Magnitude", 0xDE, GEN_II}, + {"Mean Look", 0xD4, GEN_II}, + {"Meditate", 0x60, (GEN_I | GEN_II)}, + {"Mega Drain", 0x48, (GEN_I | GEN_II)}, + {"Megahorn", 0xE0, GEN_II}, + {"Mega Kick", 0x19, (GEN_I | GEN_II)}, + {"Mega Punch", 0x05, (GEN_I | GEN_II)}, + {"Metal Claw", 0xE8, GEN_II}, + {"Metronome", 0x76, (GEN_I | GEN_II)}, + {"Milk Drink", 0xD0, GEN_II}, + {"Mimic", 0x66, (GEN_I | GEN_II)}, + {"Mind Reader", 0xAA, GEN_II}, + {"Minimize", 0x6B, (GEN_I | GEN_II)}, + {"Mirror Coat", 0xF3, GEN_II}, + {"Mirror Move", 0x77, (GEN_I | GEN_II)}, + {"Mist", 0x36, (GEN_I | GEN_II)}, + {"Moonlight", 0xEC, GEN_II}, + {"Morning Sun", 0xEA, GEN_II}, + {"Mud-Slap", 0xBD, GEN_II}, + {"Nightmare", 0xAB, GEN_II}, + {"Night Shade", 0x65, (GEN_I | GEN_II)}, + {"Octazooka", 0xBE, GEN_II}, + {"Outrage", 0xC8, GEN_II}, + {"Pain Split", 0xDC, GEN_II}, + {"Pay Day", 0x06, (GEN_I | GEN_II)}, + {"Peck", 0x40, (GEN_I | GEN_II)}, + {"Perish Song", 0xC3, GEN_II}, + {"Petal Dance", 0x50, (GEN_I | GEN_II)}, + {"Pin Missile", 0x2A, (GEN_I | GEN_II)}, + {"Poison Gas", 0x8B, (GEN_I | GEN_II)}, + {"Poisonpowder", 0x4D, (GEN_I | GEN_II)}, + {"Poison Sting", 0x28, (GEN_I | GEN_II)}, + {"Pound", 0x01, (GEN_I | GEN_II)}, + {"Powder Snow", 0xB5, GEN_II}, + {"Present", 0xD9, GEN_II}, + {"Protect", 0xB6, GEN_II}, + {"Psybeam", 0x3C, (GEN_I | GEN_II)}, + {"Psychic", 0x5E, (GEN_I | GEN_II)}, + {"Psych Up", 0xF4, GEN_II}, + {"Psywave", 0x95, (GEN_I | GEN_II)}, + {"Pursuit", 0xE4, GEN_II}, + {"Quick Attack", 0x62, (GEN_I | GEN_II)}, + {"Rage", 0x63, (GEN_I | GEN_II)}, + {"Rain Dance", 0xF0, GEN_II}, + {"Rapid Spin", 0xE5, GEN_II}, + {"Razor Leaf", 0x4B, (GEN_I | GEN_II)}, + {"Razor Wind", 0x0D, (GEN_I | GEN_II)}, + {"Recover", 0x69, (GEN_I | GEN_II)}, + {"Reflect", 0x73, (GEN_I | GEN_II)}, + {"Rest", 0x9C, (GEN_I | GEN_II)}, + {"Return", 0xD8, GEN_II}, + {"Reversal", 0xB3, GEN_II}, + {"Roar", 0x2E, (GEN_I | GEN_II)}, + {"Rock Slide", 0x9D, (GEN_I | GEN_II)}, + {"Rock Smash", 0xF9, GEN_II}, + {"Rock Throw", 0x58, (GEN_I | GEN_II)}, + {"Rolling Kick", 0x1B, (GEN_I | GEN_II)}, + {"Rollout", 0xCD, GEN_II}, + {"Sacred Fire", 0xDD, GEN_II}, + {"Safeguard", 0xDB, GEN_II}, + {"Sand Attack", 0x1C, (GEN_I | GEN_II)}, + {"Sandstorm", 0xC9, GEN_II}, + {"Scary Face", 0xB8, GEN_II}, + {"Scratch", 0x0A, (GEN_I | GEN_II)}, + {"Screech", 0x67, (GEN_I | GEN_II)}, + {"Seismic Toss", 0x45, (GEN_I | GEN_II)}, + {"Selfdestruct", 0x78, (GEN_I | GEN_II)}, + {"Shadow Ball", 0xF7, GEN_II}, + {"Sharpen", 0x9F, (GEN_I | GEN_II)}, + {"Sing", 0x2F, (GEN_I | GEN_II)}, + {"Sketch", 0xA6, GEN_II}, + {"Skull Bash", 0x82, (GEN_I | GEN_II)}, + {"Sky Attack", 0x8F, (GEN_I | GEN_II)}, + {"Slam", 0x15, (GEN_I | GEN_II)}, + {"Slash", 0xA3, (GEN_I | GEN_II)}, + {"Sleep Powder", 0x4F, (GEN_I | GEN_II)}, + {"Sleep Talk", 0xD6, GEN_II}, + {"Sludge", 0x7C, (GEN_I | GEN_II)}, + {"Sludge Bomb", 0xBC, GEN_II}, + {"Smog", 0x7B, (GEN_I | GEN_II)}, + {"Smokescreen", 0x6C, (GEN_I | GEN_II)}, + {"Snore", 0xAD, GEN_II}, + {"Softboiled", 0x87, (GEN_I | GEN_II)}, + {"Solar Beam", 0x4C, (GEN_I | GEN_II)}, + {"Sonicboom", 0x31, (GEN_I | GEN_II)}, + {"Spark", 0xD1, GEN_II}, + {"Spider Web", 0xA9, GEN_II}, + {"Spike Cannon", 0x83, (GEN_I | GEN_II)}, + {"Spikes", 0xBF, GEN_II}, + {"Spite", 0xB4, GEN_II}, + {"Splash", 0x96, (GEN_I | GEN_II)}, + {"Spore", 0x93, (GEN_I | GEN_II)}, + {"Steel Wing", 0xD3, GEN_II}, + {"Stomp", 0x17, (GEN_I | GEN_II)}, + {"Strength", 0x46, (GEN_I | GEN_II)}, + {"String Shot", 0x51, (GEN_I | GEN_II)}, + {"Struggle", 0xA5, (GEN_I | GEN_II)}, + {"Stun Spore", 0x4E, (GEN_I | GEN_II)}, + {"Submission", 0x42, (GEN_I | GEN_II)}, + {"Substitute", 0xA4, (GEN_I | GEN_II)}, + {"Sunny Day", 0xF1, GEN_II}, + {"Super Fang", 0xA2, (GEN_I | GEN_II)}, + {"Supersonic", 0x30, (GEN_I | GEN_II)}, + {"Surf", 0x39, (GEN_I | GEN_II)}, + {"Swagger", 0xCF, GEN_II}, + {"Sweet Kiss", 0xBA, GEN_II}, + {"Sweet Scent", 0xE6, GEN_II}, + {"Swift", 0x81, (GEN_I | GEN_II)}, + {"Swords Dance", 0x0E, (GEN_I | GEN_II)}, + {"Synthesis", 0xEB, GEN_II}, + {"Tackle", 0x21, (GEN_I | GEN_II)}, + {"Tail Whip", 0x27, (GEN_I | GEN_II)}, + {"Take Down", 0x24, (GEN_I | GEN_II)}, + {"Teleport", 0x64, (GEN_I | GEN_II)}, + {"Thief", 0xA8, GEN_II}, + {"Thrash", 0x25, (GEN_I | GEN_II)}, + {"Thunder", 0x57, (GEN_I | GEN_II)}, + {"Thunderbolt", 0x55, (GEN_I | GEN_II)}, + {"Thunderpunch", 0x09, (GEN_I | GEN_II)}, + {"Thundershock", 0x54, (GEN_I | GEN_II)}, + {"Thunder Wave", 0x56, (GEN_I | GEN_II)}, + {"Toxic", 0x5C, (GEN_I | GEN_II)}, + {"Transform", 0x90, (GEN_I | GEN_II)}, + {"Tri Attack", 0xA1, (GEN_I | GEN_II)}, + {"Triple Kick", 0xA7, GEN_II}, + {"Twineedle", 0x29, (GEN_I | GEN_II)}, + {"Twister", 0xEF, GEN_II}, + {"Vicegrip", 0x0B, (GEN_I | GEN_II)}, + {"Vine Whip", 0x16, (GEN_I | GEN_II)}, + {"Vital Throw", 0xE9, GEN_II}, + {"Waterfall", 0x7F, (GEN_I | GEN_II)}, + {"Water Gun", 0x37, (GEN_I | GEN_II)}, + {"Whirlpool", 0xFA, GEN_II}, + {"Whirlwind", 0x12, (GEN_I | GEN_II)}, + {"Wing Attack", 0x11, (GEN_I | GEN_II)}, + {"Withdraw", 0x6E, (GEN_I | GEN_II)}, + {"Wrap", 0x23, (GEN_I | GEN_II)}, + {"Zap Cannon", 0xC0, GEN_II}, + {}, +}; diff --git a/move_nl.h b/move_nl.h new file mode 100644 index 00000000000..2a7e4bbe3dc --- /dev/null +++ b/move_nl.h @@ -0,0 +1,8 @@ +#ifndef __MOVE_NL_H__ +#define __MOVE_NL_H__ + +#pragma once + +extern const NamedList move_list[]; + +#endif // __MOVE_NL_H__ diff --git a/named_list.c b/named_list.c new file mode 100644 index 00000000000..746caa59630 --- /dev/null +++ b/named_list.c @@ -0,0 +1,61 @@ +#include +#include + +#include + +/* Get number of elements in a list + * This is not very efficient as-is since it has to walk the whole list. + */ +size_t namedlist_cnt(const NamedList* list) { + size_t i; + + for(i = 0;; i++) { + if(list[i].name == NULL) return i; + } +} + +/* Returns the generation mask of the requested item in the list */ +uint32_t namedlist_gen_get_pos(const NamedList* list, uint32_t pos) { + return list[pos].gen; +} + +/* Returns the generation mask of the item in the list that matches the + * provided index. This will ultimately return the 0th element in the case + * of the provided index not matching any of the list elements. + */ +uint32_t namedlist_gen_get_index(const NamedList* list, uint32_t index) { + return list[namedlist_pos_get(list, index)].gen; +} + +/* Returns the list position based on the provided index. If index is not + * matched, the 0th position is returned. In most lists this is a "NONE" + * indicator. e.g. No Move. + */ +uint32_t namedlist_pos_get(const NamedList* list, uint32_t index) { + int i; + + for(i = 0;; i++) { + if(list[i].name == NULL) break; + if(index == list[i].index) return i; + } + + /* This will return the first entry in case index is not matched. + * Could be surprising at runtime. + */ + return 0; +} + +/* Get the item's index value from the position specified */ +uint32_t namedlist_index_get(const NamedList* list, uint32_t pos) { + return list[pos].index; +} + +/* Get a pointer to the item's name from an item's index */ +const char* namedlist_name_get_index(const NamedList* list, uint32_t index) { + return list[namedlist_pos_get(list, index)].name; +} + +/* Get a pointer to the item's name from a position */ +const char* namedlist_name_get_pos(const NamedList* list, uint32_t pos) { + return list[pos].name; +} diff --git a/named_list.h b/named_list.h new file mode 100644 index 00000000000..4b3fad71b18 --- /dev/null +++ b/named_list.h @@ -0,0 +1,46 @@ +#ifndef __NAMED_LIST_H__ +#define __NAMED_LIST_H__ + +#pragma once + +#include +#include + +struct __attribute__((__packed__)) named_list { + const char* name; + const uint8_t index; + const uint8_t gen; // Bitfield of compatible generations +}; + +typedef struct named_list NamedList; + +/* Get number of elements in a list + * This is not very efficient as-is since it has to walk the whole list. + */ +size_t namedlist_cnt(const NamedList* list); + +/* Returns the generation mask of the requested item in the list */ +uint32_t namedlist_gen_get_pos(const NamedList* list, uint32_t pos); + +/* Returns the generation mask of the item in the list that matches the + * provided index. This will ultimately return the 0th element in the case + * of the provided index not matching any of the list elements. + */ +uint32_t namedlist_gen_get_index(const NamedList* list, uint32_t index); + +/* Returns the list position based on the provided index. If index is not + * matched, the 0th position is returned. In most lists this is a "NONE" + * indicator. e.g. No Move. + */ +uint32_t namedlist_pos_get(const NamedList* list, uint32_t index); + +/* Get the item's index value from the position specified */ +uint32_t namedlist_index_get(const NamedList* list, uint32_t pos); + +/* Get a pointer to the item's name from an item's index */ +const char* namedlist_name_get_index(const NamedList* list, uint32_t index); + +/* Get a pointer to the item's name from a position */ +const char* namedlist_name_get_pos(const NamedList* list, uint32_t pos); + +#endif //__NAMED_LIST_H__ diff --git a/pokemon_app.c b/pokemon_app.c index 000245b77d1..200d892cabd 100644 --- a/pokemon_app.c +++ b/pokemon_app.c @@ -1,2155 +1,13 @@ #include -#include #include +#include "pokemon_app.h" +#include "pokemon_data.h" #include "scenes/pokemon_menu.h" #include "views/trade.h" #include "views/select_pokemon.h" -#include "pokemon_app.h" #include "pokemon_char_encode.h" -const PokemonTable pokemon_table[] = { - /* Values for base_*, moves, etc., pulled directly from a copy of Pokemon Blue */ - {"Bulbasaur", - &I_bulbasaur, - 0x99, - 0x2D, - 0x31, - 0x31, - 0x2D, - 0x41, - {0x16, 0x03}, - {0x21, 0x2D, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Ivysaur", - &I_ivysaur, - 0x09, - 0x3C, - 0x3E, - 0x3F, - 0x3C, - 0x50, - {0x16, 0x03}, - {0x21, 0x2D, 0x49, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Venusaur", - &I_venusaur, - 0x9A, - 0x50, - 0x52, - 0x53, - 0x50, - 0x64, - {0x16, 0x03}, - {0x21, 0x2D, 0x49, 0x16}, - GROWTH_MEDIUM_SLOW}, - {"Charmander", - &I_charmander, - 0xB0, - 0x27, - 0x34, - 0x2B, - 0x41, - 0x32, - {0x14, 0x14}, - {0x0A, 0x2D, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Charmeleon", - &I_charmeleon, - 0xB2, - 0x3A, - 0x40, - 0x3A, - 0x50, - 0x41, - {0x14, 0x14}, - {0x0A, 0x2D, 0x34, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Charizard", - &I_charizard, - 0xB4, - 0x4E, - 0x54, - 0x4E, - 0x64, - 0x55, - {0x14, 0x02}, - {0x0A, 0x2D, 0x34, 0x2B}, - GROWTH_MEDIUM_SLOW}, - {"Squirtle", - &I_squirtle, - 0xB1, - 0x2C, - 0x30, - 0x41, - 0x2B, - 0x32, - {0x15, 0x15}, - {0x21, 0x27, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Wartortle", - &I_wartortle, - 0xB3, - 0x3B, - 0x3F, - 0x50, - 0x3A, - 0x41, - {0x15, 0x15}, - {0x21, 0x27, 0x91, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Blastoise", - &I_blastoise, - 0x1C, - 0x4F, - 0x53, - 0x64, - 0x4E, - 0x55, - {0x15, 0x15}, - {0x21, 0x27, 0x91, 0x37}, - GROWTH_MEDIUM_SLOW}, - {"Caterpie", - &I_caterpie, - 0x7B, - 0x2D, - 0x1E, - 0x23, - 0x2D, - 0x14, - {0x07, 0x07}, - {0x21, 0x51, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Metapod", - &I_metapod, - 0x7C, - 0x32, - 0x14, - 0x37, - 0x1E, - 0x19, - {0x07, 0x07}, - {0x6A, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Butterfree", - &I_butterfree, - 0x7D, - 0x3C, - 0x2D, - 0x32, - 0x46, - 0x50, - {0x07, 0x02}, - {0x5D, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Weedle", - &I_weedle, - 0x70, - 0x28, - 0x23, - 0x1E, - 0x32, - 0x14, - {0x07, 0x03}, - {0x28, 0x51, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Kakuna", - &I_kakuna, - 0x71, - 0x2D, - 0x19, - 0x32, - 0x23, - 0x19, - {0x07, 0x03}, - {0x6A, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Beedrill", - &I_beedrill, - 0x72, - 0x41, - 0x50, - 0x28, - 0x4B, - 0x2D, - {0x07, 0x03}, - {0x1F, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Pidgey", - &I_pidgey, - 0x24, - 0x28, - 0x2D, - 0x28, - 0x38, - 0x23, - {0x00, 0x02}, - {0x10, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Pidgeotto", - &I_pidgeotto, - 0x96, - 0x3F, - 0x3C, - 0x37, - 0x47, - 0x32, - {0x00, 0x02}, - {0x10, 0x1C, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Pidgeot", - &I_pidgeot, - 0x97, - 0x53, - 0x50, - 0x4B, - 0x5B, - 0x46, - {0x00, 0x02}, - {0x10, 0x1C, 0x62, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Rattata", - &I_rattata, - 0xA5, - 0x1E, - 0x38, - 0x23, - 0x48, - 0x19, - {0x00, 0x00}, - {0x21, 0x27, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Raticate", - &I_raticate, - 0xA6, - 0x37, - 0x51, - 0x3C, - 0x61, - 0x32, - {0x00, 0x00}, - {0x21, 0x27, 0x62, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Spearow", - &I_spearow, - 0x05, - 0x28, - 0x3C, - 0x1E, - 0x46, - 0x1F, - {0x00, 0x02}, - {0x40, 0x2D, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Fearow", - &I_fearow, - 0x23, - 0x41, - 0x5A, - 0x41, - 0x64, - 0x3D, - {0x00, 0x02}, - {0x40, 0x2D, 0x2B, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Ekans", - &I_ekans, - 0x6C, - 0x23, - 0x3C, - 0x2C, - 0x37, - 0x28, - {0x03, 0x03}, - {0x23, 0x2B, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Arbok", - &I_arbok, - 0x2D, - 0x3C, - 0x55, - 0x45, - 0x50, - 0x41, - {0x03, 0x03}, - {0x23, 0x2B, 0x28, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Pikachu", - &I_pikachu, - 0x54, - 0x23, - 0x37, - 0x1E, - 0x5A, - 0x32, - {0x17, 0x17}, - {0x54, 0x2D, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Raichu", - &I_raichu, - 0x55, - 0x3C, - 0x5A, - 0x37, - 0x64, - 0x5A, - {0x17, 0x17}, - {0x54, 0x2D, 0x56, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Sandshrew", - &I_sandshrew, - 0x60, - 0x32, - 0x4B, - 0x55, - 0x28, - 0x1E, - {0x04, 0x04}, - {0x0A, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Sandslash", - &I_sandslash, - 0x61, - 0x4B, - 0x64, - 0x6E, - 0x41, - 0x37, - {0x04, 0x04}, - {0x0A, 0x1C, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Nidoran\200", - &I_nidoranf, - 0x0F, - 0x37, - 0x2F, - 0x34, - 0x29, - 0x28, - {0x03, 0x03}, - {0x2D, 0x21, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Nidorina", - &I_nidorina, - 0xA8, - 0x46, - 0x3E, - 0x43, - 0x38, - 0x37, - {0x03, 0x03}, - {0x2D, 0x21, 0x0A, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Nidoqueen", - &I_nidoqueen, - 0x10, - 0x5A, - 0x52, - 0x57, - 0x4C, - 0x4B, - {0x03, 0x04}, - {0x21, 0x0A, 0x27, 0x22}, - GROWTH_MEDIUM_SLOW}, - {"Nidoran\201", - &I_nidoranm, - 0x03, - 0x2E, - 0x39, - 0x28, - 0x32, - 0x28, - {0x03, 0x03}, - {0x2B, 0x21, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Nidorino", - &I_nidorino, - 0xA7, - 0x3D, - 0x48, - 0x39, - 0x41, - 0x37, - {0x03, 0x03}, - {0x2B, 0x21, 0x1E, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Nidoking", - &I_nidoking, - 0x07, - 0x51, - 0x5C, - 0x4D, - 0x55, - 0x4B, - {0x03, 0x04}, - {0x21, 0x1E, 0x28, 0x25}, - GROWTH_MEDIUM_SLOW}, - {"Clefairy", - &I_clefairy, - 0x04, - 0x46, - 0x2D, - 0x30, - 0x23, - 0x3C, - {0x00, 0x00}, - {0x01, 0x2D, 0x00, 0x00}, - GROWTH_FAST}, - {"Clefable", - &I_clefable, - 0x8E, - 0x5F, - 0x46, - 0x49, - 0x3C, - 0x55, - {0x00, 0x00}, - {0x2F, 0x03, 0x6B, 0x76}, - GROWTH_FAST}, - {"Vulpix", - &I_vulpix, - 0x52, - 0x26, - 0x29, - 0x28, - 0x41, - 0x41, - {0x14, 0x14}, - {0x34, 0x27, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Ninetales", - &I_ninetales, - 0x53, - 0x49, - 0x4C, - 0x4B, - 0x64, - 0x64, - {0x14, 0x14}, - {0x34, 0x27, 0x62, 0x2E}, - GROWTH_MEDIUM_FAST}, - {"Jigglypuff", - &I_jigglypuff, - 0x64, - 0x73, - 0x2D, - 0x14, - 0x14, - 0x19, - {0x00, 0x00}, - {0x2F, 0x00, 0x00, 0x00}, - GROWTH_FAST}, - {"Wigglytuff", - &I_wigglytuff, - 0x65, - 0x8C, - 0x46, - 0x2D, - 0x2D, - 0x32, - {0x00, 0x00}, - {0x2F, 0x32, 0x6F, 0x03}, - GROWTH_FAST}, - {"Zubat", - &I_zubat, - 0x6B, - 0x28, - 0x2D, - 0x23, - 0x37, - 0x28, - {0x03, 0x02}, - {0x8D, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Golbat", - &I_golbat, - 0x82, - 0x4B, - 0x50, - 0x46, - 0x5A, - 0x4B, - {0x03, 0x02}, - {0x8D, 0x67, 0x2C, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Oddish", - &I_oddish, - 0xB9, - 0x2D, - 0x32, - 0x37, - 0x1E, - 0x4B, - {0x16, 0x03}, - {0x47, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Gloom", - &I_gloom, - 0xBA, - 0x3C, - 0x41, - 0x46, - 0x28, - 0x55, - {0x16, 0x03}, - {0x47, 0x4D, 0x4E, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Vileplume", - &I_vileplume, - 0xBB, - 0x4B, - 0x50, - 0x55, - 0x32, - 0x64, - {0x16, 0x03}, - {0x4E, 0x4F, 0x33, 0x50}, - GROWTH_MEDIUM_SLOW}, - {"Paras", - &I_paras, - 0x6D, - 0x23, - 0x46, - 0x37, - 0x19, - 0x37, - {0x07, 0x16}, - {0x0A, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Parasect", - &I_parasect, - 0x2E, - 0x3C, - 0x5F, - 0x50, - 0x1E, - 0x50, - {0x07, 0x16}, - {0x0A, 0x4E, 0x8D, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Venonat", - &I_venonat, - 0x41, - 0x3C, - 0x37, - 0x32, - 0x2D, - 0x28, - {0x07, 0x03}, - {0x21, 0x32, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Venomoth", - &I_venomoth, - 0x77, - 0x46, - 0x41, - 0x3C, - 0x5A, - 0x5A, - {0x07, 0x03}, - {0x21, 0x32, 0x4D, 0x8D}, - GROWTH_MEDIUM_FAST}, - {"Diglett", - &I_diglett, - 0x3B, - 0x0A, - 0x37, - 0x19, - 0x5F, - 0x2D, - {0x04, 0x04}, - {0x0A, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Dugtrio", - &I_dugtrio, - 0x76, - 0x23, - 0x50, - 0x32, - 0x78, - 0x46, - {0x04, 0x04}, - {0x0A, 0x2D, 0x5B, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Meowth", - &I_meowth, - 0x4D, - 0x28, - 0x2D, - 0x23, - 0x5A, - 0x28, - {0x00, 0x00}, - {0x0A, 0x2D, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Persian", - &I_persian, - 0x90, - 0x41, - 0x46, - 0x3C, - 0x73, - 0x41, - {0x00, 0x00}, - {0x0A, 0x2D, 0x2C, 0x67}, - GROWTH_MEDIUM_FAST}, - {"Psyduck", - &I_psyduck, - 0x2F, - 0x32, - 0x34, - 0x30, - 0x37, - 0x32, - {0x15, 0x15}, - {0x0A, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Golduck", - &I_golduck, - 0x80, - 0x50, - 0x52, - 0x4E, - 0x55, - 0x50, - {0x15, 0x15}, - {0x0A, 0x27, 0x32, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Mankey", - &I_mankey, - 0x39, - 0x28, - 0x50, - 0x23, - 0x46, - 0x23, - {0x01, 0x01}, - {0x0A, 0x2B, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Primeape", - &I_primeape, - 0x75, - 0x41, - 0x69, - 0x3C, - 0x5F, - 0x3C, - {0x01, 0x01}, - {0x0A, 0x2B, 0x02, 0x9A}, - GROWTH_MEDIUM_FAST}, - {"Growlithe", - &I_growlithe, - 0x21, - 0x37, - 0x46, - 0x2D, - 0x3C, - 0x32, - {0x14, 0x14}, - {0x2C, 0x2E, 0x00, 0x00}, - GROWTH_SLOW}, - {"Arcanine", - &I_arcanine, - 0x14, - 0x5A, - 0x6E, - 0x50, - 0x5F, - 0x50, - {0x14, 0x14}, - {0x2E, 0x34, 0x2B, 0x24}, - GROWTH_SLOW}, - {"Poliwag", - &I_poliwag, - 0x47, - 0x28, - 0x32, - 0x28, - 0x5A, - 0x28, - {0x15, 0x15}, - {0x91, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Poliwhirl", - &I_poliwhirl, - 0x6E, - 0x41, - 0x41, - 0x41, - 0x5A, - 0x32, - {0x15, 0x15}, - {0x91, 0x5F, 0x37, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Poliwrath", - &I_poliwrath, - 0x6F, - 0x5A, - 0x55, - 0x5F, - 0x46, - 0x46, - {0x15, 0x01}, - {0x5F, 0x37, 0x03, 0x22}, - GROWTH_MEDIUM_SLOW}, - {"Abra", - &I_abra, - 0x94, - 0x19, - 0x14, - 0x0F, - 0x5A, - 0x69, - {0x18, 0x18}, - {0x64, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Kadabra", - &I_kadabra, - 0x26, - 0x28, - 0x23, - 0x1E, - 0x69, - 0x78, - {0x18, 0x18}, - {0x64, 0x5D, 0x32, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Alakazam", - &I_alakazam, - 0x95, - 0x37, - 0x32, - 0x2D, - 0x78, - 0x87, - {0x18, 0x18}, - {0x64, 0x5D, 0x32, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Machop", - &I_machop, - 0x6A, - 0x46, - 0x50, - 0x32, - 0x23, - 0x23, - {0x01, 0x01}, - {0x02, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Machoke", - &I_machoke, - 0x29, - 0x50, - 0x64, - 0x46, - 0x2D, - 0x32, - {0x01, 0x01}, - {0x02, 0x43, 0x2B, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Machamp", - &I_machamp, - 0x7E, - 0x5A, - 0x82, - 0x50, - 0x37, - 0x41, - {0x01, 0x01}, - {0x02, 0x43, 0x2B, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Bellsprout", - &I_bellsprout, - 0xBC, - 0x32, - 0x4B, - 0x23, - 0x28, - 0x46, - {0x16, 0x03}, - {0x16, 0x4A, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Weepinbell", - &I_weepinbell, - 0xBD, - 0x41, - 0x5A, - 0x32, - 0x37, - 0x55, - {0x16, 0x03}, - {0x16, 0x4A, 0x23, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Victreebel", - &I_victreebel, - 0xBE, - 0x50, - 0x69, - 0x41, - 0x46, - 0x64, - {0x16, 0x03}, - {0x4F, 0x4E, 0x33, 0x4B}, - GROWTH_MEDIUM_SLOW}, - {"Tentacool", - &I_tentacool, - 0x18, - 0x28, - 0x28, - 0x23, - 0x46, - 0x64, - {0x15, 0x03}, - {0x33, 0x00, 0x00, 0x00}, - GROWTH_SLOW}, - {"Tentacruel", - &I_tentacruel, - 0x9B, - 0x50, - 0x46, - 0x41, - 0x64, - 0x78, - {0x15, 0x03}, - {0x33, 0x30, 0x23, 0x00}, - GROWTH_SLOW}, - {"Geodude", - &I_geodude, - 0xA9, - 0x28, - 0x50, - 0x64, - 0x14, - 0x1E, - {0x05, 0x04}, - {0x21, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Graveler", - &I_graveler, - 0x27, - 0x37, - 0x5F, - 0x73, - 0x23, - 0x2D, - {0x05, 0x04}, - {0x21, 0x6F, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Golem", - &I_golem, - 0x31, - 0x50, - 0x6E, - 0x82, - 0x2D, - 0x37, - {0x05, 0x04}, - {0x21, 0x6F, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Ponyta", - &I_ponyta, - 0xA3, - 0x32, - 0x55, - 0x37, - 0x5A, - 0x41, - {0x14, 0x14}, - {0x34, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Rapidash", - &I_rapidash, - 0xA4, - 0x41, - 0x64, - 0x46, - 0x69, - 0x50, - {0x14, 0x14}, - {0x34, 0x27, 0x17, 0x2D}, - GROWTH_MEDIUM_FAST}, - {"Slowpoke", - &I_slowpoke, - 0x25, - 0x5A, - 0x41, - 0x41, - 0x0F, - 0x28, - {0x15, 0x18}, - {0x5D, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Slowbro", - &I_slowbro, - 0x08, - 0x5F, - 0x4B, - 0x6E, - 0x1E, - 0x50, - {0x15, 0x18}, - {0x5D, 0x32, 0x1D, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Magnemite", - &I_magnemite, - 0xAD, - 0x19, - 0x23, - 0x46, - 0x2D, - 0x5F, - {0x17, 0x17}, - {0x21, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Magneton", - &I_magneton, - 0x36, - 0x32, - 0x3C, - 0x5F, - 0x46, - 0x78, - {0x17, 0x17}, - {0x21, 0x31, 0x54, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Farfetch'd", - &I_farfetchd, - 0x40, - 0x34, - 0x41, - 0x37, - 0x3C, - 0x3A, - {0x00, 0x02}, - {0x40, 0x1C, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Doduo", - &I_doduo, - 0x46, - 0x23, - 0x55, - 0x2D, - 0x4B, - 0x23, - {0x00, 0x02}, - {0x40, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Dodrio", - &I_dodrio, - 0x74, - 0x3C, - 0x6E, - 0x46, - 0x64, - 0x3C, - {0x00, 0x02}, - {0x40, 0x2D, 0x1F, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Seel", - &I_seel, - 0x3A, - 0x41, - 0x2D, - 0x37, - 0x2D, - 0x46, - {0x15, 0x15}, - {0x1D, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Dewgong", - &I_dewgong, - 0x78, - 0x5A, - 0x46, - 0x50, - 0x46, - 0x5F, - {0x15, 0x19}, - {0x1D, 0x2D, 0x3E, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Grimer", - &I_grimer, - 0x0D, - 0x50, - 0x50, - 0x32, - 0x19, - 0x28, - {0x03, 0x03}, - {0x01, 0x32, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Muk", - &I_muk, - 0x88, - 0x69, - 0x69, - 0x4B, - 0x32, - 0x41, - {0x03, 0x03}, - {0x01, 0x32, 0x8B, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Shellder", - &I_shellder, - 0x17, - 0x1E, - 0x41, - 0x64, - 0x28, - 0x2D, - {0x15, 0x15}, - {0x21, 0x6E, 0x00, 0x00}, - GROWTH_SLOW}, - {"Cloyster", - &I_cloyster, - 0x8B, - 0x32, - 0x5F, - 0xB4, - 0x46, - 0x55, - {0x15, 0x19}, - {0x6E, 0x30, 0x80, 0x3E}, - GROWTH_SLOW}, - {"Gastly", - &I_gastly, - 0x19, - 0x1E, - 0x23, - 0x1E, - 0x50, - 0x64, - {0x08, 0x03}, - {0x7A, 0x6D, 0x65, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Haunter", - &I_haunter, - 0x93, - 0x2D, - 0x32, - 0x2D, - 0x5F, - 0x73, - {0x08, 0x03}, - {0x7A, 0x6D, 0x65, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Gengar", - &I_gengar, - 0x0E, - 0x3C, - 0x41, - 0x3C, - 0x6E, - 0x82, - {0x08, 0x03}, - {0x7A, 0x6D, 0x65, 0x00}, - GROWTH_MEDIUM_SLOW}, - {"Onix", - &I_onix, - 0x22, - 0x23, - 0x2D, - 0xA0, - 0x46, - 0x1E, - {0x05, 0x04}, - {0x21, 0x67, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Drowzee", - &I_drowzee, - 0x30, - 0x3C, - 0x30, - 0x2D, - 0x2A, - 0x5A, - {0x18, 0x18}, - {0x01, 0x5F, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Hypno", - &I_hypno, - 0x81, - 0x55, - 0x49, - 0x46, - 0x43, - 0x73, - {0x18, 0x18}, - {0x01, 0x5F, 0x32, 0x5D}, - GROWTH_MEDIUM_FAST}, - {"Krabby", - &I_krabby, - 0x4E, - 0x1E, - 0x69, - 0x5A, - 0x32, - 0x19, - {0x15, 0x15}, - {0x91, 0x2B, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Kingler", - &I_kingler, - 0x8A, - 0x37, - 0x82, - 0x73, - 0x4B, - 0x32, - {0x15, 0x15}, - {0x91, 0x2B, 0x0B, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Voltorb", - &I_voltorb, - 0x06, - 0x28, - 0x1E, - 0x32, - 0x64, - 0x37, - {0x17, 0x17}, - {0x21, 0x67, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Electrode", - &I_electrode, - 0x8D, - 0x3C, - 0x32, - 0x46, - 0x8C, - 0x50, - {0x17, 0x17}, - {0x21, 0x67, 0x31, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Exeggcute", - &I_exeggcute, - 0x0C, - 0x3C, - 0x28, - 0x50, - 0x28, - 0x3C, - {0x16, 0x18}, - {0x8C, 0x5F, 0x00, 0x00}, - GROWTH_SLOW}, - {"Exeggutor", - &I_exeggutor, - 0x0A, - 0x5F, - 0x5F, - 0x55, - 0x37, - 0x7D, - {0x16, 0x18}, - {0x8C, 0x5F, 0x00, 0x00}, - GROWTH_SLOW}, - {"Cubone", - &I_cubone, - 0x11, - 0x32, - 0x32, - 0x5F, - 0x23, - 0x28, - {0x04, 0x04}, - {0x7D, 0x2D, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Marowak", - &I_marowak, - 0x91, - 0x3C, - 0x50, - 0x6E, - 0x2D, - 0x32, - {0x04, 0x04}, - {0x7D, 0x2D, 0x2B, 0x74}, - GROWTH_MEDIUM_FAST}, - {"Hitmonlee", - &I_hitmonlee, - 0x2B, - 0x32, - 0x78, - 0x35, - 0x57, - 0x23, - {0x01, 0x01}, - {0x18, 0x60, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Hitmonchan", - &I_hitmonchan, - 0x2C, - 0x32, - 0x69, - 0x4F, - 0x4C, - 0x23, - {0x01, 0x01}, - {0x04, 0x61, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Lickitung", - &I_lickitung, - 0x0B, - 0x5A, - 0x37, - 0x4B, - 0x1E, - 0x3C, - {0x00, 0x00}, - {0x23, 0x30, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Koffing", - &I_koffing, - 0x37, - 0x28, - 0x41, - 0x5F, - 0x23, - 0x3C, - {0x03, 0x03}, - {0x21, 0x7B, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Weezing", - &I_weezing, - 0x8F, - 0x41, - 0x5A, - 0x78, - 0x3C, - 0x55, - {0x03, 0x03}, - {0x21, 0x7B, 0x7C, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Rhyhorn", - &I_rhyhorn, - 0x12, - 0x50, - 0x55, - 0x5F, - 0x19, - 0x1E, - {0x04, 0x05}, - {0x1E, 0x00, 0x00, 0x00}, - GROWTH_SLOW}, - {"Rhydon", - &I_rhydon, - 0x01, - 0x69, - 0x82, - 0x78, - 0x28, - 0x2D, - {0x04, 0x05}, - {0x1E, 0x17, 0x27, 0x1F}, - GROWTH_SLOW}, - {"Chansey", - &I_chansey, - 0x28, - 0xFA, - 0x05, - 0x05, - 0x32, - 0x69, - {0x00, 0x00}, - {0x01, 0x03, 0x00, 0x00}, - GROWTH_FAST}, - {"Tangela", - &I_tangela, - 0x1E, - 0x41, - 0x37, - 0x73, - 0x3C, - 0x64, - {0x16, 0x16}, - {0x84, 0x14, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Kangaskhan", - &I_kangaskhan, - 0x02, - 0x69, - 0x5F, - 0x50, - 0x5A, - 0x28, - {0x00, 0x00}, - {0x04, 0x63, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Horsea", - &I_horsea, - 0x5C, - 0x1E, - 0x28, - 0x46, - 0x3C, - 0x46, - {0x15, 0x15}, - {0x91, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Seadra", - &I_seadra, - 0x5D, - 0x37, - 0x41, - 0x5F, - 0x55, - 0x5F, - {0x15, 0x15}, - {0x91, 0x6C, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Goldeen", - &I_goldeen, - 0x9D, - 0x2D, - 0x43, - 0x3C, - 0x3F, - 0x32, - {0x15, 0x15}, - {0x40, 0x27, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Seaking", - &I_seaking, - 0x9E, - 0x50, - 0x5C, - 0x41, - 0x44, - 0x50, - {0x15, 0x15}, - {0x40, 0x27, 0x30, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Staryu", - &I_staryu, - 0x1B, - 0x1E, - 0x2D, - 0x37, - 0x55, - 0x46, - {0x15, 0x15}, - {0x21, 0x00, 0x00, 0x00}, - GROWTH_SLOW}, - {"Starmie", - &I_starmie, - 0x98, - 0x3C, - 0x4B, - 0x55, - 0x73, - 0x64, - {0x15, 0x18}, - {0x21, 0x37, 0x6A, 0x00}, - GROWTH_SLOW}, - {"Mr.Mime", - &I_mr_mime, - 0x2A, - 0x28, - 0x2D, - 0x41, - 0x5A, - 0x64, - {0x18, 0x18}, - {0x5D, 0x70, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Scyther", - &I_scyther, - 0x1A, - 0x46, - 0x6E, - 0x50, - 0x69, - 0x37, - {0x07, 0x02}, - {0x62, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Jynx", - &I_jynx, - 0x48, - 0x41, - 0x32, - 0x23, - 0x5F, - 0x5F, - {0x19, 0x18}, - {0x01, 0x8E, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Electabuzz", - &I_electabuzz, - 0x35, - 0x41, - 0x53, - 0x39, - 0x69, - 0x55, - {0x17, 0x17}, - {0x62, 0x2B, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Magmar", - &I_magmar, - 0x33, - 0x41, - 0x5F, - 0x39, - 0x5D, - 0x55, - {0x14, 0x14}, - {0x34, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Pinsir", - &I_pinsir, - 0x1D, - 0x41, - 0x7D, - 0x64, - 0x55, - 0x37, - {0x07, 0x07}, - {0x0B, 0x00, 0x00, 0x00}, - GROWTH_SLOW}, - {"Tauros", - &I_tauros, - 0x3C, - 0x4B, - 0x64, - 0x5F, - 0x6E, - 0x46, - {0x00, 0x00}, - {0x21, 0x00, 0x00, 0x00}, - GROWTH_SLOW}, - {"Magikarp", - &I_magikarp, - 0x85, - 0x14, - 0x0A, - 0x37, - 0x50, - 0x14, - {0x15, 0x15}, - {0x96, 0x00, 0x00, 0x00}, - GROWTH_SLOW}, - {"Gyarados", - &I_gyarados, - 0x16, - 0x5F, - 0x7D, - 0x4F, - 0x51, - 0x64, - {0x15, 0x02}, - {0x2C, 0x52, 0x2B, 0x38}, - GROWTH_SLOW}, - {"Lapras", - &I_lapras, - 0x13, - 0x82, - 0x55, - 0x50, - 0x3C, - 0x5F, - {0x15, 0x19}, - {0x37, 0x2D, 0x00, 0x00}, - GROWTH_SLOW}, - {"Ditto", - &I_ditto, - 0x4C, - 0x30, - 0x30, - 0x30, - 0x30, - 0x30, - {0x00, 0x00}, - {0x90, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Eevee", - &I_eevee, - 0x66, - 0x37, - 0x37, - 0x32, - 0x37, - 0x41, - {0x00, 0x00}, - {0x21, 0x1C, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Vaporeon", - &I_vaporeon, - 0x69, - 0x82, - 0x41, - 0x3C, - 0x41, - 0x6E, - {0x15, 0x15}, - {0x21, 0x1C, 0x62, 0x37}, - GROWTH_MEDIUM_FAST}, - {"Jolteon", - &I_jolteon, - 0x68, - 0x41, - 0x41, - 0x3C, - 0x82, - 0x6E, - {0x17, 0x17}, - {0x21, 0x1C, 0x62, 0x54}, - GROWTH_MEDIUM_FAST}, - {"Flareon", - &I_flareon, - 0x67, - 0x41, - 0x82, - 0x3C, - 0x41, - 0x6E, - {0x14, 0x14}, - {0x21, 0x1C, 0x62, 0x34}, - GROWTH_MEDIUM_FAST}, - {"Porygon", - &I_porygon, - 0xAA, - 0x41, - 0x3C, - 0x46, - 0x28, - 0x4B, - {0x00, 0x00}, - {0x21, 0x9F, 0xA0, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Omanyte", - &I_omanyte, - 0x62, - 0x23, - 0x28, - 0x64, - 0x23, - 0x5A, - {0x05, 0x15}, - {0x37, 0x6E, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Omastar", - &I_omastar, - 0x63, - 0x46, - 0x3C, - 0x7D, - 0x37, - 0x73, - {0x05, 0x15}, - {0x37, 0x6E, 0x1E, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Kabuto", - &I_kabuto, - 0x5A, - 0x1E, - 0x50, - 0x5A, - 0x37, - 0x2D, - {0x05, 0x15}, - {0x0A, 0x6A, 0x00, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Kabutops", - &I_kabutops, - 0x5B, - 0x3C, - 0x73, - 0x69, - 0x50, - 0x46, - {0x05, 0x15}, - {0x0A, 0x6A, 0x47, 0x00}, - GROWTH_MEDIUM_FAST}, - {"Aerodactyl", - &I_aerodactyl, - 0xAB, - 0x50, - 0x69, - 0x41, - 0x82, - 0x3C, - {0x05, 0x02}, - {0x11, 0x61, 0x00, 0x00}, - GROWTH_SLOW}, - {"Snorlax", - &I_snorlax, - 0x84, - 0xA0, - 0x6E, - 0x41, - 0x1E, - 0x41, - {0x00, 0x00}, - {0x1D, 0x85, 0x9C, 0x00}, - GROWTH_SLOW}, - {"Articuno", - &I_articuno, - 0x4A, - 0x5A, - 0x55, - 0x64, - 0x55, - 0x7D, - {0x19, 0x02}, - {0x40, 0x3A, 0x00, 0x00}, - GROWTH_SLOW}, - {"Zapdos", - &I_zapdos, - 0x4B, - 0x5A, - 0x5A, - 0x55, - 0x64, - 0x7D, - {0x17, 0x02}, - {0x54, 0x41, 0x00, 0x00}, - GROWTH_SLOW}, - {"Moltres", - &I_moltres, - 0x49, - 0x5A, - 0x64, - 0x5A, - 0x5A, - 0x7D, - {0x14, 0x02}, - {0x40, 0x53, 0x00, 0x00}, - GROWTH_SLOW}, - {"Dratini", - &I_dratini, - 0x58, - 0x29, - 0x40, - 0x2D, - 0x32, - 0x32, - {0x1A, 0x1A}, - {0x23, 0x2B, 0x00, 0x00}, - GROWTH_SLOW}, - {"Dragonair", - &I_dragonair, - 0x59, - 0x3D, - 0x54, - 0x41, - 0x46, - 0x46, - {0x1A, 0x1A}, - {0x23, 0x2B, 0x56, 0x00}, - GROWTH_SLOW}, - {"Dragonite", - &I_dragonite, - 0x42, - 0x5B, - 0x86, - 0x5F, - 0x50, - 0x64, - {0x1A, 0x02}, - {0x23, 0x2B, 0x56, 0x61}, - GROWTH_SLOW}, - {"Mewtwo", - &I_mewtwo, - 0x83, - 0x6A, - 0x6E, - 0x5A, - 0x82, - 0x9A, - {0x18, 0x18}, - {0x5D, 0x32, 0x81, 0x5E}, - GROWTH_SLOW}, - {"Mew", - &I_mew, - 0x15, - 0x64, - 0x64, - 0x64, - 0x64, - 0x64, - {0x18, 0x18}, - {0x01, 0x00, 0x00, 0x00}, - GROWTH_MEDIUM_SLOW}, - {}, -}; - -const NamedList move_list[] = { - {"No Move", 0x00}, - {"Absorb", 0x47}, - {"Acid Armor", 0x97}, - {"Acid", 0x33}, - {"Agility", 0x61}, - {"Amnesia", 0x85}, - {"Aurora Beam", 0x3E}, - {"Barrage", 0x8C}, - {"Barrier", 0x70}, - {"Bide", 0x75}, - {"Bind", 0x14}, - {"Bite", 0x2C}, - {"Blizzard", 0x3B}, - {"Body Slam", 0x22}, - {"Bone Club", 0x7D}, - {"Boomerang", 0x9B}, - {"Bubblebeam", 0x3D}, - {"Bubble", 0x91}, - {"Clamp", 0x80}, - {"Comet Punch", 0x04}, - {"Confuse Ray", 0x6D}, - {"Confusion", 0x5D}, - {"Constrict", 0x84}, - {"Conversion", 0xA0}, - {"Counter", 0x44}, - {"Crabhammer", 0x98}, - {"Cut", 0x0F}, - {"Defense Curl", 0x6F}, - {"Dig", 0x5B}, - {"Disable", 0x32}, - {"Dizzy Punch", 0x92}, - {"Doubleslap", 0x03}, - {"Double Kick", 0x18}, - {"Double Team", 0x68}, - {"Double-Edge", 0x26}, - {"Dragon Rage", 0x52}, - {"Dream Eater", 0x8A}, - {"Drill Peck", 0x41}, - {"Earthquake", 0x59}, - {"Egg Bomb", 0x79}, - {"Ember", 0x34}, - {"Explosion", 0x99}, - {"Fire Blast", 0x7E}, - {"Fire Punch", 0x07}, - {"Fire Spin", 0x53}, - {"Fissure", 0x5A}, - {"Flamethrower", 0x35}, - {"Flash", 0x94}, - {"Fly", 0x13}, - {"Focus Energy", 0x74}, - {"Fury Attack", 0x1F}, - {"Fury Swipes", 0x9A}, - {"Glare", 0x89}, - {"Growl", 0x2D}, - {"Growth", 0x4A}, - {"Guillotine", 0x0C}, - {"Gust", 0x10}, - {"Harden", 0x6A}, - {"Haze", 0x72}, - {"Headbutt", 0x1D}, - {"Hi Jump Kick", 0x88}, - {"Horn Attack", 0x1E}, - {"Horn Drill", 0x20}, - {"Hydro Pump", 0x38}, - {"Hyper Beam", 0x3F}, - {"Hyper Fang", 0x9E}, - {"Hypnosis", 0x5F}, - {"Ice Beam", 0x3A}, - {"Ice Punch", 0x08}, - {"Jump Kick", 0x1A}, - {"Karate Chop", 0x02}, - {"Kinesis", 0x86}, - {"Leech Life", 0x8D}, - {"Leech Seed", 0x49}, - {"Leer", 0x2B}, - {"Lick", 0x7A}, - {"Light Screen", 0x71}, - {"Lovely Kiss", 0x8E}, - {"Low Kick", 0x43}, - {"Meditate", 0x60}, - {"Mega Drain", 0x48}, - {"Mega Kick", 0x19}, - {"Mega Punch", 0x05}, - {"Metronome", 0x76}, - {"Mimic", 0x66}, - {"Minimize", 0x6B}, - {"Mirror Move", 0x77}, - {"Mist", 0x36}, - {"Night Shade", 0x65}, - {"Pay Day", 0x06}, - {"Peck", 0x40}, - {"Petal Dance", 0x50}, - {"Pin Missile", 0x2A}, - {"Poisonpowder", 0x4D}, - {"Poison Gas", 0x8B}, - {"Poison Sting", 0x28}, - {"Pound", 0x01}, - {"Psybeam", 0x3C}, - {"Psychic", 0x5E}, - {"Psywave", 0x95}, - {"Quick Attack", 0x62}, - {"Rage", 0x63}, - {"Razor Leaf", 0x4B}, - {"Razor Wind", 0x0D}, - {"Recover", 0x69}, - {"Reflect", 0x73}, - {"Rest", 0x9C}, - {"Roar", 0x2E}, - {"Rock Slide", 0x9D}, - {"Rock Throw", 0x58}, - {"Rolling Kick", 0x1B}, - {"Sand Attack", 0x1C}, - {"Scratch", 0x0A}, - {"Screech", 0x67}, - {"Seismic Toss", 0x45}, - {"Selfdestruct", 0x78}, - {"Sharpen", 0x9F}, - {"Sing", 0x2F}, - {"Skull Bash", 0x82}, - {"Sky Attack", 0x8F}, - {"Slam", 0x15}, - {"Slash", 0xA3}, - {"Sleep Powder", 0x4F}, - {"Sludge", 0x7C}, - {"Smog", 0x7B}, - {"Smokescreen", 0x6C}, - {"Softboiled", 0x87}, - {"Solar Beam", 0x4C}, - {"Sonicboom", 0x31}, - {"Spike Cannon", 0x83}, - {"Splash", 0x96}, - {"Spore", 0x93}, - {"Stomp", 0x17}, - {"Strength", 0x46}, - {"String Shot", 0x51}, - {"Struggle", 0xA5}, - {"Stun Spore", 0x4E}, - {"Submission", 0x42}, - {"Substitute", 0xA4}, - {"Supersonic", 0x30}, - {"Super Fang", 0xA2}, - {"Surf", 0x39}, - {"Swift", 0x81}, - {"Swords Dance", 0x0E}, - {"Tackle", 0x21}, - {"Tail Whip", 0x27}, - {"Take Down", 0x24}, - {"Teleport", 0x64}, - {"Thrash", 0x25}, - {"Thunderbolt", 0x55}, - {"Thunderpunch", 0x09}, - {"Thundershock", 0x54}, - {"Thunder Wave", 0x56}, - {"Thunder", 0x57}, - {"Toxic", 0x5C}, - {"Transform", 0x90}, - {"Tri Attack", 0xA1}, - {"Twineedle", 0x29}, - {"Vicegrip", 0x0B}, - {"Vine Whip", 0x16}, - {"Waterfall", 0x7F}, - {"Water Gun", 0x37}, - {"Whirlwind", 0x12}, - {"Wing Attack", 0x11}, - {"Withdraw", 0x6E}, - {"Wrap", 0x23}, - {}, -}; - -const NamedList type_list[] = { - {"Bug", 0x07}, - {"Dragon", 0x1A}, - {"Electric", 0x17}, - {"Fighting", 0x01}, - {"Fire", 0x14}, - {"Flying", 0x02}, - {"Ghost", 0x08}, - {"Grass", 0x16}, - {"Ground", 0x04}, - {"Ice", 0x19}, - {"Normal", 0x00}, - {"Poison", 0x03}, - {"Psychic", 0x18}, - {"Rock", 0x05}, - {"Water", 0x15}, - {}, -}; - -int pokemon_table_get_num_from_index(const PokemonTable* table, uint8_t index) { - int i; - - for(i = 0;; i++) { - if(table[i].index == index) return i; - if(table[i].name == NULL) break; - } - - return 0; -} - -int pokemon_named_list_get_num_elements(const NamedList* list) { - int i; - - for(i = 0;; i++) { - if(list[i].name == NULL) return i; - } -} - -int pokemon_named_list_get_list_pos_from_index(const NamedList* list, uint8_t index) { - int i; - - for(i = 0;; i++) { - if(list[i].name == NULL) break; - if(index == list[i].index) return i; - } - - /* This will return the first entry in case index is not matched. - * Could be surprising at runtime. - */ - return 0; -} - -const char* pokemon_named_list_get_name_from_index(const NamedList* list, uint8_t index) { - int i; - - for(i = 0;; i++) { - if(list[i].name == NULL) break; - if(index == list[i].index) return list[i].name; - } - - /* This will return the first entry in the case index is not matched, - * this could be confusing/problematic at runtime. - */ - return list[0].name; -} - -/* If dest is not NULL, a copy of the default name is written to it as well */ -void pokemon_trade_block_set_default_name(char* dest, PokemonFap* pokemon_fap, size_t n) { - int i; - char buf[11]; - - /* Walk through the default name, toupper() each character, encode it, and - * then write that to the same position in the trade_block. - */ - for(i = 0; i < 11; i++) { - pokemon_fap->trade_block->nickname[0].str[i] = pokemon_char_to_encoded( - toupper(pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].name[i])); - buf[i] = toupper(pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].name[i]); - } - FURI_LOG_D(TAG, "[app] Set default nickname"); - - if(dest != NULL) { - strncpy(dest, buf, n); - } -} - -#define UINT32_TO_EXP(input, output_array) \ - do { \ - (output_array)[2] = (uint8_t)((input)&0xFF); \ - (output_array)[1] = (uint8_t)(((input) >> 8) & 0xFF); \ - (output_array)[0] = (uint8_t)(((input) >> 16) & 0xFF); \ - } while(0) - -void pokemon_trade_block_recalculate_stats_from_level(PokemonFap* pokemon_fap) { - struct pokemon_structure* pkmn = &pokemon_fap->trade_block->party[0]; - const PokemonTable* table = &pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon]; - int curr_stats = pokemon_fap->curr_stats; - uint32_t experience; - int level = pkmn->level; - uint16_t stat; - uint8_t hp_iv = 0xf; - uint8_t atk_iv = 0xf; - uint8_t def_iv = 0xf; - uint8_t spd_iv = 0xf; - uint8_t special_iv = 0xf; - - /* Calculate exp */ - switch(table->growth) { - case GROWTH_FAST: - // https://bulbapedia.bulbagarden.net/wiki/Experience#Fast - experience = (4 * level * level * level) / 5; - break; - case GROWTH_MEDIUM_FAST: - // https://bulbapedia.bulbagarden.net/wiki/Experience#Medium_Fast - experience = (level * level * level); - break; - case GROWTH_MEDIUM_SLOW: - // https://bulbapedia.bulbagarden.net/wiki/Experience#Medium_Slow - experience = - (((level * level * level) * 6 / 5) - (15 * level * level) + (100 * level) - 140); - break; - case GROWTH_SLOW: - // https://bulbapedia.bulbagarden.net/wiki/Experience#Slow - experience = (5 * level * level * level) / 4; - break; - default: - furi_crash("incorrect growth val"); - break; - } - - pkmn->level_again = level; - UINT32_TO_EXP(experience, pkmn->exp); - FURI_LOG_D(TAG, "[app] Set pkmn level %d", level); - FURI_LOG_D(TAG, "[app] Set pkmn exp %d", (int)experience); - - /* Generate STATEXP */ - switch(curr_stats) { - case 1: - case 4: - stat = (0xffff / 100) * level; - break; - case 2: - case 5: - stat = 0xffff; - break; - default: - stat = 0; - break; - } - - FURI_LOG_D(TAG, "[app] EVs set to %d", stat); - stat = __builtin_bswap16(stat); - - pkmn->hp_ev = stat; - pkmn->atk_ev = stat; - pkmn->def_ev = stat; - pkmn->spd_ev = stat; - pkmn->special_ev = stat; - - /* Set up IVs */ - if(curr_stats <= 2) { - atk_iv = rand() % 15; - def_iv = rand() % 15; - spd_iv = rand() % 15; - special_iv = rand() % 15; - pkmn->iv = ((atk_iv & 0x0f) << 12) | ((def_iv & 0x0f) << 8) | ((spd_iv & 0x0f) << 4) | - ((special_iv & 0x0f)); - hp_iv = (pkmn->iv & 0xAA) >> 4; - } - FURI_LOG_D( - TAG, - "[app] atk_iv %d, def_iv %d, spd_iv %d, spc_iv %d, hp_iv %d", - atk_iv, - def_iv, - spd_iv, - special_iv, - hp_iv); - - /* Calculate HP */ - // https://bulbapedia.bulbagarden.net/wiki/Stat#Generations_I_and_II - stat = floor((((2 * (table->base_hp + hp_iv)) + floor(sqrt(pkmn->hp_ev) / 4)) * level) / 100) + - (level + 10); - FURI_LOG_D(TAG, "[app] HP set to %d", stat); - pkmn->hp = __builtin_bswap16(stat); - pkmn->max_hp = pkmn->hp; - - /* Calculate ATK, DEF, SPD, SP */ - /* TODO: these all use the same calculations, could put the stats in a sub-array and iterate - * through each element in order rather than having to repeat the code. IVs would also need - * to be in a similar array. - **/ - // https://bulbapedia.bulbagarden.net/wiki/Stat#Generations_I_and_II - stat = - floor((((2 * (table->base_atk + atk_iv)) + floor(sqrt(pkmn->atk_ev) / 4)) * level) / 100) + - 5; - FURI_LOG_D(TAG, "[app] ATK set to %d", stat); - pkmn->atk = __builtin_bswap16(stat); - stat = - floor((((2 * (table->base_def + def_iv)) + floor(sqrt(pkmn->def_ev) / 4)) * level) / 100) + - 5; - FURI_LOG_D(TAG, "[app] DEF set to %d", stat); - pkmn->def = __builtin_bswap16(stat); - stat = - floor((((2 * (table->base_spd + spd_iv)) + floor(sqrt(pkmn->spd_ev) / 4)) * level) / 100) + - 5; - FURI_LOG_D(TAG, "[app] SPD set to %d", stat); - pkmn->spd = __builtin_bswap16(stat); - stat = floor( - (((2 * (table->base_special + special_iv)) + floor(sqrt(pkmn->special_ev) / 4)) * - level) / - 100) + - 5; - FURI_LOG_D(TAG, "[app] SPC set to %d", stat); - pkmn->special = __builtin_bswap16(stat); -} - -/* Rebuild the current trade block's variables based on curr_pokemon */ -void pokemon_trade_block_recalculate(PokemonFap* pokemon_fap) { - struct pokemon_structure* pkmn = &pokemon_fap->trade_block->party[0]; - const PokemonTable* table = &pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon]; - int i; - - /* Set current pokemon to the trade structure */ - pkmn->index = table->index; - pokemon_fap->trade_block->party_members[0] = table->index; - FURI_LOG_D(TAG, "[app] Set %s in trade block", table->name); - - /* Set current pokemon's moves to the trade structure */ - for(i = 0; i < 4; i++) { - pkmn->move[i] = table->move[i]; - FURI_LOG_D( - TAG, - "[app] Set %s in trade block", - pokemon_named_list_get_name_from_index(pokemon_fap->move_list, pkmn->move[i])); - } - - /* Set current pokemon's types to the trade structure */ - for(i = 0; i < 2; i++) { - pkmn->type[i] = table->type[i]; - FURI_LOG_D( - TAG, - "[app] Set %s in trade block", - pokemon_named_list_get_name_from_index(pokemon_fap->type_list, pkmn->type[i])); - } - - pokemon_trade_block_recalculate_stats_from_level(pokemon_fap); - pokemon_trade_block_set_default_name(NULL, pokemon_fap, 0); -} - -/* Allocates a chunk of memory for the trade data block and sets up some - * default values. - */ -static TradeBlock* trade_block_alloc(void) { - TradeBlock* trade; - - trade = malloc(sizeof(TradeBlock)); - - /* Clear struct to be all TERM_ bytes as the various name strings need this */ - memset(trade, TERM_, sizeof(TradeBlock)); - - /* The party_members element needs to be 0xff for unused */ - memset(trade->party_members, 0xFF, sizeof(trade->party_members)); - - /* Zero the main party data, TERM_ in there can cause weirdness */ - memset(trade->party, 0x00, sizeof(trade->party)); - - /* Set our Name, the pokemon's default OT name and ID */ - trade->party_cnt = 1; - - /* Trainer/OT name, not to exceed 7 characters! */ - pokemon_str_to_encoded_array(trade->trainer_name, "Flipper", sizeof(trade->trainer_name)); - pokemon_str_to_encoded_array(trade->ot_name[0].str, "Flipper", sizeof(trade->ot_name[0].str)); - - /* OT trainer ID# */ - trade->party[0].ot_id = __builtin_bswap16(42069); - - /* Notes: - * Move pp isn't explicitly set up, should be fine - * Catch/held isn't explicitly set up, should be okay for only Gen I support now - * Status condition isn't explicity let up, would you ever want to? - */ - - /* Set up initial level */ - trade->party[0].level = 2; - - return trade; -} - -static void trade_block_free(TradeBlock* trade) { - free(trade); -} - -/* The MALVEKE board has an esp32 which is set to TX on the flipper's default - * UART pins. If this pin shows signs of something connected, assume a MALVEKE - * board is being used. - */ -static bool detect_malveke(void) { - bool rc; - - furi_hal_gpio_init(&gpio_usart_rx, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); - rc = furi_hal_gpio_read(&gpio_usart_rx); - furi_hal_gpio_init_simple(&gpio_usart_rx, GpioModeAnalog); - - return rc; -} - PokemonFap* pokemon_alloc() { PokemonFap* pokemon_fap = (PokemonFap*)malloc(sizeof(PokemonFap)); @@ -2163,34 +21,23 @@ PokemonFap* pokemon_alloc() { (Gui*)furi_record_open(RECORD_GUI), ViewDispatcherTypeFullscreen); - /* Set up pointers to const data tables for reference elsewhere */ - pokemon_fap->pokemon_table = pokemon_table; - pokemon_fap->move_list = move_list; - pokemon_fap->type_list = type_list; - // Set up defaults - pokemon_fap->curr_pokemon = 0; - pokemon_fap->curr_stats = 0; - pokemon_fap->malveke_detected = detect_malveke(); - memcpy( - &pokemon_fap->pins, - &common_pinouts[pokemon_fap->malveke_detected], - sizeof(struct gblink_pins)); - - // Set up trade party struct - pokemon_fap->trade_block = trade_block_alloc(); - - /* Update trade block struct with calculated details from initial values from trade_block_alloc() */ - pokemon_trade_block_recalculate(pokemon_fap); + memcpy(&pokemon_fap->pins, &common_pinouts[PINOUT_ORIGINAL], sizeof(struct gblink_pins)); /* Set up gui modules used. It would be nice if these could be allocated and * freed as needed, however, the scene manager still requires pointers that * get set up as a part of the scene. Therefore, individual scene's exit * callbacks cannot free the buffer. + * + * In order to do this properly, I think each scene, or maybe common to all + * scenes, would end up needing to set a delayed callback of some kind. But + * I'm not sure how to guarantee this gets called in a reasonable amount of + * time. */ pokemon_fap->text_input = text_input_alloc(); pokemon_fap->submenu = submenu_alloc(); pokemon_fap->variable_item_list = variable_item_list_alloc(); + pokemon_fap->dialog_ex = dialog_ex_alloc(); // Set up menu scene pokemon_fap->scene_manager = scene_manager_alloc(&pokemon_scene_manager_handlers, pokemon_fap); @@ -2198,33 +45,12 @@ PokemonFap* pokemon_alloc() { pokemon_fap->view_dispatcher, AppViewMainMenu, submenu_get_view(pokemon_fap->submenu)); scene_manager_next_scene(pokemon_fap->scene_manager, MainMenuScene); - // Select Pokemon View - pokemon_fap->select_view = select_pokemon_alloc(pokemon_fap); - view_dispatcher_add_view( - pokemon_fap->view_dispatcher, AppViewSelectPokemon, pokemon_fap->select_view); - - // Trade View - /* Allocates its own view and adds it to the main view_dispatcher */ - pokemon_fap->trade = trade_alloc( - pokemon_fap->trade_block, - pokemon_fap->pokemon_table, - &pokemon_fap->pins, - pokemon_fap->view_dispatcher, - AppViewTrade); - return pokemon_fap; } void free_app(PokemonFap* pokemon_fap) { furi_assert(pokemon_fap); - // Free views - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewSelectPokemon); - select_pokemon_free(pokemon_fap); - - /* Also removes itself from the view_dispatcher */ - trade_free(pokemon_fap->view_dispatcher, AppViewTrade, pokemon_fap->trade); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewMainMenu); view_dispatcher_free(pokemon_fap->view_dispatcher); @@ -2236,13 +62,11 @@ void free_app(PokemonFap* pokemon_fap) { submenu_free(pokemon_fap->submenu); text_input_free(pokemon_fap->text_input); variable_item_list_free(pokemon_fap->variable_item_list); + dialog_ex_free(pokemon_fap->dialog_ex); // Close records furi_record_close(RECORD_GUI); - // Free trade block - trade_block_free(pokemon_fap->trade_block); - // Free rest free(pokemon_fap); pokemon_fap = NULL; diff --git a/pokemon_app.h b/pokemon_app.h index b3795a3eb70..e29d92b5ae0 100644 --- a/pokemon_app.h +++ b/pokemon_app.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,78 +17,26 @@ #define TAG "Pokemon" -/* #defines for the data table entries */ -#define GROWTH_FAST 4 -#define GROWTH_MEDIUM_FAST 0 -#define GROWTH_MEDIUM_SLOW 3 -#define GROWTH_SLOW 5 - -struct pokemon_data_table { - const char* name; - const Icon* icon; - const uint8_t index; - const uint8_t base_hp; - const uint8_t base_atk; - const uint8_t base_def; - const uint8_t base_spd; - const uint8_t base_special; - const uint8_t type[2]; - const uint8_t move[4]; - const uint8_t growth; -}; - -typedef struct pokemon_data_table PokemonTable; - -struct named_list { - const char* name; - const uint8_t index; -}; - -typedef struct named_list NamedList; - struct pokemon_fap { + /* Various anonymous pointers for flipper UI/navigation */ ViewDispatcher* view_dispatcher; - - /* View ports for each of the application's steps */ - View* select_view; - void* trade; - - /* Scene manager */ SceneManager* scene_manager; - - /* gui modules used in the application lifetime */ + void* select; + void* trade; Submenu* submenu; TextInput* text_input; VariableItemList* variable_item_list; - - /* Table of pokemon data for Gen I */ - const PokemonTable* pokemon_table; - - /* List of moves, alphabetically ordered */ - const NamedList* move_list; - - /* List of types, alphabetically ordered */ - const NamedList* type_list; + DialogEx* dialog_ex; /* Struct for holding trade data */ /* NOTE: There may be some runtime memory savings by adding more intelligence * to views/trade and slimming down this struct to only contain the single * pokemon data rather than the full 6 member party data. */ - TradeBlock* trade_block; + PokemonData* pdata; /* Pin definition to actual Game Link Cable interface */ struct gblink_pins pins; - int malveke_detected; - - /* The currently selected pokemon */ - int curr_pokemon; - - /* TODO: Other variables will end up here, like selected level, EV/IV, - * moveset, etc. Likely will want to be another sub struct similar to - * the actual pokemon data structure. - */ - int curr_stats; }; typedef struct pokemon_fap PokemonFap; @@ -100,18 +49,4 @@ typedef enum { AppViewExitConfirm, } AppView; -int pokemon_table_get_num_from_index(const PokemonTable* table, uint8_t index); - -int pokemon_named_list_get_num_elements(const NamedList* list); - -int pokemon_named_list_get_list_pos_from_index(const NamedList* list, uint8_t index); - -const char* pokemon_named_list_get_name_from_index(const NamedList* list, uint8_t index); - -void pokemon_trade_block_set_default_name(char* dest, PokemonFap* pokemon_fap, size_t n); - -void pokemon_trade_block_recalculate(PokemonFap* pokemon_fap); - -void pokemon_trade_block_recalculate_stats_from_level(PokemonFap* pokemon_fap); - #endif /* POKEMON_APP_H */ diff --git a/pokemon_char_encode.c b/pokemon_char_encode.c index 14351eae7dc..40b7f8551df 100644 --- a/pokemon_char_encode.c +++ b/pokemon_char_encode.c @@ -109,6 +109,8 @@ char pokemon_char_to_encoded(int byte) { return y_; case 'z': return z_; + case '-': + return HYPHEN_; case '0': return _0_; case '1': @@ -255,6 +257,8 @@ int pokemon_encoded_to_char(char byte) { return 'y'; case z_: return 'z'; + case HYPHEN_: + return '-'; case _0_: return '0'; case _1_: diff --git a/pokemon_char_encode.h b/pokemon_char_encode.h index 08e33adeaa7..d6f7eb4cfb4 100644 --- a/pokemon_char_encode.h +++ b/pokemon_char_encode.h @@ -87,6 +87,7 @@ #define D_ARR_ 0xee #define MALE_ 0xef #define FEMALE_ 0xf5 +#define HYPHEN_ 0xe3 #define _0_ 0xf6 #define _1_ 0xf7 #define _2_ 0xf8 diff --git a/pokemon_data.c b/pokemon_data.c new file mode 100644 index 00000000000..8e71977c43b --- /dev/null +++ b/pokemon_data.c @@ -0,0 +1,914 @@ +#include + +#include + +#include "pokemon_data.h" +#include "pokemon_data_i.h" +#include "pokemon_app.h" +#include "pokemon_char_encode.h" + +#include "pokemon_table.h" + +#include +#include +#include +#include +#include + +#include + +#define RECALC_NONE 0x00 +#define RECALC_EXP 0x01 +#define RECALC_EVS 0x02 +#define RECALC_IVS 0x04 +#define RECALC_STATS 0x08 +#define RECALC_NICKNAME 0x10 +#define RECALC_MOVES 0x20 +#define RECALC_TYPES 0x40 +#define RECALC_ALL 0xFF + +#define FXBM_SPRITE_SIZE 404 // Each 56x56 sprite + +/* Text lookups to make debug output cleaner and easier to parse as a human */ +static char* stat_text_get(DataStat stat) { + switch(stat) { + case STAT_ATK: + return "ATK"; + case STAT_DEF: + return "DEF"; + case STAT_SPD: + return "SPD"; + case STAT_SPC: + return "SPC"; + case STAT_SPC_ATK: + return "SPC_ATK"; + case STAT_SPC_DEF: + return "SPC_DEF"; + case STAT_HP: + return "HP"; + case STAT_TYPE: + return "Type"; + case STAT_MOVE: + return "Move"; + case STAT_ATK_EV: + return "ATK_EV"; + case STAT_DEF_EV: + return "DEF_EV"; + case STAT_SPD_EV: + return "SPD_EV"; + case STAT_SPC_ATK_EV: + case STAT_SPC_DEF_EV: + case STAT_SPC_EV: + return "SPC_EV"; + case STAT_HP_EV: + return "HP_EV"; + case STAT_IV: + return "IV"; + case STAT_ATK_IV: + return "ATK_IV"; + case STAT_DEF_IV: + return "DEF_IV"; + case STAT_SPD_IV: + return "SPD_IV"; + case STAT_SPC_ATK_IV: + case STAT_SPC_DEF_IV: + case STAT_SPC_IV: + return "SPC_IV"; + case STAT_HP_IV: + return "HP_IV"; + case STAT_LEVEL: + return "Lvl."; + case STAT_INDEX: + return "Idx."; + case STAT_NUM: + return "Num."; + case STAT_CONDITION: + return "Cond."; + case STAT_NICKNAME: + return "Nick."; + case STAT_OT_NAME: + return "OT Name"; + case STAT_OT_ID: + return "OT ID"; + case STAT_TRAINER_NAME: + return "Trainer Name"; + case STAT_SEL: + return "EV/IV Sel."; // which EV/IV calc to use + case STAT_EXP: + return "Exp."; + case STAT_HELD_ITEM: + return "Held Item"; + case STAT_POKERUS: + return "Pokerus"; + default: + return "UNKNOWN STAT"; + } +} + +/* Allocates a chunk of memory for the trade data block and sets up some + * default values. + */ +PokemonData* pokemon_data_alloc(uint8_t gen) { + PokemonData* pdata; + + pdata = malloc(sizeof(PokemonData)); + pdata->gen = gen; + + /* Set up lists */ + pdata->move_list = move_list; + pdata->type_list = type_list; + pdata->stat_list = stat_list; + pdata->item_list = item_list; + pdata->pokemon_table = table_pointer_get(); + + pdata->storage = furi_record_open(RECORD_STORAGE); + pdata->asset_path = furi_string_alloc_set(APP_ASSETS_PATH()); + storage_common_resolve_path_and_ensure_app_directory(pdata->storage, pdata->asset_path); + + switch(gen) { + case GEN_I: + /* Allocate trade block and set its size for the trade view to use */ + pdata->trade_block_sz = sizeof(TradeBlockGenI); + pdata->party_sz = sizeof(PokemonPartyGenI) * 6; + pdata->trade_block = malloc(pdata->trade_block_sz); + + /* The party_members element needs to be 0xff for unused */ + memset( + ((TradeBlockGenI*)pdata->trade_block)->party_members, + 0xFF, + sizeof(((TradeBlockGenI*)pdata->trade_block)->party_members)); + + pdata->party = ((TradeBlockGenI*)pdata->trade_block)->party; + + /* Set party count to 1 */ + ((TradeBlockGenI*)pdata->trade_block)->party_cnt = 1; + + /* Set the max pokedex number, 0 indexed */ + pdata->dex_max = 150; + break; + case GEN_II: + /* Allocate trade block and set its size for the trade view to use */ + pdata->trade_block_sz = sizeof(TradeBlockGenII); + pdata->party_sz = sizeof(PokemonPartyGenII) * 6; + pdata->trade_block = malloc(pdata->trade_block_sz); + + /* The party_members element needs to be 0xff for unused */ + memset( + ((TradeBlockGenII*)pdata->trade_block)->party_members, + 0xFF, + sizeof(((TradeBlockGenII*)pdata->trade_block)->party_members)); + + pdata->party = ((TradeBlockGenII*)pdata->trade_block)->party; + + /* Set party count to 1 */ + ((TradeBlockGenII*)pdata->trade_block)->party_cnt = 1; + + /* Set the max pokedex number, 0 indexed */ + pdata->dex_max = 250; + break; + default: + furi_crash("Invalid Gen"); + break; + } + + /* Trainer/OT name, not to exceed 7 characters! */ + pokemon_name_set(pdata, STAT_TRAINER_NAME, "Flipper"); + pokemon_name_set(pdata, STAT_OT_NAME, "Flipper"); + + /* OT trainer ID# */ + pokemon_stat_set(pdata, STAT_OT_ID, NONE, 42069); + + /* Notes: + * Move pp isn't explicitly set up, should be fine + * Catch/held isn't explicitly set up, should be okay for only Gen I support now + * Status condition isn't explicity let up, would you ever want to? + */ + + /* Set up initial pokemon and level */ + /* This causes all other stats to be recalculated */ + pokemon_stat_set(pdata, STAT_NUM, NONE, 0); // First Pokemon + pokemon_stat_set(pdata, STAT_LEVEL, NONE, 2); // Minimum level of 2 + + return pdata; +} + +void pokemon_data_free(PokemonData* pdata) { + furi_record_close(RECORD_STORAGE); + free(pdata->trade_block); + if(pdata->bitmap && pdata->bitmap_num != 0) free(pdata->bitmap); + furi_string_free(pdata->asset_path); + free(pdata); +} + +/* Recalculate values and stats based on their dependencies. + * The order of the if statements are in order of dependence from + * depending on no other value, to dpeneding on multiple other values. + * + * level: depends on: none + * iv: depends on: none (only what the EV/IV general setting is, which recalculates EV/IV at time of set) + * ev: depends on: level (sometimes) + * exp: depends on: level, index + * moves: depends on: index + * types: depends on: index + * nickname: depends on: index + * atk/def/etc: depends on: level, iv, ev, index + */ +void pokemon_recalculate(PokemonData* pdata, uint8_t recalc) { + furi_assert(pdata); + int i; + + if(recalc == RECALC_NONE) return; + + /* Ordered in order of priority for calculating other stats */ + if(recalc & RECALC_NICKNAME) pokemon_default_nickname_set(NULL, pdata, 0); + + if(recalc & RECALC_MOVES) { + for(i = MOVE_0; i <= MOVE_3; i++) { + pokemon_stat_set( + pdata, + STAT_MOVE, + i, + table_stat_base_get( + pdata->pokemon_table, + pokemon_stat_get(pdata, STAT_NUM, NONE), + STAT_BASE_MOVE, + i)); + } + } + + if(recalc & RECALC_TYPES) { + for(i = TYPE_0; i <= TYPE_1; i++) { + pokemon_stat_set( + pdata, + STAT_TYPE, + i, + table_stat_base_get( + pdata->pokemon_table, + pokemon_stat_get(pdata, STAT_NUM, NONE), + STAT_BASE_TYPE, + i)); + } + } + + if(recalc & RECALC_EXP) pokemon_exp_calc(pdata); + + if(recalc & RECALC_EVS) pokemon_stat_ev_calc(pdata, pdata->stat_sel); + + /* This just rerolls the IVs, nothing really to calculate */ + if(recalc & RECALC_IVS) pokemon_stat_iv_calc(pdata, pdata->stat_sel); + + /* Note: This will still end up calculating spc_def on gen i pokemon. + * However, the way the accessors are set up the calculated value will + * never be written anywhere. This is just wasted CPU time. + */ + if(recalc & RECALC_STATS) { + for(i = STAT; i < STAT_END; i++) { + pokemon_stat_calc(pdata, i); + } + } +} + +/* This needs to convert to encoded characters */ +void pokemon_name_set(PokemonData* pdata, DataStat stat, char* name) { + furi_assert(pdata); + size_t len; + uint8_t gen = pdata->gen; + uint8_t* ptr = NULL; + + switch(stat) { + case STAT_NICKNAME: + if(gen == GEN_I) ptr = ((TradeBlockGenI*)pdata->trade_block)->nickname[0].str; + if(gen == GEN_II) ptr = ((TradeBlockGenII*)pdata->trade_block)->nickname[0].str; + len = 10; + break; + case STAT_OT_NAME: + if(gen == GEN_I) ptr = ((TradeBlockGenI*)pdata->trade_block)->ot_name[0].str; + if(gen == GEN_II) ptr = ((TradeBlockGenII*)pdata->trade_block)->ot_name[0].str; + len = 7; + break; + case STAT_TRAINER_NAME: + if(gen == GEN_I) ptr = ((TradeBlockGenI*)pdata->trade_block)->trainer_name.str; + if(gen == GEN_II) ptr = ((TradeBlockGenII*)pdata->trade_block)->trainer_name.str; + len = 7; + break; + default: + furi_crash("name"); + break; + } + + /* Clear the buffer with TERM character */ + memset(ptr, TERM_, LEN_NAME_BUF); + + /* Set the encoded name in the buffer */ + pokemon_str_to_encoded_array(ptr, name, len); + FURI_LOG_D(TAG, "[data] %s name set to %s", stat_text_get(stat), name); +} + +void pokemon_name_get(PokemonData* pdata, DataStat stat, char* dest, size_t len) { + furi_assert(pdata); + uint8_t* ptr = NULL; + uint8_t gen = pdata->gen; + + switch(stat) { + case STAT_NICKNAME: + if(gen == GEN_I) ptr = ((TradeBlockGenI*)pdata->trade_block)->nickname[0].str; + if(gen == GEN_II) ptr = ((TradeBlockGenII*)pdata->trade_block)->nickname[0].str; + break; + case STAT_OT_NAME: + if(gen == GEN_I) ptr = ((TradeBlockGenI*)pdata->trade_block)->ot_name[0].str; + if(gen == GEN_II) ptr = ((TradeBlockGenII*)pdata->trade_block)->ot_name[0].str; + break; + default: + furi_crash("name_get invalid"); + break; + } + + pokemon_encoded_array_to_str(dest, ptr, len); +} + +/* If dest is not NULL, a copy of the default name is written to it as well */ +void pokemon_default_nickname_set(char* dest, PokemonData* pdata, size_t n) { + furi_assert(pdata); + unsigned int i; + char buf[LEN_NAME_BUF]; + + /* First, get the default name */ + strncpy( + buf, + table_stat_name_get(pdata->pokemon_table, pokemon_stat_get(pdata, STAT_NUM, NONE)), + sizeof(buf)); + + /* Next, walk through and toupper() each character */ + for(i = 0; i < sizeof(buf); i++) { + buf[i] = toupper(buf[i]); + } + + pokemon_name_set(pdata, STAT_NICKNAME, buf); + FURI_LOG_D(TAG, "[data] Set default nickname"); + + if(dest != NULL) { + strncpy(dest, buf, n); + } +} + +/* Each sprite 56x56 is 404 bytes long */ +uint8_t* pokemon_icon_get(PokemonData* pdata, int num) { + furi_assert(pdata); + File* file; + FuriString* path; + uint32_t size; + bool is_error = true; + + if(pdata->bitmap_num != num) { + if(pdata->bitmap) { + free(pdata->bitmap); + pdata->bitmap = NULL; + } + + file = storage_file_alloc(pdata->storage); + path = furi_string_alloc_set(pdata->asset_path); + furi_string_cat_printf(path, "all_sprites.fxbm"); + + if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + storage_file_seek(file, (num - 1) * FXBM_SPRITE_SIZE, true); + if(storage_file_read(file, &size, sizeof(size)) == sizeof(size)) { + pdata->bitmap = malloc(size); + if(storage_file_read(file, pdata->bitmap, size) == + FXBM_SPRITE_SIZE - sizeof(size)) { + FURI_LOG_D(TAG, "Opened file \'%s\'", furi_string_get_cstr(path)); + is_error = false; + } else { + free(pdata->bitmap); + } + } + } + + if(is_error) { + FURI_LOG_E( + TAG, "Failed to open \'%s\' or access sprite data", furi_string_get_cstr(path)); + pdata->bitmap = (struct fxbm_sprite*)((uint8_t*)(__000_fxbm) + sizeof(size)); + num = 0; + } + + storage_file_free(file); + furi_string_free(path); + + pdata->bitmap_num = num; + } + + return (uint8_t*)pdata->bitmap; +} + +uint16_t pokemon_stat_get(PokemonData* pdata, DataStat stat, DataStatSub which) { + furi_assert(pdata); + void* party = pdata->party; + int gen = pdata->gen; + uint16_t val = 0; + uint8_t hp_iv = 0; + + switch(stat) { + case STAT_ATK: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->atk; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->atk; + break; + case STAT_DEF: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->def; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->def; + break; + case STAT_SPD: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->spd; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->spd; + break; + case STAT_SPC: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->spc; + break; + case STAT_SPC_ATK: + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->spc_atk; + break; + case STAT_SPC_DEF: + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->spc_def; + break; + case STAT_HP: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->hp; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->hp; + break; + case STAT_ATK_EV: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->atk_ev; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->atk_ev; + break; + case STAT_DEF_EV: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->def_ev; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->def_ev; + break; + case STAT_SPD_EV: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->spd_ev; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->spd_ev; + break; + case STAT_SPC_EV: + case STAT_SPC_ATK_EV: + case STAT_SPC_DEF_EV: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->spc_ev; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->spc_ev; + break; + case STAT_HP_EV: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->hp_ev; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->hp_ev; + break; + case STAT_IV: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->iv; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->iv; + break; + /* The IVs in GB byte order, are always: + * atk, def, spd, spc + * Like every other 16 bit quantity that the Flipper acts on, we need to + * bytw swap them normally. However, the below accessors for individual + * IV nibbles directly pull from the data structures which will always + * be in GB endianness. + */ + case STAT_SPD_IV: + if(gen == GEN_I) return (((PokemonPartyGenI*)party)->iv >> 12) & 0x0F; + if(gen == GEN_II) return (((PokemonPartyGenII*)party)->iv >> 12) & 0x0F; + break; + /* In order to line up all of the dynamic stat accessors used as part of the + * stat calculation loop, we need to overload the SPC IV accessor to allow + * accessing SPC, SPC_ATK, and SPC_DEF. Note that only SPC exists, the ATK + * and DEF are the overloaded values. This is so when, for example, gen i + * calculates its SPC value, or gen ii calculates is SPC_DEF value, it will + * always grab the same IV nibble. + */ + case STAT_SPC_IV: + case STAT_SPC_ATK_IV: + case STAT_SPC_DEF_IV: + if(gen == GEN_I) return (((PokemonPartyGenI*)party)->iv >> 8) & 0x0F; + if(gen == GEN_II) return (((PokemonPartyGenII*)party)->iv >> 8) & 0x0F; + break; + case STAT_ATK_IV: + if(gen == GEN_I) return (((PokemonPartyGenI*)party)->iv >> 4) & 0x0F; + if(gen == GEN_II) return (((PokemonPartyGenII*)party)->iv >> 4) & 0x0F; + break; + case STAT_DEF_IV: + if(gen == GEN_I) return ((PokemonPartyGenI*)party)->iv & 0x0F; + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->iv & 0x0F; + break; + case STAT_HP_IV: + /* NOTE: + * HP IV is calculated as the LSB of each other IV, assembled in the + * same bit order down to a single nibble. + */ + if(gen == GEN_I) val = (((PokemonPartyGenI*)party)->iv); + if(gen == GEN_II) val = (((PokemonPartyGenII*)party)->iv); + /* NOTE: + * As noted above, we store the IV in the trade struct in the byte order + * of the gameboy which is swapped from the Flipper's byte order. + */ + hp_iv |= ((val & 0x0010) >> 1); // ATK IV, MSbit of the hp_iv nibble + hp_iv |= ((val & 0x0001) << 2); // DEF IV, right of ATK IV in hp_iv nibble + hp_iv |= ((val & 0x1000) >> 11); // SPD IV, right of DEF IV in hp_iv nibble + hp_iv |= ((val & 0x0100) >> 8); // SPC IV, right of SPD IV in hp_iv nibble + return hp_iv; + break; + case STAT_LEVEL: + if(gen == GEN_I) return ((PokemonPartyGenI*)party)->level; + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->level; + break; + case STAT_INDEX: + if(gen == GEN_I) return ((PokemonPartyGenI*)party)->index; + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->index - 1; + break; + /* In Gen I, index is not relative at all to dex num. + * In Gen II, index is the same as the dex num. + */ + case STAT_NUM: + if(gen == GEN_I) { + val = ((PokemonPartyGenI*)party)->index; + return table_pokemon_pos_get(pdata->pokemon_table, val); + } + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->index - 1; + break; + case STAT_MOVE: + if(gen == GEN_I) return ((PokemonPartyGenI*)party)->move[which]; + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->move[which]; + break; + case STAT_TYPE: + if(gen == GEN_I) return ((PokemonPartyGenI*)party)->type[which]; + break; + case STAT_OT_ID: + if(gen == GEN_I) val = ((PokemonPartyGenI*)party)->ot_id; + if(gen == GEN_II) val = ((PokemonPartyGenII*)party)->ot_id; + break; + case STAT_POKERUS: + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->pokerus; + break; + case STAT_SEL: + if(gen == GEN_I) return pdata->stat_sel; + if(gen == GEN_II) return pdata->stat_sel; + break; + case STAT_CONDITION: + if(gen == GEN_I) return ((PokemonPartyGenI*)party)->status_condition = val; + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->status_condition = val; + break; + case STAT_HELD_ITEM: + if(gen == GEN_II) return ((PokemonPartyGenII*)party)->held_item; + break; + default: + furi_crash("STAT_GET: invalid stat"); + break; + } + + return __builtin_bswap16(val); +} + +void pokemon_stat_set(PokemonData* pdata, DataStat stat, DataStatSub which, uint16_t val) { + furi_assert(pdata); + void* party = pdata->party; + int gen = pdata->gen; + uint8_t recalc = 0; + uint16_t val_swap = __builtin_bswap16(val); + + switch(stat) { + case STAT_ATK: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->atk = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->atk = val_swap; + break; + case STAT_DEF: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->def = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->def = val_swap; + break; + case STAT_SPD: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->spd = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->spd = val_swap; + break; + case STAT_SPC: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->spc = val_swap; + break; + case STAT_SPC_ATK: + if(gen == GEN_II) ((PokemonPartyGenII*)party)->spc_atk = val_swap; + break; + case STAT_SPC_DEF: + if(gen == GEN_II) ((PokemonPartyGenII*)party)->spc_def = val_swap; + break; + case STAT_HP: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->hp = val_swap; + ((PokemonPartyGenI*)party)->max_hp = val_swap; + } + if(gen == GEN_II) { + ((PokemonPartyGenII*)party)->hp = val_swap; + ((PokemonPartyGenII*)party)->max_hp = val_swap; + } + break; + case STAT_ATK_EV: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->atk_ev = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->atk_ev = val_swap; + break; + case STAT_DEF_EV: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->def_ev = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->def_ev = val_swap; + break; + case STAT_SPD_EV: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->spd_ev = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->spd_ev = val_swap; + break; + /* The SPC ATK/DEF EVs are not real values, we just pretend they are */ + case STAT_SPC_EV: + case STAT_SPC_ATK_EV: + case STAT_SPC_DEF_EV: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->spc_ev = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->spc_ev = val_swap; + break; + case STAT_HP_EV: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->hp_ev = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->hp_ev = val_swap; + break; + case STAT_IV: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->iv = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->iv = val_swap; + break; + /* The IVs in GB byte order, are always: + * atk, def, spd, spc + * Like every other 16 bit quantity that the Flipper acts on, we need to + * bytw swap them normally. However, the below accessors for individual + * IV nibbles directly manipulate the data structures which will always + * be in GB endianness. + */ + case STAT_SPD_IV: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->iv &= ~(0x0F << 12); + ((PokemonPartyGenI*)party)->iv |= ((val & 0x0F) << 12); + } + if(gen == GEN_II) { + ((PokemonPartyGenII*)party)->iv &= ~(0x0F << 12); + ((PokemonPartyGenII*)party)->iv |= ((val & 0x0F) << 12); + } + break; + /* In order to line up all of the dynamic stat accessors used as part of the + * stat calculation loop, we need to overload the SPC IV accessor to allow + * accessing SPC, SPC_ATK, and SPC_DEF. Note that only SPC exists, the ATK + * and DEF are the overloaded values. This is so when, for example, gen i + * calculates its SPC value, or gen ii calculates is SPC_DEF value, it will + * always grab the same IV nibble. + */ + case STAT_SPC_IV: + case STAT_SPC_ATK_IV: + case STAT_SPC_DEF_IV: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->iv &= ~(0x0F << 8); + ((PokemonPartyGenI*)party)->iv |= ((val & 0x0F) << 8); + } + if(gen == GEN_II) { + ((PokemonPartyGenII*)party)->iv &= ~(0x0F << 8); + ((PokemonPartyGenII*)party)->iv |= ((val & 0x0F) << 8); + } + break; + case STAT_ATK_IV: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->iv &= ~(0x0F << 4); + ((PokemonPartyGenI*)party)->iv |= ((val & 0x0F) << 4); + } + if(gen == GEN_II) { + ((PokemonPartyGenII*)party)->iv &= ~(0x0F << 4); + ((PokemonPartyGenII*)party)->iv |= ((val & 0x0F) << 4); + } + break; + case STAT_DEF_IV: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->iv &= ~(0x0F); + ((PokemonPartyGenI*)party)->iv |= (val & 0x0F); + } + if(gen == GEN_II) { + ((PokemonPartyGenII*)party)->iv &= ~(0x0F); + ((PokemonPartyGenII*)party)->iv |= (val & 0x0F); + } + break; + case STAT_MOVE: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->move[which] = val; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->move[which] = val; + break; + case STAT_TYPE: + /* Gen II doesn't have type assignment */ + if(gen == GEN_I) ((PokemonPartyGenI*)party)->type[which] = val; + break; + case STAT_LEVEL: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->level = val; + ((PokemonPartyGenI*)party)->level_again = val; + } + if(gen == GEN_II) ((PokemonPartyGenII*)party)->level = val; + recalc = (RECALC_STATS | RECALC_EXP | RECALC_EVS); + break; + /* In Gen I, index is not relative at all to dex num. + * In Gen II, index is the same as the dex num. + */ + case STAT_INDEX: + if(gen == GEN_I) { + ((PokemonPartyGenI*)party)->index = val; + ((TradeBlockGenI*)pdata->trade_block)->party_members[0] = val; + } + if(gen == GEN_II) { + ((PokemonPartyGenII*)party)->index = val + 1; + ((TradeBlockGenII*)pdata->trade_block)->party_members[0] = val + 1; + } + recalc = RECALC_ALL; // Always recalculate everything if we selected a different pokemon + break; + case STAT_NUM: + if(gen == GEN_I) + pokemon_stat_set( + pdata, + STAT_INDEX, + NONE, + table_stat_base_get(pdata->pokemon_table, val, STAT_BASE_INDEX, NONE)); + if(gen == GEN_II) pokemon_stat_set(pdata, STAT_INDEX, NONE, val); + break; + case STAT_OT_ID: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->ot_id = val_swap; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->ot_id = val_swap; + break; + case STAT_POKERUS: + if(gen == GEN_II) ((PokemonPartyGenII*)party)->pokerus = val; + break; + case STAT_SEL: + pdata->stat_sel = val; + recalc = (RECALC_EVS | RECALC_IVS | RECALC_STATS); + break; + case STAT_EXP: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->exp[which] = val; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->exp[which] = val; + break; + case STAT_CONDITION: + if(gen == GEN_I) ((PokemonPartyGenI*)party)->status_condition = val; + if(gen == GEN_II) ((PokemonPartyGenII*)party)->status_condition = val; + break; + case STAT_HELD_ITEM: + if(gen == GEN_II) ((PokemonPartyGenII*)party)->held_item = val; + break; + default: + furi_crash("STAT_SET: invalid stat"); + break; + } + FURI_LOG_D(TAG, "[data] stat %s:%d set to 0x%X", stat_text_get(stat), which, val); + pokemon_recalculate(pdata, recalc); +} + +static void pokemon_stat_ev_calc(PokemonData* pdata, EvIv val) { + furi_assert(pdata); + int level; + uint16_t ev; + DataStat i; + + level = pokemon_stat_get(pdata, STAT_LEVEL, NONE); + + /* Generate STATEXP */ + switch(val) { + case RANDIV_LEVELEV: + case MAXIV_LEVELEV: + ev = (0xffff / 100) * level; + break; + case RANDIV_MAXEV: + case MAXIV_MAXEV: + ev = 0xffff; + break; + default: + ev = 0; + break; + } + + for(i = STAT_EV; i < STAT_EV_END; i++) { + pokemon_stat_set(pdata, i, NONE, ev); + } +} + +static void pokemon_stat_iv_calc(PokemonData* pdata, EvIv val) { + furi_assert(pdata); + uint16_t iv; + + /* Set up IVs */ + switch(val) { + case RANDIV_ZEROEV: + case RANDIV_LEVELEV: + case RANDIV_MAXEV: + iv = (uint16_t)rand(); + break; + default: + iv = 0xFFFF; + break; + } + + pokemon_stat_set(pdata, STAT_IV, NONE, iv); +} + +#define UINT32_TO_EXP(input, output_array) \ + do { \ + (output_array)[2] = (uint8_t)((input) & 0xFF); \ + (output_array)[1] = (uint8_t)(((input) >> 8) & 0xFF); \ + (output_array)[0] = (uint8_t)(((input) >> 16) & 0xFF); \ + } while(0) + +void pokemon_exp_set(PokemonData* pdata, uint32_t exp) { + furi_assert(pdata); + uint8_t exp_tmp[3]; + int i; + + UINT32_TO_EXP(exp, exp_tmp); + + for(i = EXP_0; i <= EXP_2; i++) { + pokemon_stat_set(pdata, STAT_EXP, i, exp_tmp[i]); + } + + FURI_LOG_D(TAG, "[data] Set pkmn exp %d", (int)exp); +} + +void pokemon_exp_calc(PokemonData* pdata) { + furi_assert(pdata); + int level; + uint32_t exp; + uint8_t growth = table_stat_base_get( + pdata->pokemon_table, pokemon_stat_get(pdata, STAT_NUM, NONE), STAT_BASE_GROWTH, NONE); + + level = (int)pokemon_stat_get(pdata, STAT_LEVEL, NONE); + /* Calculate exp */ + switch(growth) { + case GROWTH_FAST: + // https://bulbapedia.bulbagarden.net/wiki/Experience#Fast + exp = (4 * level * level * level) / 5; + break; + case GROWTH_MEDIUM_FAST: + // https://bulbapedia.bulbagarden.net/wiki/Experience#Medium_Fast + exp = (level * level * level); + break; + case GROWTH_MEDIUM_SLOW: + // https://bulbapedia.bulbagarden.net/wiki/Experience#Medium_Slow + exp = (((level * level * level) * 6 / 5) - (15 * level * level) + (100 * level) - 140); + break; + case GROWTH_SLOW: + // https://bulbapedia.bulbagarden.net/wiki/Experience#Slow + exp = (5 * level * level * level) / 4; + break; + default: + furi_crash("incorrect growth val"); + break; + } + + pokemon_exp_set(pdata, exp); +} + +/* Calculates stat from current level */ +void pokemon_stat_calc(PokemonData* pdata, DataStat stat) { + furi_assert(pdata); + uint8_t iv; + uint16_t ev; + uint8_t base; + uint8_t level; + uint16_t calc; + + level = pokemon_stat_get(pdata, STAT_LEVEL, NONE); + base = table_stat_base_get( + pdata->pokemon_table, pokemon_stat_get(pdata, STAT_NUM, NONE), stat, NONE); + ev = pokemon_stat_get(pdata, stat + STAT_EV_OFFS, NONE); + iv = pokemon_stat_get(pdata, stat + STAT_IV_OFFS, NONE); + + /* Gen I and II calculation */ + // https://bulbapedia.bulbagarden.net/wiki/Stat#Generations_I_and_II + calc = floor((((2 * (base + iv)) + floor(sqrt(ev) / 4)) * level) / 100); + + if(stat == STAT_HP) + calc += (level + 10); + else + calc += 5; + + pokemon_stat_set(pdata, stat, NONE, calc); +} + +/* Copy the traded-in Pokemon's main data to our struct */ +void pokemon_stat_memcpy(PokemonData* dst, PokemonData* src, uint8_t which) { + if(dst->gen == GEN_I) { + ((TradeBlockGenI*)dst->trade_block)->party_members[0] = + ((TradeBlockGenI*)src->trade_block)->party_members[which]; + memcpy( + &(((TradeBlockGenI*)dst->trade_block)->party[0]), + &(((TradeBlockGenI*)src->trade_block)->party[which]), + sizeof(PokemonPartyGenI)); + memcpy( + &(((TradeBlockGenI*)dst->trade_block)->nickname[0]), + &(((TradeBlockGenI*)src->trade_block)->nickname[which]), + sizeof(struct name)); + memcpy( + &(((TradeBlockGenI*)dst->trade_block)->ot_name[0]), + &(((TradeBlockGenI*)src->trade_block)->ot_name[which]), + sizeof(struct name)); + } else if(dst->gen == GEN_II) { + ((TradeBlockGenI*)dst->trade_block)->party_members[0] = + ((TradeBlockGenI*)src->trade_block)->party_members[which]; + memcpy( + &(((TradeBlockGenII*)dst->trade_block)->party[0]), + &(((TradeBlockGenII*)src->trade_block)->party[which]), + sizeof(PokemonPartyGenI)); + memcpy( + &(((TradeBlockGenII*)dst->trade_block)->nickname[0]), + &(((TradeBlockGenII*)src->trade_block)->nickname[which]), + sizeof(struct name)); + memcpy( + &(((TradeBlockGenII*)dst->trade_block)->ot_name[0]), + &(((TradeBlockGenII*)src->trade_block)->ot_name[which]), + sizeof(struct name)); + } +} diff --git a/pokemon_data.h b/pokemon_data.h index 7c7effecebe..3609388932b 100644 --- a/pokemon_data.h +++ b/pokemon_data.h @@ -3,72 +3,90 @@ #pragma once -/* The struct is laid out exactly as the data trasfer that gets sent for trade - * information. It has to be packed in order to not have padding in the Flipper. - * Packing is always potentially filled with pitfalls, however this has worked - * in testing without issue and this code isn't meant to be portable. - */ - -/* NOTE: These are all opposite endianness on the flipper than they are in the - * GB/Z80. e.g. a uint16_t value of 0x2c01 translates to 0x012c. - * Need to use __builtin_bswap16(val) to switch between Flipper and Pokemon. - */ -/* This is 44 bytes in memory */ -struct __attribute__((__packed__)) pokemon_structure { - uint8_t index; - uint16_t hp; // Calculated from level - /* Level is normally calculated from exp, however, level is more human - * readable/digestable compared to exp. Therefore, we set legel and then - * from that calculate, (Max)HP, ATK, DEF, SPD, SPC. - */ - uint8_t level; - uint8_t status_condition; // Do you really want to trade a Poisoned pokemon? - uint8_t type[2]; // Pokemon with a single type just repeat the type twice - uint8_t catch_held; // Unsure if this has any effect in Gen 1 - uint8_t move[4]; - uint16_t ot_id; - uint8_t exp[3]; // Calculated from level - uint16_t hp_ev; - uint16_t atk_ev; - uint16_t def_ev; - uint16_t spd_ev; - uint16_t special_ev; - uint16_t iv; - uint8_t move_pp[4]; - uint8_t level_again; // Copy of level - uint16_t max_hp; // Calculated from level - uint16_t atk; // Calculated from level - uint16_t def; // Calculated from level - uint16_t spd; // Calculated from level - uint16_t special; // Calculated from level -}; +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include "stats.h" + +/* Generation defines */ +#define GEN_I 0x01 +#define GEN_II 0x02 + +/* Some length macros */ +#define LEN_NAME_BUF 11 +#define LEN_NICKNAME 11 // Max 10 chars +#define LEN_OT_NAME 8 // Max 7 chars +#define LEN_NUM_BUF 6 +#define LEN_LEVEL 4 // Max 3 digits +#define LEN_OT_ID 6 // Max 5 digits + +typedef struct pokemon_party_data_gen_i PokemonPartyGenI; +typedef struct trade_block_gen_i TradeBlockGenI; +typedef struct pokemon_party_data_gen_ii PokemonPartyGenII; +typedef struct trade_block_gen_ii TradeBlockGenII; -struct __attribute__((__packed__)) name { - /* Reused a few times, but in Gen I, all name strings are 11 bytes in memory. - * At most, 10 symbols and a TERM_ byte. - * Note that some strings must be shorter than 11. - */ - unsigned char str[11]; +/* Based on the flipperzero-game-engine sprite structure */ +struct fxbm_sprite { + uint32_t width; + uint32_t height; + uint8_t data[]; }; -/* This is 415 bytes in memory/transmitted */ -struct __attribute__((__packed__)) trade_data_block { - /* TODO: Change this to use struct name above */ - unsigned char trainer_name[11]; - uint8_t party_cnt; - /* Only the first pokemon is ever used even though there are 7 bytes here. - * If the remaining 6 bytes are _not_ 0xff, then the trade window renders - * garbage for the Flipper's party. - */ - uint8_t party_members[7]; - /* Only the first pokemon is set up, even though there are 6 total party members */ - struct pokemon_structure party[6]; - /* Only the first pokemon has an OT name and nickname even though there are 6 members */ - /* OT name should not exceed 7 chars! */ - struct name ot_name[6]; - struct name nickname[6]; +struct pokemon_data { + const NamedList* move_list; + const NamedList* stat_list; + const NamedList* type_list; + const NamedList* item_list; + const PokemonTable* pokemon_table; + /* Pointer to the live trade_block */ + void* trade_block; + /* The length of the current trade_block. */ + size_t trade_block_sz; + /* Shortcut pointer to the actual party data in the trade block */ + void* party; + size_t party_sz; + + /* Current EV/IV stat selection */ + EvIv stat_sel; + + /* Current generation */ + uint8_t gen; + + /* 0 indexed max pokedex number */ + uint8_t dex_max; + + /* These are private to pokemon_data */ + Storage* storage; + struct fxbm_sprite* bitmap; + uint8_t bitmap_num; + FuriString* asset_path; }; +typedef struct pokemon_data PokemonData; + +PokemonData* pokemon_data_alloc(uint8_t gen); +void pokemon_data_free(PokemonData* pdata); -typedef struct trade_data_block TradeBlock; +uint8_t* pokemon_icon_get(PokemonData* pdata, int num); +void pokemon_stat_memcpy(PokemonData* dst, PokemonData* src, uint8_t which); +uint16_t pokemon_stat_get(PokemonData* pdata, DataStat stat, DataStatSub num); +void pokemon_stat_set(PokemonData* pdata, DataStat stat, DataStatSub which, uint16_t val); +uint16_t pokemon_stat_ev_get(PokemonData* pdata, DataStat stat); +void pokemon_stat_ev_set(PokemonData* pdata, DataStat stat, uint16_t val); +void pokemon_stat_iv_set(PokemonData* pdata, int val); +void pokemon_exp_set(PokemonData* pdata, uint32_t exp); +void pokemon_exp_calc(PokemonData* pdata); +void pokemon_stat_calc(PokemonData* pdata, DataStat stat); +void pokemon_default_nickname_set(char* dest, PokemonData* pdata, size_t n); +void pokemon_name_set(PokemonData* pdata, DataStat stat, char* name); +void pokemon_name_get(PokemonData* pdata, DataStat stat, char* dest, size_t len); #endif /* POKEMON_DATA_H */ diff --git a/pokemon_data_i.h b/pokemon_data_i.h new file mode 100644 index 00000000000..e94fd46d587 --- /dev/null +++ b/pokemon_data_i.h @@ -0,0 +1,143 @@ +#ifndef __POKEMON_DATA_I_H__ +#define __POKEMON_DATA_I_H__ + +#include "pokemon_data.h" + +//#include "pokemon_app.h" +//#include "pokemon_char_encode.h" + +static void pokemon_stat_ev_calc(PokemonData* pdata, EvIv val); +static void pokemon_stat_iv_calc(PokemonData* pdata, EvIv val); + +/* The struct is laid out exactly as the data trasfer that gets sent for trade + * information. It has to be packed in order to not have padding in the Flipper. + * Packing is always potentially filled with pitfalls, however this has worked + * in testing without issue and this code isn't meant to be portable. + */ + +/* NOTE: These are all opposite endianness on the flipper than they are in the + * GB/Z80. e.g. a uint16_t value of 0x2c01 translates to 0x012c. + * Need to use __builtin_bswap16(val) to switch between Flipper and Pokemon. + */ +/* This is 44 bytes in memory */ +struct __attribute__((__packed__)) pokemon_party_data_gen_i { + uint8_t index; + uint16_t hp; // Calculated from level + /* Level is normally calculated from exp, however, level is more human + * readable/digestable compared to exp. Therefore, we set legel and then + * from that calculate, (Max)HP, ATK, DEF, SPD, SPC. + */ + uint8_t level; + uint8_t status_condition; // Do you really want to trade a Poisoned pokemon? + uint8_t type[2]; // Pokemon with a single type just repeat the type twice + uint8_t catch_held; // Unsure if this has any effect in Gen 1 + uint8_t move[4]; + uint16_t ot_id; + uint8_t exp[3]; // Calculated from level + uint16_t hp_ev; + uint16_t atk_ev; + uint16_t def_ev; + uint16_t spd_ev; + uint16_t spc_ev; + uint16_t iv; + uint8_t move_pp[4]; + uint8_t level_again; // Copy of level + uint16_t max_hp; // Calculated from level + uint16_t atk; // Calculated from level + uint16_t def; // Calculated from level + uint16_t spd; // Calculated from level + uint16_t spc; // Calculated from level +}; + +struct __attribute__((__packed__)) name { + /* Reused a few times, but in Gen I, all name strings are 11 bytes in memory. + * At most, 10 symbols and a TERM_ byte. + * Note that some strings must be shorter than 11. + */ + uint8_t str[LEN_NAME_BUF]; +}; +typedef struct name Name; + +/* This is 415 bytes in memory/transmitted */ +struct __attribute__((__packed__)) trade_block_gen_i { + Name trainer_name; + uint8_t party_cnt; + /* Only the first pokemon is ever used even though there are 7 bytes here. + * If the remaining 6 bytes are _not_ 0xff, then the trade window renders + * garbage for the Flipper's party. + */ + uint8_t party_members[7]; + /* Only the first pokemon is set up, even though there are 6 total party members */ + PokemonPartyGenI party[6]; + /* Only the first pokemon has an OT name and nickname even though there are 6 members */ + /* OT name should not exceed 7 chars! */ + Name ot_name[6]; + Name nickname[6]; +}; + +/* NOTE: These are all opposite endianness on the flipper than they are in the + * GB/Z80. e.g. a uint16_t value of 0x2c01 translates to 0x012c. + * Need to use __builtin_bswap16(val) to switch between Flipper and Pokemon. + */ +/* This is 48 bytes in memory */ +struct __attribute__((__packed__)) pokemon_party_data_gen_ii { + uint8_t index; + uint8_t held_item; + uint8_t move[4]; + uint16_t ot_id; + uint8_t exp[3]; + uint16_t hp_ev; + uint16_t atk_ev; + uint16_t def_ev; + uint16_t spd_ev; + uint16_t spc_ev; + uint16_t iv; + uint8_t move_pp[4]; + uint8_t friendship; + uint8_t pokerus; + uint16_t caught_data; + /* Level is normally calculated from exp, however, level is more human + * readable/digestable compared to exp. Therefore, we set level and then + * from that calculate, (Max)HP, ATK, DEF, SPD, SPC. + */ + uint8_t level; + uint8_t status_condition; + uint8_t unused; + uint16_t hp; + uint16_t max_hp; + uint16_t atk; + uint16_t def; + uint16_t spd; + uint16_t spc_atk; + uint16_t spc_def; +}; + +/* NOTE: + * For eggs in gen ii, the handling is a bit clever. The party structure is set + * up as normal for the pokemon that will hatch. The only difference is the + * friendship vairable is used to denote number of egg cycles remaining. + * Then, in the party_members array, that pokemon's index is set to 0xFD which + * is the index for an egg. Once traded, its now an egg. + * Creating an egg is not implemented at this time because I don't really see + * a reason to. But, knowing some of these details makes it really easy to + * implement later on. + */ + +struct __attribute__((__packed__)) trade_block_gen_ii { + Name trainer_name; + uint8_t party_cnt; + /* Only the first pokemon is ever used even though there are 7 bytes here. + * If the remaining 6 bytes are _not_ 0xff, then the trade window renders + * garbage for the Flipper's party. + */ + uint8_t party_members[7]; + uint16_t trainer_id; + /* Only the first pokemon is set up, even though there are 6 total party members */ + PokemonPartyGenII party[6]; + /* Only the first pokemon has an OT name and nickname even though there are 6 members */ + /* OT name should not exceed 7 chars! */ + Name ot_name[6]; + Name nickname[6]; +}; + +#endif // __POKEMON_DATA_I_H__ diff --git a/pokemon_table.c b/pokemon_table.c new file mode 100644 index 00000000000..e0b4017e98a --- /dev/null +++ b/pokemon_table.c @@ -0,0 +1,3361 @@ +#include + +#include +#include "stats.h" + +#include +#include + +#include + +/* NOTE: It seems like gen ii index is national pokedex order? */ +/* Gen i and Gen ii are _almost_ the same with all stats. The big difference + * is that while most gen i pokemon's spc matches the same gen ii spc_atk, + * some of them do differ. Therefore, we track spc for gen i, and then spc_atk + * and spc_def for gen ii. + */ +struct __attribute__((__packed__)) pokemon_data_table { + const char* name; + const uint8_t index; + const uint8_t base_hp; + const uint8_t base_atk; + const uint8_t base_def; + const uint8_t base_spd; + const uint8_t base_spc; + const uint8_t base_spc_atk; + const uint8_t base_spc_def; + const uint8_t type[2]; + const uint8_t move[4]; + const Growth growth; + const Gender gender_ratio; +}; + +int table_pokemon_pos_get(const PokemonTable* table, uint8_t index) { + int i; + + for(i = 0;; i++) { + if(table[i].index == index) return i; + if(table[i].name == NULL) break; + } + + /* This will return the first entry in case index is not matched. + * Could be surprising at runtime. + */ + return 0; +} + +const char* table_stat_name_get(const PokemonTable* table, int num) { + return table[num].name; +} + +uint8_t + table_stat_base_get(const PokemonTable* table, uint8_t num, DataStat stat, DataStatSub which) { + furi_assert(table); + + switch(stat) { + case STAT_BASE_INDEX: + return table[num].index; + case STAT_BASE_ATK: + return table[num].base_hp; + case STAT_BASE_DEF: + return table[num].base_def; + case STAT_BASE_SPD: + return table[num].base_spd; + case STAT_BASE_SPC: + return table[num].base_spc; + case STAT_BASE_SPC_ATK: + return table[num].base_spc_atk; + case STAT_BASE_SPC_DEF: + return table[num].base_spc_def; + case STAT_BASE_HP: + return table[num].base_hp; + case STAT_BASE_TYPE: + return table[num].type[which]; + case STAT_BASE_MOVE: + return table[num].move[which]; + case STAT_BASE_GROWTH: + return table[num].growth; + case STAT_BASE_GENDER_RATIO: + return table[num].gender_ratio; + default: + furi_crash("BASE_GET: invalid stat"); + break; + } + + return 0; +} + +static const PokemonTable pokemon_table[] = { + /* Values for base_*, moves, etc., pulled directly from a copy of Pokemon Blue */ + /* Note that, comparison between blue and gold show the same base stats for pokemon, with spc stk/def added in gold. spc atk is the same as spc between blue and gold for the first 151 pokemon. Movesets are different in gen ii for the first 151 pokeon, but, they are left with gen i movesets below. */ + {"Bulbasaur", + 0x99, + 0x2D, + 0x31, + 0x31, + 0x2D, + 0x41, + 0x41, + 0x41, + {0x16, 0x03}, + {0x21, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Ivysaur", + 0x09, + 0x3C, + 0x3E, + 0x3F, + 0x3C, + 0x50, + 0x50, + 0x50, + {0x16, 0x03}, + {0x21, 0x2D, 0x49, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Venusaur", + 0x9A, + 0x50, + 0x52, + 0x53, + 0x50, + 0x64, + 0x64, + 0x64, + {0x16, 0x03}, + {0x21, 0x2D, 0x49, 0x16}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Charmander", + 0xB0, + 0x27, + 0x34, + 0x2B, + 0x41, + 0x32, + 0x3C, + 0x32, + {0x14, 0x14}, + {0x0A, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Charmeleon", + 0xB2, + 0x3A, + 0x40, + 0x3A, + 0x50, + 0x41, + 0x50, + 0x41, + {0x14, 0x14}, + {0x0A, 0x2D, 0x34, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Charizard", + 0xB4, + 0x4E, + 0x54, + 0x4E, + 0x64, + 0x55, + 0x6D, + 0x55, + {0x14, 0x02}, + {0x0A, 0x2D, 0x34, 0x2B}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Squirtle", + 0xB1, + 0x2C, + 0x30, + 0x41, + 0x2B, + 0x32, + 0x32, + 0x40, + {0x15, 0x15}, + {0x21, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Wartortle", + 0xB3, + 0x3B, + 0x3F, + 0x50, + 0x3A, + 0x41, + 0x41, + 0x50, + {0x15, 0x15}, + {0x21, 0x27, 0x91, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Blastoise", + 0x1C, + 0x4F, + 0x53, + 0x64, + 0x4E, + 0x55, + 0x55, + 0x69, + {0x15, 0x15}, + {0x21, 0x27, 0x91, 0x37}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Caterpie", + 0x7B, + 0x2D, + 0x1E, + 0x23, + 0x2D, + 0x14, + 0x14, + 0x14, + {0x07, 0x07}, + {0x21, 0x51, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Metapod", + 0x7C, + 0x32, + 0x14, + 0x37, + 0x1E, + 0x19, + 0x19, + 0x19, + {0x07, 0x07}, + {0x6A, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Butterfree", + 0x7D, + 0x3C, + 0x2D, + 0x32, + 0x46, + 0x50, + 0x50, + 0x50, + {0x07, 0x02}, + {0x5D, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Weedle", + 0x70, + 0x28, + 0x23, + 0x1E, + 0x32, + 0x14, + 0x14, + 0x14, + {0x07, 0x03}, + {0x28, 0x51, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Kakuna", + 0x71, + 0x2D, + 0x19, + 0x32, + 0x23, + 0x19, + 0x19, + 0x19, + {0x07, 0x03}, + {0x6A, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Beedrill", + 0x72, + 0x41, + 0x50, + 0x28, + 0x4B, + 0x2D, + 0x2D, + 0x50, + {0x07, 0x03}, + {0x1F, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Pidgey", + 0x24, + 0x28, + 0x2D, + 0x28, + 0x38, + 0x23, + 0x23, + 0x23, + {0x00, 0x02}, + {0x10, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Pidgeotto", + 0x96, + 0x3F, + 0x3C, + 0x37, + 0x47, + 0x32, + 0x32, + 0x32, + {0x00, 0x02}, + {0x10, 0x1C, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Pidgeot", + 0x97, + 0x53, + 0x50, + 0x4B, + 0x5B, + 0x46, + 0x46, + 0x46, + {0x00, 0x02}, + {0x10, 0x1C, 0x62, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Rattata", + 0xA5, + 0x1E, + 0x38, + 0x23, + 0x48, + 0x19, + 0x19, + 0x23, + {0x00, 0x00}, + {0x21, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Raticate", + 0xA6, + 0x37, + 0x51, + 0x3C, + 0x61, + 0x32, + 0x32, + 0x46, + {0x00, 0x00}, + {0x21, 0x27, 0x62, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Spearow", + 0x05, + 0x28, + 0x3C, + 0x1E, + 0x46, + 0x1F, + 0x1F, + 0x1F, + {0x00, 0x02}, + {0x40, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Fearow", + 0x23, + 0x41, + 0x5A, + 0x41, + 0x64, + 0x3D, + 0x3D, + 0x3D, + {0x00, 0x02}, + {0x40, 0x2D, 0x2B, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Ekans", + 0x6C, + 0x23, + 0x3C, + 0x2C, + 0x37, + 0x28, + 0x28, + 0x36, + {0x03, 0x03}, + {0x23, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Arbok", + 0x2D, + 0x3C, + 0x55, + 0x45, + 0x50, + 0x41, + 0x41, + 0x4F, + {0x03, 0x03}, + {0x23, 0x2B, 0x28, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Pikachu", + 0x54, + 0x23, + 0x37, + 0x1E, + 0x5A, + 0x32, + 0x32, + 0x28, + {0x17, 0x17}, + {0x54, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Raichu", + 0x55, + 0x3C, + 0x5A, + 0x37, + 0x64, + 0x5A, + 0x5A, + 0x50, + {0x17, 0x17}, + {0x54, 0x2D, 0x56, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Sandshrew", + 0x60, + 0x32, + 0x4B, + 0x55, + 0x28, + 0x1E, + 0x14, + 0x1E, + {0x04, 0x04}, + {0x0A, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Sandslash", + 0x61, + 0x4B, + 0x64, + 0x6E, + 0x41, + 0x37, + 0x2D, + 0x37, + {0x04, 0x04}, + {0x0A, 0x1C, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Nidoran\200", + 0x0F, + 0x37, + 0x2F, + 0x34, + 0x29, + 0x28, + 0x28, + 0x28, + {0x03, 0x03}, + {0x2D, 0x21, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F100}, + {"Nidorina", + 0xA8, + 0x46, + 0x3E, + 0x43, + 0x38, + 0x37, + 0x37, + 0x37, + {0x03, 0x03}, + {0x2D, 0x21, 0x0A, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F100}, + {"Nidoqueen", + 0x10, + 0x5A, + 0x52, + 0x57, + 0x4C, + 0x4B, + 0x4B, + 0x55, + {0x03, 0x04}, + {0x21, 0x0A, 0x27, 0x22}, + GROWTH_MEDIUM_SLOW, + GENDER_F100}, + {"Nidoran\201", + 0x03, + 0x2E, + 0x39, + 0x28, + 0x32, + 0x28, + 0x28, + 0x28, + {0x03, 0x03}, + {0x2B, 0x21, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F0}, + {"Nidorino", + 0xA7, + 0x3D, + 0x48, + 0x39, + 0x41, + 0x37, + 0x37, + 0x37, + {0x03, 0x03}, + {0x2B, 0x21, 0x1E, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F0}, + {"Nidoking", + 0x07, + 0x51, + 0x5C, + 0x4D, + 0x55, + 0x4B, + 0x55, + 0x4B, + {0x03, 0x04}, + {0x21, 0x1E, 0x28, 0x25}, + GROWTH_MEDIUM_SLOW, + GENDER_F0}, + {"Clefairy", + 0x04, + 0x46, + 0x2D, + 0x30, + 0x23, + 0x3C, + 0x3C, + 0x41, + {0x00, 0x00}, + {0x01, 0x2D, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Clefable", + 0x8E, + 0x5F, + 0x46, + 0x49, + 0x3C, + 0x55, + 0x55, + 0x5A, + {0x00, 0x00}, + {0x2F, 0x03, 0x6B, 0x76}, + GROWTH_FAST, + GENDER_F75}, + {"Vulpix", + 0x52, + 0x26, + 0x29, + 0x28, + 0x41, + 0x41, + 0x32, + 0x41, + {0x14, 0x14}, + {0x34, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F75}, + {"Ninetales", + 0x53, + 0x49, + 0x4C, + 0x4B, + 0x64, + 0x64, + 0x51, + 0x64, + {0x14, 0x14}, + {0x34, 0x27, 0x62, 0x2E}, + GROWTH_MEDIUM_FAST, + GENDER_F75}, + {"Jigglypuff", + 0x64, + 0x73, + 0x2D, + 0x14, + 0x14, + 0x19, + 0x2D, + 0x19, + {0x00, 0x00}, + {0x2F, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Wigglytuff", + 0x65, + 0x8C, + 0x46, + 0x2D, + 0x2D, + 0x32, + 0x4B, + 0x32, + {0x00, 0x00}, + {0x2F, 0x32, 0x6F, 0x03}, + GROWTH_FAST, + GENDER_F75}, + {"Zubat", + 0x6B, + 0x28, + 0x2D, + 0x23, + 0x37, + 0x28, + 0x1E, + 0x28, + {0x03, 0x02}, + {0x8D, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Golbat", + 0x82, + 0x4B, + 0x50, + 0x46, + 0x5A, + 0x4B, + 0x41, + 0x4B, + {0x03, 0x02}, + {0x8D, 0x67, 0x2C, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Oddish", + 0xB9, + 0x2D, + 0x32, + 0x37, + 0x1E, + 0x4B, + 0x4B, + 0x41, + {0x16, 0x03}, + {0x47, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Gloom", + 0xBA, + 0x3C, + 0x41, + 0x46, + 0x28, + 0x55, + 0x55, + 0x4B, + {0x16, 0x03}, + {0x47, 0x4D, 0x4E, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Vileplume", + 0xBB, + 0x4B, + 0x50, + 0x55, + 0x32, + 0x64, + 0x64, + 0x5A, + {0x16, 0x03}, + {0x4E, 0x4F, 0x33, 0x50}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Paras", + 0x6D, + 0x23, + 0x46, + 0x37, + 0x19, + 0x37, + 0x2D, + 0x37, + {0x07, 0x16}, + {0x0A, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Parasect", + 0x2E, + 0x3C, + 0x5F, + 0x50, + 0x1E, + 0x50, + 0x3C, + 0x50, + {0x07, 0x16}, + {0x0A, 0x4E, 0x8D, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Venonat", + 0x41, + 0x3C, + 0x37, + 0x32, + 0x2D, + 0x28, + 0x28, + 0x37, + {0x07, 0x03}, + {0x21, 0x32, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Venomoth", + 0x77, + 0x46, + 0x41, + 0x3C, + 0x5A, + 0x5A, + 0x5A, + 0x4B, + {0x07, 0x03}, + {0x21, 0x32, 0x4D, 0x8D}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Diglett", + 0x3B, + 0x0A, + 0x37, + 0x19, + 0x5F, + 0x2D, + 0x23, + 0x2D, + {0x04, 0x04}, + {0x0A, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Dugtrio", + 0x76, + 0x23, + 0x50, + 0x32, + 0x78, + 0x46, + 0x32, + 0x46, + {0x04, 0x04}, + {0x0A, 0x2D, 0x5B, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Meowth", + 0x4D, + 0x28, + 0x2D, + 0x23, + 0x5A, + 0x28, + 0x28, + 0x28, + {0x00, 0x00}, + {0x0A, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Persian", + 0x90, + 0x41, + 0x46, + 0x3C, + 0x73, + 0x41, + 0x41, + 0x41, + {0x00, 0x00}, + {0x0A, 0x2D, 0x2C, 0x67}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Psyduck", + 0x2F, + 0x32, + 0x34, + 0x30, + 0x37, + 0x32, + 0x41, + 0x32, + {0x15, 0x15}, + {0x0A, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Golduck", + 0x80, + 0x50, + 0x52, + 0x4E, + 0x55, + 0x50, + 0x5F, + 0x50, + {0x15, 0x15}, + {0x0A, 0x27, 0x32, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Mankey", + 0x39, + 0x28, + 0x50, + 0x23, + 0x46, + 0x23, + 0x23, + 0x2D, + {0x01, 0x01}, + {0x0A, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Primeape", + 0x75, + 0x41, + 0x69, + 0x3C, + 0x5F, + 0x3C, + 0x3C, + 0x46, + {0x01, 0x01}, + {0x0A, 0x2B, 0x02, 0x9A}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Growlithe", + 0x21, + 0x37, + 0x46, + 0x2D, + 0x3C, + 0x32, + 0x46, + 0x32, + {0x14, 0x14}, + {0x2C, 0x2E, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F25}, + {"Arcanine", + 0x14, + 0x5A, + 0x6E, + 0x50, + 0x5F, + 0x50, + 0x64, + 0x50, + {0x14, 0x14}, + {0x2E, 0x34, 0x2B, 0x24}, + GROWTH_SLOW, + GENDER_F25}, + {"Poliwag", + 0x47, + 0x28, + 0x32, + 0x28, + 0x5A, + 0x28, + 0x28, + 0x28, + {0x15, 0x15}, + {0x91, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Poliwhirl", + 0x6E, + 0x41, + 0x41, + 0x41, + 0x5A, + 0x32, + 0x32, + 0x32, + {0x15, 0x15}, + {0x91, 0x5F, 0x37, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Poliwrath", + 0x6F, + 0x5A, + 0x55, + 0x5F, + 0x46, + 0x46, + 0x46, + 0x5A, + {0x15, 0x01}, + {0x5F, 0x37, 0x03, 0x22}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Abra", + 0x94, + 0x19, + 0x14, + 0x0F, + 0x5A, + 0x69, + 0x69, + 0x37, + {0x18, 0x18}, + {0x64, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F25}, + {"Kadabra", + 0x26, + 0x28, + 0x23, + 0x1E, + 0x69, + 0x78, + 0x78, + 0x46, + {0x18, 0x18}, + {0x64, 0x5D, 0x32, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F25}, + {"Alakazam", + 0x95, + 0x37, + 0x32, + 0x2D, + 0x78, + 0x87, + 0x87, + 0x55, + {0x18, 0x18}, + {0x64, 0x5D, 0x32, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F25}, + {"Machop", + 0x6A, + 0x46, + 0x50, + 0x32, + 0x23, + 0x23, + 0x23, + 0x23, + {0x01, 0x01}, + {0x02, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F25}, + {"Machoke", + 0x29, + 0x50, + 0x64, + 0x46, + 0x2D, + 0x32, + 0x32, + 0x3C, + {0x01, 0x01}, + {0x02, 0x43, 0x2B, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F25}, + {"Machamp", + 0x7E, + 0x5A, + 0x82, + 0x50, + 0x37, + 0x41, + 0x41, + 0x55, + {0x01, 0x01}, + {0x02, 0x43, 0x2B, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F25}, + {"Bellsprout", + 0xBC, + 0x32, + 0x4B, + 0x23, + 0x28, + 0x46, + 0x46, + 0x1E, + {0x16, 0x03}, + {0x16, 0x4A, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Weepinbell", + 0xBD, + 0x41, + 0x5A, + 0x32, + 0x37, + 0x55, + 0x55, + 0x2D, + {0x16, 0x03}, + {0x16, 0x4A, 0x23, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Victreebel", + 0xBE, + 0x50, + 0x69, + 0x41, + 0x46, + 0x64, + 0x64, + 0x3C, + {0x16, 0x03}, + {0x4F, 0x4E, 0x33, 0x4B}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Tentacool", + 0x18, + 0x28, + 0x28, + 0x23, + 0x46, + 0x64, + 0x32, + 0x64, + {0x15, 0x03}, + {0x33, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Tentacruel", + 0x9B, + 0x50, + 0x46, + 0x41, + 0x64, + 0x78, + 0x50, + 0x78, + {0x15, 0x03}, + {0x33, 0x30, 0x23, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Geodude", + 0xA9, + 0x28, + 0x50, + 0x64, + 0x14, + 0x1E, + 0x1E, + 0x1E, + {0x05, 0x04}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Graveler", + 0x27, + 0x37, + 0x5F, + 0x73, + 0x23, + 0x2D, + 0x2D, + 0x2D, + {0x05, 0x04}, + {0x21, 0x6F, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Golem", + 0x31, + 0x50, + 0x6E, + 0x82, + 0x2D, + 0x37, + 0x37, + 0x41, + {0x05, 0x04}, + {0x21, 0x6F, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Ponyta", + 0xA3, + 0x32, + 0x55, + 0x37, + 0x5A, + 0x41, + 0x41, + 0x41, + {0x14, 0x14}, + {0x34, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Rapidash", + 0xA4, + 0x41, + 0x64, + 0x46, + 0x69, + 0x50, + 0x50, + 0x50, + {0x14, 0x14}, + {0x34, 0x27, 0x17, 0x2D}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Slowpoke", + 0x25, + 0x5A, + 0x41, + 0x41, + 0x0F, + 0x28, + 0x28, + 0x28, + {0x15, 0x18}, + {0x5D, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Slowbro", + 0x08, + 0x5F, + 0x4B, + 0x6E, + 0x1E, + 0x50, + 0x64, + 0x50, + {0x15, 0x18}, + {0x5D, 0x32, 0x1D, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Magnemite", + 0xAD, + 0x19, + 0x23, + 0x46, + 0x2D, + 0x5F, + 0x5F, + 0x37, + {0x17, 0x17}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Magneton", + 0x36, + 0x32, + 0x3C, + 0x5F, + 0x46, + 0x78, + 0x78, + 0x46, + {0x17, 0x17}, + {0x21, 0x31, 0x54, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Farfetch'd", + 0x40, + 0x34, + 0x41, + 0x37, + 0x3C, + 0x3A, + 0x3A, + 0x3E, + {0x00, 0x02}, + {0x40, 0x1C, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Doduo", + 0x46, + 0x23, + 0x55, + 0x2D, + 0x4B, + 0x23, + 0x23, + 0x23, + {0x00, 0x02}, + {0x40, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Dodrio", + 0x74, + 0x3C, + 0x6E, + 0x46, + 0x64, + 0x3C, + 0x3C, + 0x3C, + {0x00, 0x02}, + {0x40, 0x2D, 0x1F, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Seel", + 0x3A, + 0x41, + 0x2D, + 0x37, + 0x2D, + 0x46, + 0x2D, + 0x46, + {0x15, 0x15}, + {0x1D, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Dewgong", + 0x78, + 0x5A, + 0x46, + 0x50, + 0x46, + 0x5F, + 0x46, + 0x5F, + {0x15, 0x19}, + {0x1D, 0x2D, 0x3E, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Grimer", + 0x0D, + 0x50, + 0x50, + 0x32, + 0x19, + 0x28, + 0x28, + 0x32, + {0x03, 0x03}, + {0x01, 0x32, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Muk", + 0x88, + 0x69, + 0x69, + 0x4B, + 0x32, + 0x41, + 0x41, + 0x64, + {0x03, 0x03}, + {0x01, 0x32, 0x8B, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Shellder", + 0x17, + 0x1E, + 0x41, + 0x64, + 0x28, + 0x2D, + 0x2D, + 0x19, + {0x15, 0x15}, + {0x21, 0x6E, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Cloyster", + 0x8B, + 0x32, + 0x5F, + 0xB4, + 0x46, + 0x55, + 0x55, + 0x2D, + {0x15, 0x19}, + {0x6E, 0x30, 0x80, 0x3E}, + GROWTH_SLOW, + GENDER_F50}, + {"Gastly", + 0x19, + 0x1E, + 0x23, + 0x1E, + 0x50, + 0x64, + 0x64, + 0x23, + {0x08, 0x03}, + {0x7A, 0x6D, 0x65, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Haunter", + 0x93, + 0x2D, + 0x32, + 0x2D, + 0x5F, + 0x73, + 0x73, + 0x37, + {0x08, 0x03}, + {0x7A, 0x6D, 0x65, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Gengar", + 0x0E, + 0x3C, + 0x41, + 0x3C, + 0x6E, + 0x82, + 0x82, + 0x4B, + {0x08, 0x03}, + {0x7A, 0x6D, 0x65, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Onix", + 0x22, + 0x23, + 0x2D, + 0xA0, + 0x46, + 0x1E, + 0x1E, + 0x2D, + {0x05, 0x04}, + {0x21, 0x67, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Drowzee", + 0x30, + 0x3C, + 0x30, + 0x2D, + 0x2A, + 0x5A, + 0x2B, + 0x5A, + {0x18, 0x18}, + {0x01, 0x5F, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Hypno", + 0x81, + 0x55, + 0x49, + 0x46, + 0x43, + 0x73, + 0x49, + 0x73, + {0x18, 0x18}, + {0x01, 0x5F, 0x32, 0x5D}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Krabby", + 0x4E, + 0x1E, + 0x69, + 0x5A, + 0x32, + 0x19, + 0x19, + 0x19, + {0x15, 0x15}, + {0x91, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Kingler", + 0x8A, + 0x37, + 0x82, + 0x73, + 0x4B, + 0x32, + 0x32, + 0x32, + {0x15, 0x15}, + {0x91, 0x2B, 0x0B, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Voltorb", + 0x06, + 0x28, + 0x1E, + 0x32, + 0x64, + 0x37, + 0x37, + 0x37, + {0x17, 0x17}, + {0x21, 0x67, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Electrode", + 0x8D, + 0x3C, + 0x32, + 0x46, + 0x8C, + 0x50, + 0x50, + 0x50, + {0x17, 0x17}, + {0x21, 0x67, 0x31, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Exeggcute", + 0x0C, + 0x3C, + 0x28, + 0x50, + 0x28, + 0x3C, + 0x3C, + 0x2D, + {0x16, 0x18}, + {0x8C, 0x5F, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Exeggutor", + 0x0A, + 0x5F, + 0x5F, + 0x55, + 0x37, + 0x7D, + 0x7D, + 0x41, + {0x16, 0x18}, + {0x8C, 0x5F, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Cubone", + 0x11, + 0x32, + 0x32, + 0x5F, + 0x23, + 0x28, + 0x28, + 0x32, + {0x04, 0x04}, + {0x7D, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Marowak", + 0x91, + 0x3C, + 0x50, + 0x6E, + 0x2D, + 0x32, + 0x32, + 0x50, + {0x04, 0x04}, + {0x7D, 0x2D, 0x2B, 0x74}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Hitmonlee", + 0x2B, + 0x32, + 0x78, + 0x35, + 0x57, + 0x23, + 0x23, + 0x6E, + {0x01, 0x01}, + {0x18, 0x60, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F0}, + {"Hitmonchan", + 0x2C, + 0x32, + 0x69, + 0x4F, + 0x4C, + 0x23, + 0x23, + 0x6E, + {0x01, 0x01}, + {0x04, 0x61, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F0}, + {"Lickitung", + 0x0B, + 0x5A, + 0x37, + 0x4B, + 0x1E, + 0x3C, + 0x3C, + 0x4B, + {0x00, 0x00}, + {0x23, 0x30, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Koffing", + 0x37, + 0x28, + 0x41, + 0x5F, + 0x23, + 0x3C, + 0x3C, + 0x2D, + {0x03, 0x03}, + {0x21, 0x7B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Weezing", + 0x8F, + 0x41, + 0x5A, + 0x78, + 0x3C, + 0x55, + 0x55, + 0x46, + {0x03, 0x03}, + {0x21, 0x7B, 0x7C, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Rhyhorn", + 0x12, + 0x50, + 0x55, + 0x5F, + 0x19, + 0x1E, + 0x1E, + 0x1E, + {0x04, 0x05}, + {0x1E, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Rhydon", + 0x01, + 0x69, + 0x82, + 0x78, + 0x28, + 0x2D, + 0x2D, + 0x2D, + {0x04, 0x05}, + {0x1E, 0x17, 0x27, 0x1F}, + GROWTH_SLOW, + GENDER_F50}, + {"Chansey", + 0x28, + 0xFA, + 0x05, + 0x05, + 0x32, + 0x69, + 0x23, + 0x69, + {0x00, 0x00}, + {0x01, 0x03, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F100}, + {"Tangela", + 0x1E, + 0x41, + 0x37, + 0x73, + 0x3C, + 0x64, + 0x64, + 0x28, + {0x16, 0x16}, + {0x84, 0x14, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Kangaskhan", + 0x02, + 0x69, + 0x5F, + 0x50, + 0x5A, + 0x28, + 0x28, + 0x50, + {0x00, 0x00}, + {0x04, 0x63, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F100}, + {"Horsea", + 0x5C, + 0x1E, + 0x28, + 0x46, + 0x3C, + 0x46, + 0x46, + 0x19, + {0x15, 0x15}, + {0x91, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Seadra", + 0x5D, + 0x37, + 0x41, + 0x5F, + 0x55, + 0x5F, + 0x5F, + 0x2D, + {0x15, 0x15}, + {0x91, 0x6C, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Goldeen", + 0x9D, + 0x2D, + 0x43, + 0x3C, + 0x3F, + 0x32, + 0x23, + 0x32, + {0x15, 0x15}, + {0x40, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Seaking", + 0x9E, + 0x50, + 0x5C, + 0x41, + 0x44, + 0x50, + 0x41, + 0x50, + {0x15, 0x15}, + {0x40, 0x27, 0x30, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Staryu", + 0x1B, + 0x1E, + 0x2D, + 0x37, + 0x55, + 0x46, + 0x46, + 0x37, + {0x15, 0x15}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Starmie", + 0x98, + 0x3C, + 0x4B, + 0x55, + 0x73, + 0x64, + 0x64, + 0x55, + {0x15, 0x18}, + {0x21, 0x37, 0x6A, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Mr.Mime", + 0x2A, + 0x28, + 0x2D, + 0x41, + 0x5A, + 0x64, + 0x64, + 0x78, + {0x18, 0x18}, + {0x5D, 0x70, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Scyther", + 0x1A, + 0x46, + 0x6E, + 0x50, + 0x69, + 0x37, + 0x37, + 0x50, + {0x07, 0x02}, + {0x62, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Jynx", + 0x48, + 0x41, + 0x32, + 0x23, + 0x5F, + 0x5F, + 0x73, + 0x5F, + {0x19, 0x18}, + {0x01, 0x8E, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F100}, + {"Electabuzz", + 0x35, + 0x41, + 0x53, + 0x39, + 0x69, + 0x55, + 0x5F, + 0x55, + {0x17, 0x17}, + {0x62, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F25}, + {"Magmar", + 0x33, + 0x41, + 0x5F, + 0x39, + 0x5D, + 0x55, + 0x64, + 0x55, + {0x14, 0x14}, + {0x34, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F25}, + {"Pinsir", + 0x1D, + 0x41, + 0x7D, + 0x64, + 0x55, + 0x37, + 0x37, + 0x46, + {0x07, 0x07}, + {0x0B, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Tauros", + 0x3C, + 0x4B, + 0x64, + 0x5F, + 0x6E, + 0x46, + 0x28, + 0x46, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F0}, + {"Magikarp", + 0x85, + 0x14, + 0x0A, + 0x37, + 0x50, + 0x14, + 0x0F, + 0x14, + {0x15, 0x15}, + {0x96, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Gyarados", + 0x16, + 0x5F, + 0x7D, + 0x4F, + 0x51, + 0x64, + 0x3C, + 0x64, + {0x15, 0x02}, + {0x2C, 0x52, 0x2B, 0x38}, + GROWTH_SLOW, + GENDER_F50}, + {"Lapras", + 0x13, + 0x82, + 0x55, + 0x50, + 0x3C, + 0x5F, + 0x55, + 0x5F, + {0x15, 0x19}, + {0x37, 0x2D, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Ditto", + 0x4C, + 0x30, + 0x30, + 0x30, + 0x30, + 0x30, + 0x30, + 0x30, + {0x00, 0x00}, + {0x90, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Eevee", + 0x66, + 0x37, + 0x37, + 0x32, + 0x37, + 0x41, + 0x2D, + 0x41, + {0x00, 0x00}, + {0x21, 0x1C, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Vaporeon", + 0x69, + 0x82, + 0x41, + 0x3C, + 0x41, + 0x6E, + 0x6E, + 0x5F, + {0x15, 0x15}, + {0x21, 0x1C, 0x62, 0x37}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Jolteon", + 0x68, + 0x41, + 0x41, + 0x3C, + 0x82, + 0x6E, + 0x6E, + 0x5F, + {0x17, 0x17}, + {0x21, 0x1C, 0x62, 0x54}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Flareon", + 0x67, + 0x41, + 0x82, + 0x3C, + 0x41, + 0x6E, + 0x5F, + 0x6E, + {0x14, 0x14}, + {0x21, 0x1C, 0x62, 0x34}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Porygon", + 0xAA, + 0x41, + 0x3C, + 0x46, + 0x28, + 0x4B, + 0x55, + 0x4B, + {0x00, 0x00}, + {0x21, 0x9F, 0xA0, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Omanyte", + 0x62, + 0x23, + 0x28, + 0x64, + 0x23, + 0x5A, + 0x5A, + 0x37, + {0x05, 0x15}, + {0x37, 0x6E, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Omastar", + 0x63, + 0x46, + 0x3C, + 0x7D, + 0x37, + 0x73, + 0x73, + 0x46, + {0x05, 0x15}, + {0x37, 0x6E, 0x1E, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Kabuto", + 0x5A, + 0x1E, + 0x50, + 0x5A, + 0x37, + 0x2D, + 0x37, + 0x2D, + {0x05, 0x15}, + {0x0A, 0x6A, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Kabutops", + 0x5B, + 0x3C, + 0x73, + 0x69, + 0x50, + 0x46, + 0x41, + 0x46, + {0x05, 0x15}, + {0x0A, 0x6A, 0x47, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Aerodactyl", + 0xAB, + 0x50, + 0x69, + 0x41, + 0x82, + 0x3C, + 0x3C, + 0x4B, + {0x05, 0x02}, + {0x11, 0x61, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F12_5}, + {"Snorlax", + 0x84, + 0xA0, + 0x6E, + 0x41, + 0x1E, + 0x41, + 0x41, + 0x6E, + {0x00, 0x00}, + {0x1D, 0x85, 0x9C, 0x00}, + GROWTH_SLOW, + GENDER_F12_5}, + {"Articuno", + 0x4A, + 0x5A, + 0x55, + 0x64, + 0x55, + 0x7D, + 0x5F, + 0x7D, + {0x19, 0x02}, + {0x40, 0x3A, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Zapdos", + 0x4B, + 0x5A, + 0x5A, + 0x55, + 0x64, + 0x7D, + 0x7D, + 0x5A, + {0x17, 0x02}, + {0x54, 0x41, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Moltres", + 0x49, + 0x5A, + 0x64, + 0x5A, + 0x5A, + 0x7D, + 0x7D, + 0x55, + {0x14, 0x02}, + {0x40, 0x53, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Dratini", + 0x58, + 0x29, + 0x40, + 0x2D, + 0x32, + 0x32, + 0x32, + 0x32, + {0x1A, 0x1A}, + {0x23, 0x2B, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Dragonair", + 0x59, + 0x3D, + 0x54, + 0x41, + 0x46, + 0x46, + 0x46, + 0x46, + {0x1A, 0x1A}, + {0x23, 0x2B, 0x56, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Dragonite", + 0x42, + 0x5B, + 0x86, + 0x5F, + 0x50, + 0x64, + 0x64, + 0x64, + {0x1A, 0x02}, + {0x23, 0x2B, 0x56, 0x61}, + GROWTH_SLOW, + GENDER_F50}, + {"Mewtwo", + 0x83, + 0x6A, + 0x6E, + 0x5A, + 0x82, + 0x9A, + 0x9A, + 0x5A, + {0x18, 0x18}, + {0x5D, 0x32, 0x81, 0x5E}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Mew", + 0x15, + 0x64, + 0x64, + 0x64, + 0x64, + 0x64, + 0x64, + 0x64, + {0x18, 0x18}, + {0x01, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_UNKNOWN}, + + /* Valueed from Gold */ + {"Chikorita", + 0x00, + 0x2D, + 0x31, + 0x41, + 0x2D, + 0x00, + 0x31, + 0x41, + {0x00, 0x00}, + {0x21, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Bayleef", + 0x00, + 0x3C, + 0x3E, + 0x50, + 0x3C, + 0x00, + 0x3F, + 0x50, + {0x00, 0x00}, + {0x21, 0x2D, 0x4B, 0x73}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Meganium", + 0x00, + 0x50, + 0x52, + 0x64, + 0x50, + 0x00, + 0x53, + 0x64, + {0x00, 0x00}, + {0x21, 0x2D, 0x4B, 0x73}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Cyndaquil", + 0x00, + 0x27, + 0x34, + 0x2B, + 0x41, + 0x00, + 0x3C, + 0x32, + {0x00, 0x00}, + {0x21, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Quilava", + 0x00, + 0x3A, + 0x40, + 0x3A, + 0x50, + 0x00, + 0x50, + 0x41, + {0x00, 0x00}, + {0x21, 0x2B, 0x6C, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Typhlosion", + 0x00, + 0x4E, + 0x54, + 0x4E, + 0x64, + 0x00, + 0x6D, + 0x55, + {0x00, 0x00}, + {0x21, 0x2B, 0x6C, 0x34}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Totodile", + 0x00, + 0x32, + 0x41, + 0x40, + 0x2B, + 0x00, + 0x2C, + 0x30, + {0x00, 0x00}, + {0x0A, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Croconaw", + 0x00, + 0x41, + 0x50, + 0x50, + 0x3A, + 0x00, + 0x3B, + 0x3F, + {0x00, 0x00}, + {0x0A, 0x2B, 0x63, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Feraligatr", + 0x00, + 0x55, + 0x69, + 0x64, + 0x4E, + 0x00, + 0x4F, + 0x53, + {0x00, 0x00}, + {0x0A, 0x2B, 0x63, 0x37}, + GROWTH_MEDIUM_SLOW, + GENDER_F12_5}, + {"Sentret", + 0x00, + 0x23, + 0x2E, + 0x22, + 0x14, + 0x00, + 0x23, + 0x2D, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Furret", + 0x00, + 0x55, + 0x4C, + 0x40, + 0x5A, + 0x00, + 0x2D, + 0x37, + {0x00, 0x00}, + {0x0A, 0x6F, 0x62, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Hoothoot", + 0x00, + 0x3C, + 0x1E, + 0x1E, + 0x32, + 0x00, + 0x24, + 0x38, + {0x00, 0x00}, + {0x21, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Noctowl", + 0x00, + 0x64, + 0x32, + 0x32, + 0x46, + 0x00, + 0x4C, + 0x60, + {0x00, 0x00}, + {0x21, 0x2D, 0xC1, 0x40}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Ledyba", + 0x00, + 0x28, + 0x14, + 0x1E, + 0x37, + 0x00, + 0x28, + 0x50, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Ledian", + 0x00, + 0x37, + 0x23, + 0x32, + 0x55, + 0x00, + 0x37, + 0x6E, + {0x00, 0x00}, + {0x21, 0x30, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Spinarak", + 0x00, + 0x28, + 0x3C, + 0x28, + 0x1E, + 0x00, + 0x28, + 0x28, + {0x00, 0x00}, + {0x28, 0x51, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Ariados", + 0x00, + 0x46, + 0x5A, + 0x46, + 0x28, + 0x00, + 0x3C, + 0x3C, + {0x00, 0x00}, + {0x28, 0x51, 0xB8, 0x84}, + GROWTH_FAST, + GENDER_F50}, + {"Crobat", + 0x00, + 0x55, + 0x5A, + 0x50, + 0x82, + 0x00, + 0x46, + 0x50, + {0x00, 0x00}, + {0x67, 0x8D, 0x30, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Chinchou", + 0x00, + 0x4B, + 0x26, + 0x26, + 0x43, + 0x00, + 0x38, + 0x38, + {0x00, 0x00}, + {0x91, 0x56, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Lanturn", + 0x00, + 0x7D, + 0x3A, + 0x3A, + 0x43, + 0x00, + 0x4C, + 0x4C, + {0x00, 0x00}, + {0x91, 0x56, 0x30, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Pichu", + 0x00, + 0x14, + 0x28, + 0x0F, + 0x3C, + 0x00, + 0x23, + 0x23, + {0x00, 0x00}, + {0x54, 0xCC, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Cleffa", + 0x00, + 0x32, + 0x19, + 0x1C, + 0x0F, + 0x00, + 0x2D, + 0x37, + {0x00, 0x00}, + {0x01, 0xCC, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Igglybuff", + 0x00, + 0x5A, + 0x1E, + 0x0F, + 0x0F, + 0x00, + 0x28, + 0x14, + {0x00, 0x00}, + {0x2F, 0xCC, 0x0E, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Togepi", + 0x00, + 0x23, + 0x14, + 0x41, + 0x14, + 0x00, + 0x28, + 0x41, + {0x00, 0x00}, + {0x2D, 0xCC, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F12_5}, + {"Togetic", + 0x00, + 0x37, + 0x28, + 0x55, + 0x28, + 0x00, + 0x50, + 0x69, + {0x00, 0x00}, + {0x2D, 0xCC, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F12_5}, + {"Natu", + 0x00, + 0x28, + 0x32, + 0x2D, + 0x46, + 0x00, + 0x46, + 0x2D, + {0x00, 0x00}, + {0x40, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Xatu", + 0x00, + 0x41, + 0x4B, + 0x46, + 0x5F, + 0x00, + 0x5F, + 0x46, + {0x00, 0x00}, + {0x40, 0x2B, 0x65, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Mareep", + 0x00, + 0x37, + 0x28, + 0x28, + 0x23, + 0x00, + 0x41, + 0x2D, + {0x00, 0x00}, + {0x21, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Flaaffy", + 0x00, + 0x46, + 0x37, + 0x37, + 0x2D, + 0x00, + 0x50, + 0x3C, + {0x00, 0x00}, + {0x21, 0x2D, 0x54, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Ampharos", + 0x00, + 0x5A, + 0x4B, + 0x4B, + 0x37, + 0x00, + 0x73, + 0x5A, + {0x00, 0x00}, + {0x21, 0x2D, 0x54, 0x56}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Bellossom", + 0x00, + 0x4B, + 0x50, + 0x55, + 0x32, + 0x00, + 0x5A, + 0x64, + {0x00, 0x00}, + {0x47, 0xE6, 0x4E, 0x50}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Marill", + 0x00, + 0x46, + 0x14, + 0x32, + 0x28, + 0x00, + 0x14, + 0x32, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Azumarill", + 0x00, + 0x64, + 0x32, + 0x50, + 0x32, + 0x00, + 0x32, + 0x50, + {0x00, 0x00}, + {0x21, 0x6F, 0x27, 0x37}, + GROWTH_FAST, + GENDER_F50}, + {"Sudowoodo", + 0x00, + 0x46, + 0x64, + 0x73, + 0x1E, + 0x00, + 0x1E, + 0x41, + {0x00, 0x00}, + {0x58, 0x66, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Politoed", + 0x00, + 0x5A, + 0x4B, + 0x4B, + 0x46, + 0x00, + 0x5A, + 0x64, + {0x00, 0x00}, + {0x37, 0x5F, 0x03, 0xC3}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Hoppip", + 0x00, + 0x23, + 0x23, + 0x28, + 0x32, + 0x00, + 0x23, + 0x37, + {0x00, 0x00}, + {0x96, 0xEB, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Skiploom", + 0x00, + 0x37, + 0x2D, + 0x32, + 0x50, + 0x00, + 0x2D, + 0x41, + {0x00, 0x00}, + {0x96, 0xEB, 0x27, 0x21}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Jumpluff", + 0x00, + 0x4B, + 0x37, + 0x46, + 0x6E, + 0x00, + 0x37, + 0x55, + {0x00, 0x00}, + {0x96, 0xEB, 0x27, 0x21}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Aipom", + 0x00, + 0x37, + 0x46, + 0x37, + 0x55, + 0x00, + 0x28, + 0x37, + {0x00, 0x00}, + {0x0A, 0x27, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Sunkern", + 0x00, + 0x1E, + 0x1E, + 0x1E, + 0x1E, + 0x00, + 0x1E, + 0x1E, + {0x00, 0x00}, + {0x47, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Sunflora", + 0x00, + 0x4B, + 0x4B, + 0x37, + 0x1E, + 0x00, + 0x69, + 0x55, + {0x00, 0x00}, + {0x47, 0x01, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Yanma", + 0x00, + 0x41, + 0x41, + 0x2D, + 0x5F, + 0x00, + 0x4B, + 0x2D, + {0x00, 0x00}, + {0x21, 0xC1, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Wooper", + 0x00, + 0x37, + 0x2D, + 0x2D, + 0x0F, + 0x00, + 0x19, + 0x19, + {0x00, 0x00}, + {0x37, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Quagsire", + 0x00, + 0x5F, + 0x55, + 0x55, + 0x23, + 0x00, + 0x41, + 0x41, + {0x00, 0x00}, + {0x37, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Espeon", + 0x00, + 0x41, + 0x41, + 0x3C, + 0x6E, + 0x00, + 0x82, + 0x5F, + {0x00, 0x00}, + {0x21, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Umbreon", + 0x00, + 0x5F, + 0x41, + 0x6E, + 0x41, + 0x00, + 0x3C, + 0x82, + {0x00, 0x00}, + {0x21, 0x27, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F12_5}, + {"Murkrow", + 0x00, + 0x3C, + 0x55, + 0x2A, + 0x5B, + 0x00, + 0x55, + 0x2A, + {0x00, 0x00}, + {0x40, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Slowking", + 0x00, + 0x5F, + 0x4B, + 0x50, + 0x1E, + 0x00, + 0x64, + 0x6E, + {0x00, 0x00}, + {0xAE, 0x21, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Misdreavus", + 0x00, + 0x3C, + 0x3C, + 0x3C, + 0x55, + 0x00, + 0x55, + 0x55, + {0x00, 0x00}, + {0x2D, 0x95, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Unown", + 0x00, + 0x30, + 0x48, + 0x30, + 0x30, + 0x00, + 0x48, + 0x30, + {0x00, 0x00}, + {0xED, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Wobbuffet", + 0x00, + 0xBE, + 0x21, + 0x3A, + 0x21, + 0x00, + 0x21, + 0x3A, + {0x00, 0x00}, + {0x44, 0xF3, 0xDB, 0xC2}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Girafarig", + 0x00, + 0x46, + 0x50, + 0x41, + 0x55, + 0x00, + 0x5A, + 0x41, + {0x00, 0x00}, + {0x21, 0x2D, 0x5D, 0x17}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Pineco", + 0x00, + 0x32, + 0x41, + 0x5A, + 0x0F, + 0x00, + 0x23, + 0x23, + {0x00, 0x00}, + {0x21, 0xB6, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Forretress", + 0x00, + 0x4B, + 0x5A, + 0x8C, + 0x28, + 0x00, + 0x3C, + 0x3C, + {0x00, 0x00}, + {0x21, 0xB6, 0x78, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Dunsparce", + 0x00, + 0x64, + 0x46, + 0x46, + 0x2D, + 0x00, + 0x41, + 0x41, + {0x00, 0x00}, + {0x63, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Gligar", + 0x00, + 0x41, + 0x4B, + 0x69, + 0x55, + 0x00, + 0x23, + 0x41, + {0x00, 0x00}, + {0x28, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Steelix", + 0x00, + 0x4B, + 0x55, + 0xC8, + 0x1E, + 0x00, + 0x37, + 0x41, + {0x00, 0x00}, + {0x21, 0x67, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Snubbull", + 0x00, + 0x3C, + 0x50, + 0x32, + 0x1E, + 0x00, + 0x28, + 0x28, + {0x00, 0x00}, + {0x21, 0xB8, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Granbull", + 0x00, + 0x5A, + 0x78, + 0x4B, + 0x2D, + 0x00, + 0x3C, + 0x3C, + {0x00, 0x00}, + {0x21, 0xB8, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Qwilfish", + 0x00, + 0x41, + 0x5F, + 0x4B, + 0x55, + 0x00, + 0x37, + 0x37, + {0x00, 0x00}, + {0x21, 0x28, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Scizor", + 0x00, + 0x46, + 0x82, + 0x64, + 0x41, + 0x00, + 0x37, + 0x50, + {0x00, 0x00}, + {0x62, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Shuckle", + 0x00, + 0x14, + 0x0A, + 0xE6, + 0x05, + 0x00, + 0x0A, + 0xE6, + {0x00, 0x00}, + {0x84, 0x6E, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Heracross", + 0x00, + 0x50, + 0x7D, + 0x4B, + 0x55, + 0x00, + 0x28, + 0x5F, + {0x00, 0x00}, + {0x21, 0x2B, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Sneasel", + 0x00, + 0x37, + 0x5F, + 0x37, + 0x73, + 0x00, + 0x23, + 0x4B, + {0x00, 0x00}, + {0x0A, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_SLOW, + GENDER_F50}, + {"Teddiursa", + 0x00, + 0x3C, + 0x50, + 0x32, + 0x28, + 0x00, + 0x32, + 0x32, + {0x00, 0x00}, + {0x0A, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Ursaring", + 0x00, + 0x5A, + 0x82, + 0x4B, + 0x37, + 0x00, + 0x4B, + 0x4B, + {0x00, 0x00}, + {0x0A, 0x2B, 0x7A, 0x9A}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Slugma", + 0x00, + 0x28, + 0x28, + 0x28, + 0x14, + 0x00, + 0x46, + 0x28, + {0x00, 0x00}, + {0x7B, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Magcargo", + 0x00, + 0x32, + 0x32, + 0x78, + 0x1E, + 0x00, + 0x50, + 0x50, + {0x00, 0x00}, + {0x7B, 0x34, 0x58, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Swinub", + 0x00, + 0x32, + 0x32, + 0x28, + 0x32, + 0x00, + 0x1E, + 0x1E, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Piloswine", + 0x00, + 0x64, + 0x64, + 0x50, + 0x32, + 0x00, + 0x3C, + 0x3C, + {0x00, 0x00}, + {0x1E, 0xB5, 0xCB, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Corsola", + 0x00, + 0x37, + 0x37, + 0x55, + 0x23, + 0x00, + 0x41, + 0x55, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F75}, + {"Remoraid", + 0x00, + 0x23, + 0x41, + 0x23, + 0x41, + 0x00, + 0x41, + 0x23, + {0x00, 0x00}, + {0x37, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Octillery", + 0x00, + 0x4B, + 0x69, + 0x4B, + 0x2D, + 0x00, + 0x69, + 0x4B, + {0x00, 0x00}, + {0x37, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Delibird", + 0x00, + 0x2D, + 0x37, + 0x2D, + 0x4B, + 0x00, + 0x41, + 0x2D, + {0x00, 0x00}, + {0xD9, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Mantine", + 0x00, + 0x41, + 0x28, + 0x46, + 0x46, + 0x00, + 0x50, + 0x8C, + {0x00, 0x00}, + {0x21, 0x91, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Skarmory", + 0x00, + 0x41, + 0x50, + 0x8C, + 0x46, + 0x00, + 0x28, + 0x46, + {0x00, 0x00}, + {0x2B, 0x40, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Houndour", + 0x00, + 0x2D, + 0x3C, + 0x1E, + 0x41, + 0x00, + 0x50, + 0x32, + {0x00, 0x00}, + {0x2B, 0x34, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Houndoom", + 0x00, + 0x4B, + 0x5A, + 0x32, + 0x5F, + 0x00, + 0x6E, + 0x50, + {0x00, 0x00}, + {0x2B, 0x34, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Kingdra", + 0x00, + 0x4B, + 0x5F, + 0x5F, + 0x55, + 0x00, + 0x5F, + 0x5F, + {0x00, 0x00}, + {0x91, 0x6C, 0x2B, 0x37}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Phanpy", + 0x00, + 0x5A, + 0x3C, + 0x3C, + 0x28, + 0x00, + 0x28, + 0x28, + {0x00, 0x00}, + {0x21, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Donphan", + 0x00, + 0x5A, + 0x78, + 0x78, + 0x32, + 0x00, + 0x3C, + 0x3C, + {0x00, 0x00}, + {0x1E, 0x2D, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F50}, + {"Porygon2", + 0x00, + 0x55, + 0x50, + 0x5A, + 0x3C, + 0x00, + 0x69, + 0x5F, + {0x00, 0x00}, + {0xB0, 0x21, 0xA0, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_UNKNOWN}, + {"Stantler", + 0x00, + 0x49, + 0x5F, + 0x3E, + 0x55, + 0x00, + 0x55, + 0x41, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Smeargle", + 0x00, + 0x37, + 0x14, + 0x23, + 0x4B, + 0x00, + 0x14, + 0x2D, + {0x00, 0x00}, + {0xA6, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F50}, + {"Tyrogue", + 0x00, + 0x23, + 0x23, + 0x23, + 0x23, + 0x00, + 0x23, + 0x23, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F0}, + {"Hitmontop", + 0x00, + 0x32, + 0x5F, + 0x5F, + 0x46, + 0x00, + 0x23, + 0x6E, + {0x00, 0x00}, + {0x1B, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F0}, + {"Smoochum", + 0x00, + 0x2D, + 0x1E, + 0x0F, + 0x41, + 0x00, + 0x55, + 0x41, + {0x00, 0x00}, + {0x01, 0x7A, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F100}, + {"Elekid", + 0x00, + 0x2D, + 0x3F, + 0x25, + 0x5F, + 0x00, + 0x41, + 0x37, + {0x00, 0x00}, + {0x62, 0x2B, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F25}, + {"Magby", + 0x00, + 0x2D, + 0x4B, + 0x25, + 0x53, + 0x00, + 0x46, + 0x37, + {0x00, 0x00}, + {0x34, 0x00, 0x00, 0x00}, + GROWTH_MEDIUM_FAST, + GENDER_F25}, + {"Miltank", + 0x00, + 0x5F, + 0x50, + 0x69, + 0x64, + 0x00, + 0x28, + 0x46, + {0x00, 0x00}, + {0x21, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F100}, + {"Blissey", + 0x00, + 0xFF, + 0x0A, + 0x0A, + 0x37, + 0x00, + 0x4B, + 0x87, + {0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00}, + GROWTH_FAST, + GENDER_F100}, + {"Raikou", + 0x00, + 0x5A, + 0x55, + 0x4B, + 0x73, + 0x00, + 0x73, + 0x64, + {0x00, 0x00}, + {0x2C, 0x2B, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Entei", + 0x00, + 0x73, + 0x73, + 0x55, + 0x64, + 0x00, + 0x5A, + 0x4B, + {0x00, 0x00}, + {0x2C, 0x2B, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Suicune", + 0x00, + 0x64, + 0x4B, + 0x73, + 0x55, + 0x00, + 0x5A, + 0x73, + {0x00, 0x00}, + {0x2C, 0x2B, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Larvitar", + 0x00, + 0x32, + 0x40, + 0x32, + 0x29, + 0x00, + 0x2D, + 0x32, + {0x00, 0x00}, + {0x2C, 0x2B, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_F50}, + {"Pupitar", + 0x00, + 0x46, + 0x54, + 0x46, + 0x33, + 0x00, + 0x41, + 0x46, + {0x00, 0x00}, + {0x2C, 0x2B, 0xC9, 0x67}, + GROWTH_SLOW, + GENDER_F50}, + {"Tyranitar", + 0x00, + 0x64, + 0x86, + 0x6E, + 0x3D, + 0x00, + 0x5F, + 0x64, + {0x00, 0x00}, + {0x2C, 0x2B, 0xC9, 0x67}, + GROWTH_SLOW, + GENDER_F50}, + {"Lugia", + 0x00, + 0x6A, + 0x5A, + 0x82, + 0x6E, + 0x00, + 0x5A, + 0x9A, + {0x00, 0x00}, + {0xB1, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Ho-Oh", + 0x00, + 0x6A, + 0x82, + 0x5A, + 0x5A, + 0x00, + 0x6E, + 0x9A, + {0x00, 0x00}, + {0xDD, 0x00, 0x00, 0x00}, + GROWTH_SLOW, + GENDER_UNKNOWN}, + {"Celebi", + 0x00, + 0x64, + 0x64, + 0x64, + 0x64, + 0x00, + 0x64, + 0x64, + {0x00, 0x00}, + {0x49, 0x5D, 0x69, 0xD7}, + GROWTH_MEDIUM_SLOW, + GENDER_UNKNOWN}, + {}, +}; + +const PokemonTable* table_pointer_get() { + return pokemon_table; +} diff --git a/pokemon_table.h b/pokemon_table.h new file mode 100644 index 00000000000..a02df1daaa6 --- /dev/null +++ b/pokemon_table.h @@ -0,0 +1,33 @@ +#ifndef __POKEMON_TABLE_H__ +#define __POKEMON_TABLE_H__ + +#include + +#include "stats.h" + +typedef enum { + GROWTH_MEDIUM_FAST = 0, + GROWTH_MEDIUM_SLOW = 3, + GROWTH_FAST = 4, + GROWTH_SLOW = 5, +} Growth; + +typedef enum { + GENDER_F0 = 0x00, + GENDER_F12_5 = 0x1F, + GENDER_F25 = 0x3F, + GENDER_F50 = 0x7F, + GENDER_F75 = 0xBF, + GENDER_F100 = 0xFE, + GENDER_UNKNOWN = 0xFF, +} Gender; + +typedef struct pokemon_data_table PokemonTable; + +int table_pokemon_pos_get(const PokemonTable* table, uint8_t index); +uint8_t + table_stat_base_get(const PokemonTable* table, uint8_t num, DataStat stat, DataStatSub which); +const char* table_stat_name_get(const PokemonTable* table, int num); +const PokemonTable* table_pointer_get(); + +#endif // __POKEMON_TABLE_H__ diff --git a/scenes/pokemon_exit_confirm.c b/scenes/pokemon_exit_confirm.c new file mode 100644 index 00000000000..a91e6ee3579 --- /dev/null +++ b/scenes/pokemon_exit_confirm.c @@ -0,0 +1,90 @@ +#include + +#include +#include "pokemon_menu.h" +#include "../pokemon_app.h" +#include "../pokemon_data.h" + +#include "../views/select_pokemon.h" +#include "../views/trade.h" + +static bool pokemon_exit_confirm_back_event_callback(void* context) { + UNUSED(context); + + return true; +} + +void pokemon_exit_confirm_dialog_callback(DialogExResult result, void* context) { + PokemonFap* pokemon_fap = context; + + scene_manager_handle_custom_event(pokemon_fap->scene_manager, result); +} + +void pokemon_exit_confirm_on_enter(void* context) { + PokemonFap* pokemon_fap = context; + DialogEx* dialog_ex = pokemon_fap->dialog_ex; + + // Clean view + dialog_ex_reset(pokemon_fap->dialog_ex); + + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_header(dialog_ex, "Exit to Main Menu?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, + "Current configuration and/or\ntrade status will be lost!", + 64, + 12, + AlignCenter, + AlignTop); + dialog_ex_set_icon(dialog_ex, 44, 32, &I_surprised_pika); + dialog_ex_set_context(dialog_ex, pokemon_fap); + dialog_ex_set_result_callback(dialog_ex, pokemon_exit_confirm_dialog_callback); + + /* Disable the existing navigation event handler to prevent handling further + * back events. Going back to the main menu as well as going back to the + * gen menu will re-enable the proper navigation handler. + */ + view_dispatcher_set_navigation_event_callback( + pokemon_fap->view_dispatcher, pokemon_exit_confirm_back_event_callback); + + view_dispatcher_add_view( + pokemon_fap->view_dispatcher, AppViewOpts, dialog_ex_get_view(pokemon_fap->dialog_ex)); + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); +} + +bool pokemon_exit_confirm_on_event(void* context, SceneManagerEvent event) { + PokemonFap* pokemon_fap = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + consumed = scene_manager_previous_scene(pokemon_fap->scene_manager); + } else if(event.event == DialogExResultLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + pokemon_fap->scene_manager, MainMenuScene); + /* NOTE: The above should never fail */ + furi_check(consumed); + + /* NOTE: The following might need to change when adding more + * feature support. + */ + /* Clean up PokemonData */ + pokemon_data_free(pokemon_fap->pdata); + + // Free views + /* These each remove themselves from the view_dispatcher */ + select_pokemon_free( + pokemon_fap->view_dispatcher, AppViewSelectPokemon, pokemon_fap->select); + trade_free(pokemon_fap->view_dispatcher, AppViewTrade, pokemon_fap->trade); + + pokemon_fap->pdata = NULL; + pokemon_fap->select = NULL; + pokemon_fap->trade = NULL; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} diff --git a/scenes/pokemon_exit_confirm.h b/scenes/pokemon_exit_confirm.h new file mode 100644 index 00000000000..e0904613756 --- /dev/null +++ b/scenes/pokemon_exit_confirm.h @@ -0,0 +1,15 @@ +#ifndef __POKEMON_EXIT_CONFIRM_H__ +#define __POKEMON_EXIT_CONFIRM_H__ + +#pragma once + +#include +#include + +void pokemon_exit_confirm_dialog_callback(DialogExResult result, void* context); + +void pokemon_exit_confirm_on_enter(void* context); + +bool pokemon_exit_confirm_on_event(void* context, SceneManagerEvent event); + +#endif // __POKEMON_EXIT_CONFIRM_H__ diff --git a/scenes/pokemon_gen.c b/scenes/pokemon_gen.c new file mode 100644 index 00000000000..65d1ab6491a --- /dev/null +++ b/scenes/pokemon_gen.c @@ -0,0 +1,232 @@ +#include "../pokemon_app.h" +#include "../pokemon_data.h" +#include "../pokemon_char_encode.h" + +#include + +#include "../views/trade.h" +#include "../views/select_pokemon.h" + +#include "pokemon_menu.h" +#include "pokemon_stats.h" +#include "pokemon_shiny.h" +#include "pokemon_gender.h" +#include "pokemon_pokerus.h" +#include "unown_form.h" + +static void scene_change_from_main_cb(void* context, uint32_t index) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + /* Reuse of scenes to allow for using the same functions to set names */ + switch(index) { + case SelectNicknameScene: + case SelectOTNameScene: + case SelectUnownFormScene: + scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectNicknameScene, index); + break; + case SelectLevelScene: + case SelectOTIDScene: + scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectLevelScene, index); + break; + case SelectGenderScene: + if(select_gender_is_static( + pokemon_fap->pdata, + table_stat_base_get( + pokemon_fap->pdata->pokemon_table, + pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE), + STAT_BASE_GENDER_RATIO, + NONE))) + return; + break; + } + + /* Set the navigation handler back to the basic one in the main menu. We only + * want gen_back_event_callback from this menu as going back from the gen menu + * means we need to free pdata. + */ + view_dispatcher_set_navigation_event_callback( + pokemon_fap->view_dispatcher, main_menu_back_event_callback); + + /* Set scene state to the current index so we can have that element highlighted when + * we return. + */ + scene_manager_set_scene_state(pokemon_fap->scene_manager, GenITradeScene, index); + scene_manager_next_scene(pokemon_fap->scene_manager, index); +} + +bool gen_back_event_callback(void* context) { + furi_assert(context); + PokemonFap* pokemon_fap = context; + + scene_manager_next_scene(pokemon_fap->scene_manager, ConfirmExitScene); + return true; +} + +void gen_scene_on_enter(void* context) { + char buf[32]; + char name_buf[11]; // All name buffers are 11 bytes at most, including term + PokemonFap* pokemon_fap = (PokemonFap*)context; + int pkmn_num; + uint32_t state; + + // Set up trade party struct + if(!pokemon_fap->pdata) { + state = scene_manager_get_scene_state(pokemon_fap->scene_manager, GenITradeScene); + switch(state) { + case GenITradeScene: + state = GEN_I; + break; + case GenIITradeScene: + state = GEN_II; + break; + default: + state = 0; + break; + } + pokemon_fap->pdata = pokemon_data_alloc(state); + + /* Clear the scene state as this is the first entry in to this scene + * we definitely want to be completely reset. + */ + scene_manager_set_scene_state(pokemon_fap->scene_manager, GenITradeScene, 0); + + /* Allocate select and trade views */ + /* Allocates its own view and adds it to the main view_dispatcher */ + pokemon_fap->select = select_pokemon_alloc( + pokemon_fap->pdata, + pokemon_fap->view_dispatcher, + pokemon_fap->scene_manager, + AppViewSelectPokemon); + + // Trade View + /* Allocates its own view and adds it to the main view_dispatcher */ + pokemon_fap->trade = trade_alloc( + pokemon_fap->pdata, &pokemon_fap->pins, pokemon_fap->view_dispatcher, AppViewTrade); + } + + pkmn_num = pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE); + + /* Clear the scene state of the Move scene since that is used to set the + * highlighted menu item. + * This could be done in move, but move would need its own custom exit handler + * which is fine but would just waste a few more bytes compared to us handling + * it here. + */ + scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectMoveScene, 0); + scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectItemSetScene, 0); + + submenu_reset(pokemon_fap->submenu); + + snprintf( + buf, + sizeof(buf), + "Pokemon: %s", + table_stat_name_get(pokemon_fap->pdata->pokemon_table, pkmn_num)); + submenu_add_item( + pokemon_fap->submenu, buf, SelectPokemonScene, scene_change_from_main_cb, pokemon_fap); + + pokemon_name_get(pokemon_fap->pdata, STAT_NICKNAME, name_buf, sizeof(name_buf)); + snprintf(buf, sizeof(buf), "Nickname: %s", name_buf); + submenu_add_item( + pokemon_fap->submenu, buf, SelectNicknameScene, scene_change_from_main_cb, pokemon_fap); + + snprintf( + buf, + sizeof(buf), + "Level: %d", + pokemon_stat_get(pokemon_fap->pdata, STAT_LEVEL, NONE)); + submenu_add_item( + pokemon_fap->submenu, buf, SelectLevelScene, scene_change_from_main_cb, pokemon_fap); + + if(pokemon_fap->pdata->gen == GEN_II) { + snprintf( + buf, + sizeof(buf), + "Held Item: %s", + namedlist_name_get_index( + pokemon_fap->pdata->item_list, + pokemon_stat_get(pokemon_fap->pdata, STAT_HELD_ITEM, NONE))); + submenu_add_item( + pokemon_fap->submenu, buf, SelectItemScene, scene_change_from_main_cb, pokemon_fap); + } + + submenu_add_item( + pokemon_fap->submenu, + "Select Moves", + SelectMoveScene, + scene_change_from_main_cb, + pokemon_fap); + + if(pokemon_fap->pdata->gen == GEN_I) { + submenu_add_item( + pokemon_fap->submenu, + "Select Types", + SelectTypeScene, + scene_change_from_main_cb, + pokemon_fap); + } + + submenu_add_item( + pokemon_fap->submenu, + namedlist_name_get_index( + pokemon_fap->pdata->stat_list, pokemon_stat_get(pokemon_fap->pdata, STAT_SEL, NONE)), + SelectStatsScene, + scene_change_from_main_cb, + pokemon_fap); + + if(pokemon_fap->pdata->gen == GEN_II) { + snprintf( + buf, + sizeof(buf), + "Shiny: %s", + select_shiny_is_shiny(pokemon_fap->pdata) ? "Yes" : "No"); + submenu_add_item( + pokemon_fap->submenu, buf, SelectShinyScene, scene_change_from_main_cb, pokemon_fap); + + snprintf(buf, sizeof(buf), "Gender: %s", select_gender_get(pokemon_fap->pdata)); + submenu_add_item( + pokemon_fap->submenu, buf, SelectGenderScene, scene_change_from_main_cb, pokemon_fap); + + snprintf(buf, sizeof(buf), "Pokerus: %s", select_pokerus_status(pokemon_fap)); + submenu_add_item( + pokemon_fap->submenu, buf, SelectPokerusScene, scene_change_from_main_cb, pokemon_fap); + + if(pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE) == 0xC8) { // Unown + snprintf(buf, sizeof(buf), "Unown Form: %c", unown_form_get(pokemon_fap->pdata)); + submenu_add_item( + pokemon_fap->submenu, + buf, + SelectUnownFormScene, + scene_change_from_main_cb, + pokemon_fap); + } + } + + snprintf( + buf, + sizeof(buf), + "OT ID#: %05d", + pokemon_stat_get(pokemon_fap->pdata, STAT_OT_ID, NONE)); + submenu_add_item( + pokemon_fap->submenu, buf, SelectOTIDScene, scene_change_from_main_cb, pokemon_fap); + + pokemon_name_get(pokemon_fap->pdata, STAT_OT_NAME, name_buf, sizeof(name_buf)); + snprintf(buf, sizeof(buf), "OT Name: %s", name_buf); + submenu_add_item( + pokemon_fap->submenu, buf, SelectOTNameScene, scene_change_from_main_cb, pokemon_fap); + + submenu_add_item( + pokemon_fap->submenu, "Trade PKMN", TradeScene, scene_change_from_main_cb, pokemon_fap); + + /* TODO: Add Save pokemon option here */ + + /* HACK: No matter what gen were in, we just store the scene state in GenITradeScene */ + submenu_set_selected_item( + pokemon_fap->submenu, + scene_manager_get_scene_state(pokemon_fap->scene_manager, GenITradeScene)); + + view_dispatcher_set_navigation_event_callback( + pokemon_fap->view_dispatcher, gen_back_event_callback); + + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); +} diff --git a/scenes/pokemon_gen.h b/scenes/pokemon_gen.h new file mode 100644 index 00000000000..c1ed810d05f --- /dev/null +++ b/scenes/pokemon_gen.h @@ -0,0 +1,8 @@ +#ifndef POKEMON_GEN_H +#define POKEMON_GEN_H + +#pragma once + +void gen_scene_on_enter(void* context); + +#endif // POKEMON_GEN_H diff --git a/scenes/pokemon_gender.c b/scenes/pokemon_gender.c new file mode 100644 index 00000000000..602365746bd --- /dev/null +++ b/scenes/pokemon_gender.c @@ -0,0 +1,104 @@ +#include + +#include "../pokemon_app.h" +#include "../pokemon_data.h" +#include "pokemon_menu.h" + +static const char* gender_str[] = { + "Unknown", + "Female", + "Male", +}; + +/* This returns a string pointer if the gender is static, NULL if it is not and + * the gender needs to be calculated. + */ +const char* select_gender_is_static(PokemonData* pdata, uint8_t ratio) { + switch(ratio) { + case 0xFF: + return gender_str[0]; + case 0xFE: + return gender_str[1]; + case 0x00: + if(pokemon_stat_get(pdata, STAT_NUM, NONE) != 0xEB) { // Tyrogue can be either gender + return gender_str[2]; + } + break; + default: + break; + } + + return NULL; +} + +const char* select_gender_get(PokemonData* pdata) { + uint8_t ratio = table_stat_base_get( + pdata->pokemon_table, + pokemon_stat_get(pdata, STAT_NUM, NONE), + STAT_BASE_GENDER_RATIO, + NONE); + uint8_t atk_iv; + const char* rc; + + rc = select_gender_is_static(pdata, ratio); + if(rc) return rc; + + /* Falling through here means now we need to calculate the gender from + * its ratio and ATK_IV. + */ + atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE); + if(atk_iv * 17 <= ratio) + return gender_str[1]; + else + return gender_str[2]; +} + +static void select_gender_selected_callback(void* context, uint32_t index) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + PokemonData* pdata = pokemon_fap->pdata; + uint8_t ratio = table_stat_base_get( + pdata->pokemon_table, + pokemon_stat_get(pdata, STAT_NUM, NONE), + STAT_BASE_GENDER_RATIO, + NONE); + uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE); + + /* If we need to make the pokemon a male, increase atk IV until it exceeds + * the gender ratio. + * + * Note that, there is no checking here for impossible situations as the + * scene enter function will immediately quit if its not possible to change + * the gender (the extremes of gender_ratio value). + * + * The check for gender is a percentage, if ATK_IV*(255/15) <= the ratio, + * then the pokemon is a female. The gender ratio values end up being: + * DEF GENDER_F0 EQU 0 percent + * DEF GENDER_F12_5 EQU 12 percent + 1 + * DEF GENDER_F25 EQU 25 percent + * DEF GENDER_F50 EQU 50 percent + * DEF GENDER_F75 EQU 75 percent + * DEF GENDER_F100 EQU 100 percent - 1 + * Where percent is (255/100) + */ + if(index) { + while((atk_iv * 17) <= ratio) atk_iv++; + } else { + while((atk_iv * 17) > ratio) atk_iv--; + } + + pokemon_stat_set(pdata, STAT_ATK_IV, NONE, atk_iv); + + scene_manager_previous_scene(pokemon_fap->scene_manager); +} + +void select_gender_scene_on_enter(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + submenu_reset(pokemon_fap->submenu); + + submenu_add_item( + pokemon_fap->submenu, "Female", 0, select_gender_selected_callback, pokemon_fap); + + submenu_add_item( + pokemon_fap->submenu, "Male", 1, select_gender_selected_callback, pokemon_fap); +} diff --git a/scenes/pokemon_gender.h b/scenes/pokemon_gender.h new file mode 100644 index 00000000000..d59755a2a4a --- /dev/null +++ b/scenes/pokemon_gender.h @@ -0,0 +1,22 @@ +#ifndef POKEMON_GENDER_H +#define POKEMON_GENDER_H + +#pragma once + +/* The gender ratio is a bit value, and if the ATK_IV is less than or equal to + * the gender ratio, the gender is female. + * + * A ratio of 0xff means gender is unknown. + * A ratio of 0x00 is annoyingly special. It either means that pokemon can be + * male only -OR- there is a very small chance the pokemon is female. The + * male only pokemon need to be specifically checked for. + */ + +const char* select_gender_is_static(PokemonData* pdata, uint8_t ratio); + +/* This will return a pointer to a string of the pokemon's current gender */ +char* select_gender_get(PokemonData* pdata); + +void select_gender_scene_on_enter(void* context); + +#endif // POKEMON_GENDER_H diff --git a/scenes/pokemon_item.c b/scenes/pokemon_item.c new file mode 100644 index 00000000000..45afbb428c1 --- /dev/null +++ b/scenes/pokemon_item.c @@ -0,0 +1,94 @@ +#include +#include +#include + +#include + +#include "../pokemon_app.h" +#include "../pokemon_data.h" +#include "pokemon_menu.h" + +static void select_item_selected_callback(void* context, uint32_t index) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + uint32_t item = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectItemSetScene); + + pokemon_stat_set(pokemon_fap->pdata, STAT_HELD_ITEM, item, index); + + FURI_LOG_D( + TAG, + "[item] Set item %s", + namedlist_name_get_index( + pokemon_fap->pdata->item_list, + pokemon_stat_get(pokemon_fap->pdata, STAT_HELD_ITEM, item))); + + /* Move back to Gen menu. This assumes this submenu is only ever used in Gen II */ + scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, GenIITradeScene); +} + +static void select_item_index_callback(void* context, uint32_t index) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + /* Move to next scene */ + scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectItemSetScene, index); + scene_manager_next_scene(pokemon_fap->scene_manager, SelectItemSetScene); +} + +void select_item_scene_on_enter(void* context) { + furi_assert(context); + PokemonFap* pokemon_fap = (PokemonFap*)context; + int i; + const char* name; + char letter[2] = {'\0'}; + + submenu_reset(pokemon_fap->submenu); + + /* The item list should always start with No Item, put that at the start + * for quick access. + */ + submenu_add_item( + pokemon_fap->submenu, + namedlist_name_get_index(pokemon_fap->pdata->item_list, 0), + 0, + select_item_selected_callback, + pokemon_fap); + + for(i = 1;; i++) { + name = namedlist_name_get_pos(pokemon_fap->pdata->item_list, i); + if(name == NULL) break; + if(name[0] != letter[0]) { + letter[0] = name[0]; + submenu_add_item( + pokemon_fap->submenu, letter, letter[0], select_item_index_callback, pokemon_fap); + } + } + + submenu_set_selected_item( + pokemon_fap->submenu, + scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectItemSetScene)); + scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectItemSetScene, 0); +} + +void select_item_set_scene_on_enter(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + int i; + const char* name; + char letter = + (char)scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectItemSetScene); + + /* Populate submenu with all items that start with `letter` */ + /* NOTE! Start with pos of 1 in the item list since 0 should always be no item! */ + submenu_reset(pokemon_fap->submenu); + for(i = 1;; i++) { + name = namedlist_name_get_pos(pokemon_fap->pdata->item_list, i); + if(name == NULL) break; + if(name[0] == letter && + (pokemon_fap->pdata->gen & namedlist_gen_get_pos(pokemon_fap->pdata->item_list, i))) { + submenu_add_item( + pokemon_fap->submenu, + name, + namedlist_index_get(pokemon_fap->pdata->item_list, i), + select_item_selected_callback, + pokemon_fap); + } + } +} diff --git a/scenes/pokemon_item.h b/scenes/pokemon_item.h new file mode 100644 index 00000000000..a888bb1490d --- /dev/null +++ b/scenes/pokemon_item.h @@ -0,0 +1,10 @@ +#ifndef POKEMON_ITEM_H +#define POKEMON_ITEM_H + +#pragma once + +void select_item_scene_on_enter(void* context); + +void select_item_set_scene_on_enter(void* context); + +#endif // POKEMON_ITEM_H diff --git a/scenes/pokemon_level.c b/scenes/pokemon_level.c deleted file mode 100644 index c53f6d5bb07..00000000000 --- a/scenes/pokemon_level.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -#include "../pokemon_app.h" -#include "pokemon_menu.h" - -static char level_buf[4]; - -static bool select_level_input_validator(const char* text, FuriString* error, void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - int level_val; - bool rc = true; - - level_val = atoi(text); - if(level_val < 2 || level_val > 100) { - furi_string_printf(error, "Level must\nbe a number\nbetween\n2-100!\n"); - rc = false; - } else { - pokemon_fap->trade_block->party[0].level = level_val; - pokemon_fap->trade_block->party[0].level_again = level_val; - } - - return rc; -} - -static void select_level_input_callback(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - /* Recalculate all stats from updated level */ - pokemon_trade_block_recalculate_stats_from_level(pokemon_fap); - scene_manager_previous_scene(pokemon_fap->scene_manager); -} - -void select_level_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); -} - -void select_level_scene_on_enter(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - text_input_reset(pokemon_fap->text_input); - text_input_set_validator(pokemon_fap->text_input, select_level_input_validator, pokemon_fap); - text_input_set_result_callback( - pokemon_fap->text_input, - select_level_input_callback, - pokemon_fap, - level_buf, - sizeof(level_buf), - true); - text_input_set_header_text(pokemon_fap->text_input, "Enter level (numbers only):"); - - view_dispatcher_add_view( - pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input)); - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); -} diff --git a/scenes/pokemon_level.h b/scenes/pokemon_level.h deleted file mode 100644 index f4bec0e7f22..00000000000 --- a/scenes/pokemon_level.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef POKEMON_LEVEL_H -#define POKEMON_LEVEL_H - -#pragma once - -void select_level_scene_on_enter(void* context); -void select_level_scene_on_exit(void* context); - -#endif // POKEMON_LEVEL_H diff --git a/scenes/pokemon_menu.c b/scenes/pokemon_menu.c index 9070e0b8e0f..64c7b2b1927 100644 --- a/scenes/pokemon_menu.c +++ b/scenes/pokemon_menu.c @@ -1,21 +1,31 @@ #include "../pokemon_app.h" +#include "../pokemon_data.h" #include "../pokemon_char_encode.h" #include "pokemon_menu.h" +#include "pokemon_gen.h" #include "pokemon_select.h" -#include "pokemon_nickname.h" -#include "pokemon_level.h" +#include "pokemon_name_input.h" +#include "pokemon_number_input.h" #include "pokemon_move.h" +#include "pokemon_item.h" #include "pokemon_type.h" #include "pokemon_stats.h" -#include "pokemon_ot_id.h" -#include "pokemon_ot_name.h" +#include "pokemon_shiny.h" +#include "pokemon_gender.h" +#include "pokemon_pokerus.h" #include "pokemon_trade.h" #include "pokemon_pins.h" +#include "pokemon_exit_confirm.h" static void scene_change_from_main_cb(void* context, uint32_t index) { PokemonFap* pokemon_fap = (PokemonFap*)context; + /* The same trade scene is used for both gen i and ii. Set the real index to + * scene's state. + */ + scene_manager_set_scene_state(pokemon_fap->scene_manager, GenITradeScene, index); + /* Set scene state to the current index so we can have that element highlighted when * we return. */ @@ -30,75 +40,26 @@ bool main_menu_back_event_callback(void* context) { } void main_menu_scene_on_enter(void* context) { - char buf[32]; - char name_buf[11]; // All name buffers are 11 bytes at most, including term PokemonFap* pokemon_fap = (PokemonFap*)context; - /* Clear the scene state of the Move scene since that is used to set the - * highlighted meny item. - */ - scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectMoveScene, 0); - - /* HACK: Since we may have come from trade view, we cannot assume that - * pokemon_fap->curr_pokemon is correct. - * The proper way to do this would be to instead of tracking curr_pokemon - * separately, have it always be derived fro the current trade_block. - */ - pokemon_fap->curr_pokemon = pokemon_table_get_num_from_index( - pokemon_fap->pokemon_table, pokemon_fap->trade_block->party_members[0]); - submenu_reset(pokemon_fap->submenu); + submenu_set_header(pokemon_fap->submenu, "Pokemon Trade Tool"); - snprintf( - buf, - sizeof(buf), - "Pokemon: %s", - pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].name); - submenu_add_item( - pokemon_fap->submenu, buf, SelectPokemonScene, scene_change_from_main_cb, pokemon_fap); - pokemon_encoded_array_to_str( - name_buf, (uint8_t*)pokemon_fap->trade_block->nickname, sizeof(name_buf)); - snprintf(buf, sizeof(buf), "Nickname: %s", name_buf); - submenu_add_item( - pokemon_fap->submenu, buf, SelectNicknameScene, scene_change_from_main_cb, pokemon_fap); - snprintf(buf, sizeof(buf), "Level: %d", pokemon_fap->trade_block->party[0].level); - submenu_add_item( - pokemon_fap->submenu, buf, SelectLevelScene, scene_change_from_main_cb, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, - "Select Moves", - SelectMoveScene, - scene_change_from_main_cb, - pokemon_fap); submenu_add_item( pokemon_fap->submenu, - "Select Types", - SelectTypeScene, + "Gen I (R/B/Y non-JPN)", + GenITradeScene, scene_change_from_main_cb, pokemon_fap); submenu_add_item( pokemon_fap->submenu, - stats_text[pokemon_fap->curr_stats], - SelectStatsScene, + "Gen II (G/S/C non-JPN)", + GenIITradeScene, scene_change_from_main_cb, pokemon_fap); - snprintf( - buf, - sizeof(buf), - "OT ID#: %05d", - __builtin_bswap16(pokemon_fap->trade_block->party[0].ot_id)); - submenu_add_item( - pokemon_fap->submenu, buf, SelectOTIDScene, scene_change_from_main_cb, pokemon_fap); - pokemon_encoded_array_to_str( - name_buf, (uint8_t*)pokemon_fap->trade_block->ot_name, sizeof(name_buf)); - snprintf(buf, sizeof(buf), "OT Name: %s", name_buf); - submenu_add_item( - pokemon_fap->submenu, buf, SelectOTNameScene, scene_change_from_main_cb, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, "Trade PKMN", TradeScene, scene_change_from_main_cb, pokemon_fap); submenu_add_item( pokemon_fap->submenu, - "Select Pinout", + "Select EXT Pinout", SelectPinsScene, scene_change_from_main_cb, pokemon_fap); @@ -109,6 +70,7 @@ void main_menu_scene_on_enter(void* context) { view_dispatcher_set_navigation_event_callback( pokemon_fap->view_dispatcher, main_menu_back_event_callback); + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); } @@ -122,52 +84,86 @@ void null_scene_on_exit(void* context) { UNUSED(context); } +void generic_scene_on_exit(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); + view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); +} + void (*const pokemon_scene_on_enter_handlers[])(void*) = { - main_menu_scene_on_enter, - select_pokemon_scene_on_enter, - select_nickname_scene_on_enter, - select_level_scene_on_enter, - select_move_scene_on_enter, - select_move_index_scene_on_enter, - select_move_set_scene_on_enter, - select_type_scene_on_enter, - select_stats_scene_on_enter, - select_ot_id_scene_on_enter, - select_ot_name_scene_on_enter, - trade_scene_on_enter, - select_pins_scene_on_enter, + main_menu_scene_on_enter, //MainMenuScene, + gen_scene_on_enter, //GenITradeScene, + gen_scene_on_enter, //GenIITradeScene, + select_pokemon_scene_on_enter, //SelectPokemonScene, + select_name_scene_on_enter, //SelectNicknameScene, + select_number_scene_on_enter, //SelectLevelScene, + select_move_scene_on_enter, //SelectMoveScene, + select_move_index_scene_on_enter, //SelectMoveIndexScene, + select_move_set_scene_on_enter, //SelectMoveSetScene, + select_item_scene_on_enter, //SelectItemScene, + select_item_set_scene_on_enter, //SelectItemSetScene, + select_type_scene_on_enter, //SelectTypeScene, + select_stats_scene_on_enter, //SelectStatsScene, + select_shiny_scene_on_enter, //SelectShinyScene, + select_gender_scene_on_enter, //SelectGenderScene, + select_pokerus_scene_on_enter, //SelectPokerusScene, + select_name_scene_on_enter, //SelectUnownFormScene, + select_number_scene_on_enter, //SelectOTIDScene, + select_name_scene_on_enter, //SelectOTNameScene, + trade_scene_on_enter, //TradeScene, + select_pins_scene_on_enter, //SelectPinsScene, + pokemon_exit_confirm_on_enter, //ConfirmExitScene, }; void (*const pokemon_scene_on_exit_handlers[])(void*) = { - null_scene_on_exit, - select_pokemon_scene_on_exit, - select_nickname_scene_on_exit, - select_level_scene_on_exit, - null_scene_on_exit, - null_scene_on_exit, - null_scene_on_exit, - select_type_scene_on_exit, - null_scene_on_exit, - select_ot_id_scene_on_exit, - select_ot_name_scene_on_exit, - null_scene_on_exit, - select_pins_scene_on_exit, + null_scene_on_exit, //MainMenuScene, + null_scene_on_exit, //GenITradeScene, + null_scene_on_exit, //GenIITradeScene, + null_scene_on_exit, //SelectPokemonScene, + generic_scene_on_exit, //SelectNicknameScene, + generic_scene_on_exit, //SelectLevelScene, + null_scene_on_exit, //SelectMoveScene, + null_scene_on_exit, //SelectMoveIndexScene, + null_scene_on_exit, //SelectMoveSetScene, + null_scene_on_exit, //SelectItemScene, + null_scene_on_exit, //SelectItemSetScene, + generic_scene_on_exit, //SelectTypeScene, + null_scene_on_exit, //SelectStatsScene, + null_scene_on_exit, //SelectShinyScene, + null_scene_on_exit, //SelectGenderScene, + generic_scene_on_exit, //SelectPokerusScene, + generic_scene_on_exit, //SelectUnownFormScene, + generic_scene_on_exit, //SelectOTIDScene, + generic_scene_on_exit, //SelectOTNameScene, + null_scene_on_exit, //TradeScene, + generic_scene_on_exit, //SelectPinsScene, + generic_scene_on_exit, //ConfirmExitScene, }; bool (*const pokemon_scene_on_event_handlers[])(void*, SceneManagerEvent) = { - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, - null_scene_on_event, + null_scene_on_event, //MainMenuScene, + null_scene_on_event, //GenITradeScene, + null_scene_on_event, //GenIITradeScene, + null_scene_on_event, //SelectPokemonScene, + null_scene_on_event, //SelectNicknameScene, + null_scene_on_event, //SelectLevelScene, + null_scene_on_event, //SelectMoveScene, + null_scene_on_event, //SelectMoveIndexScene, + null_scene_on_event, //SelectMoveSetScene, + null_scene_on_event, //SelectItemScene, + null_scene_on_event, //SelectItemSetScene, + null_scene_on_event, //SelectTypeScene, + null_scene_on_event, //SelectStatsScene, + null_scene_on_event, //SelectShinyScene, + null_scene_on_event, //SelectGenderScene, + null_scene_on_event, //SelectPokerusScene, + null_scene_on_event, //SelectUnownFormScene, + null_scene_on_event, //SelectOTIDScene, + null_scene_on_event, //SelectOTNameScene, + null_scene_on_event, //TradeScene, + null_scene_on_event, //SelectPinsScene, + pokemon_exit_confirm_on_event, //ConfirmExitScene, }; const SceneManagerHandlers pokemon_scene_manager_handlers = { diff --git a/scenes/pokemon_menu.h b/scenes/pokemon_menu.h index b4f6223d9bc..6fc636a2f9f 100644 --- a/scenes/pokemon_menu.h +++ b/scenes/pokemon_menu.h @@ -7,21 +7,32 @@ typedef enum { MainMenuScene, + GenITradeScene, // Formerly main menu scene + GenIITradeScene, SelectPokemonScene, SelectNicknameScene, SelectLevelScene, SelectMoveScene, SelectMoveIndexScene, SelectMoveSetScene, + SelectItemScene, + SelectItemSetScene, SelectTypeScene, SelectStatsScene, + SelectShinyScene, + SelectGenderScene, + SelectPokerusScene, + SelectUnownFormScene, SelectOTIDScene, SelectOTNameScene, TradeScene, SelectPinsScene, + ConfirmExitScene, SceneCount, } AppScene; extern const SceneManagerHandlers pokemon_scene_manager_handlers; +bool main_menu_back_event_callback(void* context); + #endif // POKEMON_MENU_H diff --git a/scenes/pokemon_move.c b/scenes/pokemon_move.c index a43241aea0f..272cb0a9982 100644 --- a/scenes/pokemon_move.c +++ b/scenes/pokemon_move.c @@ -2,24 +2,31 @@ #include #include +#include + #include "../pokemon_app.h" +#include "../pokemon_data.h" #include "pokemon_menu.h" static void select_move_selected_callback(void* context, uint32_t index) { PokemonFap* pokemon_fap = (PokemonFap*)context; uint32_t move = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveScene); + uint8_t num = pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE); if(index == UINT32_MAX) { - pokemon_fap->trade_block->party[0].move[move] = - pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].move[move]; + pokemon_stat_set( + pokemon_fap->pdata, + STAT_MOVE, + move, + table_stat_base_get(pokemon_fap->pdata->pokemon_table, num, STAT_MOVE, move)); } else { - pokemon_fap->trade_block->party[0].move[move] = (uint8_t)index; + pokemon_stat_set(pokemon_fap->pdata, STAT_MOVE, move, index); } FURI_LOG_D( TAG, "[move] Set move %s to %d", - pokemon_named_list_get_name_from_index( - pokemon_fap->move_list, pokemon_fap->trade_block->party[0].move[move]), + namedlist_name_get_index( + pokemon_fap->pdata->move_list, pokemon_stat_get(pokemon_fap->pdata, STAT_MOVE, move)), (int)move); /* Move back to move menu */ @@ -45,36 +52,24 @@ static void select_move_number_callback(void* context, uint32_t index) { } void select_move_scene_on_enter(void* context) { + furi_assert(context); PokemonFap* pokemon_fap = (PokemonFap*)context; - uint8_t* pkmn_move = pokemon_fap->trade_block->party[0].move; char buf[64]; + int i; submenu_reset(pokemon_fap->submenu); - snprintf( - buf, - sizeof(buf), - "Move 1: %s", - pokemon_named_list_get_name_from_index(pokemon_fap->move_list, pkmn_move[0])); - submenu_add_item(pokemon_fap->submenu, buf, 0, select_move_number_callback, pokemon_fap); - snprintf( - buf, - sizeof(buf), - "Move 2: %s", - pokemon_named_list_get_name_from_index(pokemon_fap->move_list, pkmn_move[1])); - submenu_add_item(pokemon_fap->submenu, buf, 1, select_move_number_callback, pokemon_fap); - snprintf( - buf, - sizeof(buf), - "Move 3: %s", - pokemon_named_list_get_name_from_index(pokemon_fap->move_list, pkmn_move[2])); - submenu_add_item(pokemon_fap->submenu, buf, 2, select_move_number_callback, pokemon_fap); - snprintf( - buf, - sizeof(buf), - "Move 4: %s", - pokemon_named_list_get_name_from_index(pokemon_fap->move_list, pkmn_move[3])); - submenu_add_item(pokemon_fap->submenu, buf, 3, select_move_number_callback, pokemon_fap); + for(i = 0; i < 4; i++) { + snprintf( + buf, + sizeof(buf), + "Move %d: %s", + i + 1, + namedlist_name_get_index( + pokemon_fap->pdata->move_list, + pokemon_stat_get(pokemon_fap->pdata, STAT_MOVE, i))); + submenu_add_item(pokemon_fap->submenu, buf, i, select_move_number_callback, pokemon_fap); + } /* TODO: Add a "Default all moves" item? */ @@ -91,10 +86,8 @@ void select_move_index_scene_on_enter(void* context) { int i; char letter[2] = {'\0'}; char buf[32]; - int curr_pokemon = pokemon_fap->curr_pokemon; + const char* name; uint32_t move_num = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveScene); - uint8_t default_move = pokemon_fap->pokemon_table[curr_pokemon].move[move_num]; - const NamedList* move_list = pokemon_fap->move_list; submenu_reset(pokemon_fap->submenu); /* The move list should always start with No Move, put that at the start @@ -102,8 +95,8 @@ void select_move_index_scene_on_enter(void* context) { */ submenu_add_item( pokemon_fap->submenu, - move_list[0].name, - move_list[0].index, + namedlist_name_get_index(pokemon_fap->pdata->move_list, 0), + 0, select_move_selected_callback, pokemon_fap); @@ -112,15 +105,26 @@ void select_move_index_scene_on_enter(void* context) { buf, sizeof(buf), "Default [%s]", - pokemon_named_list_get_name_from_index(pokemon_fap->move_list, default_move)); + namedlist_name_get_index( + pokemon_fap->pdata->move_list, + table_stat_base_get( + pokemon_fap->pdata->pokemon_table, + pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE), + STAT_MOVE, + move_num))); submenu_add_item( pokemon_fap->submenu, buf, UINT32_MAX, select_move_selected_callback, pokemon_fap); /* Now, walk through the list and make a submenu item for each move's starting letter */ for(i = 1;; i++) { - if(move_list[i].name == NULL) break; - if(toupper(move_list[i].name[0]) != toupper(letter[0])) { - letter[0] = toupper(move_list[i].name[0]); + name = namedlist_name_get_pos(pokemon_fap->pdata->move_list, i); + if(name == NULL) break; + /* TODO: Add check here for generation match. Currently, this will populate + * the letters that have any move associated with them, even if not for the + * generation currently being used. + */ + if(name[0] != letter[0]) { + letter[0] = name[0]; submenu_add_item( pokemon_fap->submenu, letter, letter[0], select_move_index_callback, pokemon_fap); } @@ -134,6 +138,7 @@ void select_move_index_scene_on_enter(void* context) { void select_move_set_scene_on_enter(void* context) { PokemonFap* pokemon_fap = (PokemonFap*)context; int i; + const char* name; char letter = (char)scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveIndexScene); @@ -141,14 +146,16 @@ void select_move_set_scene_on_enter(void* context) { /* NOTE! Start with index of 1 in the move list since 0 should always be no move! */ submenu_reset(pokemon_fap->submenu); for(i = 1;; i++) { - if(pokemon_fap->move_list[i].name == NULL) break; - if(toupper(pokemon_fap->move_list[i].name[0]) == toupper(letter)) { + name = namedlist_name_get_pos(pokemon_fap->pdata->move_list, i); + if(name == NULL) break; + if(name[0] == letter && + (pokemon_fap->pdata->gen & namedlist_gen_get_pos(pokemon_fap->pdata->move_list, i))) { submenu_add_item( pokemon_fap->submenu, - pokemon_fap->move_list[i].name, - pokemon_fap->move_list[i].index, + name, + namedlist_index_get(pokemon_fap->pdata->move_list, i), select_move_selected_callback, pokemon_fap); - } + }; } } diff --git a/scenes/pokemon_name_input.c b/scenes/pokemon_name_input.c new file mode 100644 index 00000000000..aa38303ed3b --- /dev/null +++ b/scenes/pokemon_name_input.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#include "../pokemon_app.h" +#include "../pokemon_data.h" +#include "../pokemon_char_encode.h" +#include "pokemon_menu.h" +#include "unown_form.h" + +static char name_buf[LEN_NAME_BUF]; + +/* NOTE: + * It would be nice if we could cleanly default to the pokemon's name as their + * name. The issue is that if you enter a blank line to text input, it does + * call this function, but returning true does nothing. However, I've found that + * if you check for the first char of the buffer being \0, you can then set the + * buffer and then return true. This has the effect of staying in the text_input + * screen, but, prepopulating the text entry with the buffer AND staying on the + * save button. + */ +static bool select_name_input_validator(const char* text, FuriString* error, void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + uint32_t state = + scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectNicknameScene); + unsigned int i; + + /* A blank field for the pokemon nickname means revert to default name */ + if(text[0] == '\0' && state == SelectNicknameScene) { + /* Get the pokemon's name and populate our buffer with it */ + /* TODO: Nidoran M/F are still a problem with this. */ + pokemon_default_nickname_set(name_buf, pokemon_fap->pdata, sizeof(name_buf)); + return true; + } + + /* Check to ensure no digits in OT name/nickname */ + for(i = 0; i < strlen(text); i++) { + if(isdigit((unsigned int)text[i])) { + furi_string_printf(error, "Name cannot\ncontain\nnumbers!"); + return false; + } + } + + /* Check for Unown setting is a character */ + if(state == SelectUnownFormScene) { + if(!isalpha((int)text[0])) { + furi_string_printf(error, "Form must\nbe a single\nletter!"); + return false; + } + } + + switch(state) { + case SelectNicknameScene: + pokemon_name_set(pokemon_fap->pdata, STAT_NICKNAME, (char*)text); + break; + case SelectOTNameScene: + pokemon_name_set(pokemon_fap->pdata, STAT_OT_NAME, (char*)text); + break; + case SelectUnownFormScene: + unown_form_set(pokemon_fap->pdata, text[0]); + break; + default: + furi_crash("Invalid scene"); + break; + } + + return true; +} + +static void select_name_input_callback(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + scene_manager_previous_scene(pokemon_fap->scene_manager); +} + +void select_name_scene_on_enter(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + uint32_t state = + scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectNicknameScene); + char* header; + int len; + DataStat stat; + + switch(state) { + case SelectNicknameScene: + header = "Nickname (none for default)"; + len = LEN_NICKNAME; + stat = STAT_NICKNAME; + break; + case SelectOTNameScene: + header = "Enter OT Name"; + len = LEN_OT_NAME; + stat = STAT_OT_NAME; + break; + case SelectUnownFormScene: + header = "Enter Unown Letter Form"; + len = 2; + stat = STAT_OT_NAME; + break; + default: + furi_crash("Name: invalid state"); + break; + } + + if(state == SelectUnownFormScene) { + /* Put the current letter in the buffer */ + name_buf[0] = unown_form_get(pokemon_fap->pdata); + name_buf[1] = '\0'; + } else { + pokemon_name_get(pokemon_fap->pdata, stat, name_buf, len); + } + + text_input_reset(pokemon_fap->text_input); + text_input_set_validator(pokemon_fap->text_input, select_name_input_validator, pokemon_fap); + text_input_set_result_callback( + pokemon_fap->text_input, select_name_input_callback, pokemon_fap, name_buf, len, true); + text_input_set_header_text(pokemon_fap->text_input, header); + + view_dispatcher_add_view( + pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input)); + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); +} diff --git a/scenes/pokemon_name_input.h b/scenes/pokemon_name_input.h new file mode 100644 index 00000000000..d505d5b618b --- /dev/null +++ b/scenes/pokemon_name_input.h @@ -0,0 +1,8 @@ +#ifndef POKEMON_NAME_H +#define POKEMON_NAME_H + +#pragma once + +void select_name_scene_on_enter(void* context); + +#endif // POKEMON_NAME_H diff --git a/scenes/pokemon_nickname.c b/scenes/pokemon_nickname.c deleted file mode 100644 index eb4d5eecd15..00000000000 --- a/scenes/pokemon_nickname.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../pokemon_app.h" -#include "../pokemon_char_encode.h" -#include "pokemon_menu.h" - -static char name_buf[11]; - -/* NOTE: - * It would be nice if we could cleanly default to the pokemon's name as their - * nickname. The issue is that if you enter a blank line to text input, it does - * call this function, but returning true does nothing. However, I've found that - * if you check for the first char of the buffer being \0, you can then set the - * buffer and then return true. This has the effect of staying in the text_input - * screen, but, prepopulating the text entry with the buffer AND staying on the - * save button. - */ -static bool select_nickname_input_validator(const char* text, FuriString* error, void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - bool rc = true; - unsigned int i; - - if(text[0] == '\0') { - /* Get the pokemon's name and populate our buffer with it */ - /* XXX: Nidoran M/F are still a problem with this. */ - pokemon_trade_block_set_default_name(name_buf, pokemon_fap, sizeof(name_buf)); - return true; - } - - for(i = 0; i < strlen(text); i++) { - if(isdigit((unsigned int)text[i])) { - furi_string_printf(error, "Name cannot\ncontain\nnumbers!"); - rc = false; - } - } - - if(rc == true) { - /* Clear existing nickname in trade block*/ - memset(pokemon_fap->trade_block->nickname, TERM_, sizeof(struct name)); - - /* Encode string to nickname */ - pokemon_str_to_encoded_array( - (uint8_t*)pokemon_fap->trade_block->nickname, (char*)text, strlen(text)); - FURI_LOG_D(TAG, "[nickname] Set nickname to %s", text); - } - - return rc; -} - -static void select_nickname_input_callback(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - scene_manager_previous_scene(pokemon_fap->scene_manager); -} - -void select_nickname_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); -} - -void select_nickname_scene_on_enter(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - text_input_reset(pokemon_fap->text_input); - text_input_set_validator( - pokemon_fap->text_input, select_nickname_input_validator, pokemon_fap); - text_input_set_result_callback( - pokemon_fap->text_input, - select_nickname_input_callback, - pokemon_fap, - name_buf, - sizeof(name_buf), - true); - text_input_set_header_text(pokemon_fap->text_input, "Nickname (none for default)"); - - view_dispatcher_add_view( - pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input)); - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); -} diff --git a/scenes/pokemon_nickname.h b/scenes/pokemon_nickname.h deleted file mode 100644 index 499af467f26..00000000000 --- a/scenes/pokemon_nickname.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef POKEMON_NICKNAME_H -#define POKEMON_NICKNAME_H - -#pragma once - -void select_nickname_scene_on_enter(void* context); -void select_nickname_scene_on_exit(void* context); - -#endif // POKEMON_NICKNAME_H diff --git a/scenes/pokemon_number_input.c b/scenes/pokemon_number_input.c new file mode 100644 index 00000000000..2d5229c2b94 --- /dev/null +++ b/scenes/pokemon_number_input.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +#include "../pokemon_app.h" +#include "../pokemon_data.h" +#include "pokemon_menu.h" + +static char number_buf[LEN_NUM_BUF]; + +static bool select_number_input_validator(const char* text, FuriString* error, void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + uint32_t state = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectLevelScene); + int number; + char* error_str; + int min; + int max; + DataStat stat; + bool rc = true; + unsigned int i; + + switch(state) { + case SelectLevelScene: + error_str = "Level must\nbe a number\nbetween\n2-100!"; + min = 2; + max = 100; + stat = STAT_LEVEL; + break; + case SelectOTIDScene: + error_str = "OT ID must\nbe between\n0-65535!"; + min = 0; + max = 65535; + stat = STAT_OT_ID; + break; + default: + return false; + } + + /* Need to check each byte to ensure is not alpha. atoi returns 0 which is + * technically a valid OTID, so we need to separately check for alpha chars. + */ + for(i = 0; i < sizeof(text); i++) { + if(!isdigit((unsigned int)text[i])) { + if(text[i] == '\0') break; + rc = false; + break; + } + } + + number = atoi(text); + if(number < min || number > max || rc == false) { + furi_string_printf(error, error_str); + rc = false; + } else { + pokemon_stat_set(pokemon_fap->pdata, stat, NONE, number); + } + + return rc; +} + +static void select_number_input_callback(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + scene_manager_previous_scene(pokemon_fap->scene_manager); +} + +void select_number_scene_on_enter(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + char* header; + uint32_t state = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectLevelScene); + int len; + DataStat stat; + + switch(state) { + case SelectLevelScene: + header = "Enter level (numbers only)"; + len = LEN_LEVEL; + stat = STAT_LEVEL; + break; + case SelectOTIDScene: + header = "Enter OT ID (numbers only)"; + len = LEN_OT_ID; + stat = STAT_OT_ID; + break; + default: + furi_crash("Num: invalid state"); + break; + } + + snprintf(number_buf, len, "%d", pokemon_stat_get(pokemon_fap->pdata, stat, NONE)); + + text_input_reset(pokemon_fap->text_input); + text_input_set_validator(pokemon_fap->text_input, select_number_input_validator, pokemon_fap); + text_input_set_result_callback( + pokemon_fap->text_input, select_number_input_callback, pokemon_fap, number_buf, len, true); + text_input_set_header_text(pokemon_fap->text_input, header); + + view_dispatcher_add_view( + pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input)); + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); +} diff --git a/scenes/pokemon_number_input.h b/scenes/pokemon_number_input.h new file mode 100644 index 00000000000..3aead24387a --- /dev/null +++ b/scenes/pokemon_number_input.h @@ -0,0 +1,8 @@ +#ifndef POKEMON_NUMBER_INPUT_H +#define POKEMON_NUMBER_INPUT_H + +#pragma once + +void select_number_scene_on_enter(void* context); + +#endif // POKEMON_NUMBER_INPUT_H diff --git a/scenes/pokemon_ot_id.c b/scenes/pokemon_ot_id.c deleted file mode 100644 index e97e82d90e7..00000000000 --- a/scenes/pokemon_ot_id.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../pokemon_app.h" -#include "pokemon_menu.h" - -static char ot_id_buf[6]; - -static bool select_ot_id_input_validator(const char* text, FuriString* error, void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - int ot_id; - uint16_t ot_id_16; - bool rc = true; - unsigned int i; - - /* Need to check each byte to ensure is not alpha. atoi returns 0 which is - * technically a valid ID, so we need to separately check for alpha chars. - */ - for(i = 0; i < sizeof(ot_id_buf); i++) { - if(!isdigit((unsigned int)text[i])) { - if(text[i] == '\0') break; - rc = false; - break; - } - } - - ot_id = atoi(text); - if(ot_id < 0 || ot_id > 65535 || rc == false) { - furi_string_printf(error, "OT ID must\nbe between\n0-65535!"); - rc = false; - } else { - ot_id_16 = __builtin_bswap16((uint16_t)ot_id); - pokemon_fap->trade_block->party[0].ot_id = ot_id_16; - } - - FURI_LOG_D(TAG, "[ot_id] Set OT ID to %05d", (uint16_t)ot_id); - - return rc; -} - -static void select_ot_id_input_callback(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - scene_manager_previous_scene(pokemon_fap->scene_manager); -} - -void select_ot_id_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); -} - -void select_ot_id_scene_on_enter(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - text_input_reset(pokemon_fap->text_input); - text_input_set_validator(pokemon_fap->text_input, select_ot_id_input_validator, pokemon_fap); - text_input_set_result_callback( - pokemon_fap->text_input, - select_ot_id_input_callback, - pokemon_fap, - ot_id_buf, - sizeof(ot_id_buf), - true); - text_input_set_header_text(pokemon_fap->text_input, "Enter OT ID (numbers only):"); - - view_dispatcher_add_view( - pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input)); - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); -} diff --git a/scenes/pokemon_ot_id.h b/scenes/pokemon_ot_id.h deleted file mode 100644 index bb5e9bfc296..00000000000 --- a/scenes/pokemon_ot_id.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef POKEMON_OT_ID_H -#define POKEMON_OT_ID_H - -#pragma once - -void select_ot_id_scene_on_enter(void* context); -void select_ot_id_scene_on_exit(void* context); - -#endif // POKEMON_OT_ID_H diff --git a/scenes/pokemon_ot_name.c b/scenes/pokemon_ot_name.c deleted file mode 100644 index 74e41cacd12..00000000000 --- a/scenes/pokemon_ot_name.c +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include -#include -#include -#include - -#include "../pokemon_app.h" -#include "../pokemon_char_encode.h" -#include "pokemon_menu.h" - -static char ot_name_buf[8]; - -static bool select_ot_name_input_validator(const char* text, FuriString* error, void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - bool rc = true; - unsigned int i; - - // OT name is 7 chars max on gen 1, so only take that and then fill the rest of the 11 bytes with term - - for(i = 0; i < sizeof(ot_name_buf); i++) { - if(isdigit((unsigned int)text[i])) { - furi_string_printf(error, "Name cannot\ncontain\nnumbers!"); - rc = false; - } - } - - if(rc == true) { - /* Clear existing OT Name in trade block*/ - memset(pokemon_fap->trade_block->ot_name, TERM_, sizeof(struct name)); - - /* Encode string to OT Name */ - pokemon_str_to_encoded_array( - (uint8_t*)pokemon_fap->trade_block->ot_name, (char*)text, strlen(text)); - FURI_LOG_D(TAG, "[ot_name] Set OT name to %s", text); - } - - return rc; -} - -static void select_ot_name_input_callback(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - scene_manager_previous_scene(pokemon_fap->scene_manager); -} - -void select_ot_name_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); -} - -void select_ot_name_scene_on_enter(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - text_input_reset(pokemon_fap->text_input); - text_input_set_validator(pokemon_fap->text_input, select_ot_name_input_validator, pokemon_fap); - text_input_set_result_callback( - pokemon_fap->text_input, - select_ot_name_input_callback, - pokemon_fap, - ot_name_buf, - sizeof(ot_name_buf), - true); - text_input_set_header_text(pokemon_fap->text_input, "Enter OT Name"); - - view_dispatcher_add_view( - pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input)); - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); -} diff --git a/scenes/pokemon_ot_name.h b/scenes/pokemon_ot_name.h deleted file mode 100644 index 26f1c418f2b..00000000000 --- a/scenes/pokemon_ot_name.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef POKEMON_OT_NAME_H -#define POKEMON_OT_NAME_H - -#pragma once - -void select_ot_name_scene_on_enter(void* context); -void select_ot_name_scene_on_exit(void* context); - -#endif // POKEMON_OT_NAME_H diff --git a/scenes/pokemon_pins.c b/scenes/pokemon_pins.c index 09e5ad31ef1..227375b3dcc 100644 --- a/scenes/pokemon_pins.c +++ b/scenes/pokemon_pins.c @@ -4,29 +4,30 @@ #include "../pokemon_app.h" #include "pokemon_menu.h" -struct named_pins { - const char* text; - const GpioPin* pin; -}; - -static const struct named_pins named_pins[] = { - {"PA7", &gpio_ext_pa7}, - {"PA6", &gpio_ext_pa6}, - {"PA4", &gpio_ext_pa4}, - {"PB3", &gpio_ext_pb3}, - {"PB2", &gpio_ext_pb2}, - {"PC3", &gpio_ext_pc3}, - {"PC1", &gpio_ext_pc1}, - {"PC0", &gpio_ext_pc0}, - {}, -}; - +/* This is a bit of a hack to save some space and not have to refactor this scene. + * We re-use the name and pin from the global gpio pin definition, but need to + * skip the two debug pins in the row of header pins. + * + * This is hard-coded, not really portable, but saves a couple hundred bytes :D + * + * In the future, the right way to do this would be to build our own table of + * non-debug pins from whatever the current platforms gpio pin definition is. + */ #define NUM_PINS 8 +static const GpioPinRecord* named_pins[NUM_PINS] = { + &gpio_pins[0], + &gpio_pins[1], + &gpio_pins[2], + &gpio_pins[3], + &gpio_pins[4], + &gpio_pins[5], + &gpio_pins[10], + &gpio_pins[11]}; /* This must match gblink's enum order */ static const char* named_groups[] = { "Original", - "Malveke", + "MLVK2.5", "Custom", "", }; @@ -47,9 +48,9 @@ static struct itemlist_builder builder = {0}; static void select_pins_rebuild_list(PokemonFap* pokemon_fap); static void select_pins_set(PokemonFap* pokemon_fap) { - pokemon_fap->pins.serin = named_pins[builder.serin_index].pin; - pokemon_fap->pins.serout = named_pins[builder.serout_index].pin; - pokemon_fap->pins.clk = named_pins[builder.clk_index].pin; + pokemon_fap->pins.serin = named_pins[builder.serin_index]->pin; + pokemon_fap->pins.serout = named_pins[builder.serout_index]->pin; + pokemon_fap->pins.clk = named_pins[builder.clk_index]->pin; } static void select_named_group_callback(VariableItem* item) { @@ -66,7 +67,7 @@ static void select_pins_serin_callback(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); PokemonFap* pokemon_fap = variable_item_get_context(item); - variable_item_set_current_value_text(item, named_pins[index].text); + variable_item_set_current_value_text(item, named_pins[index]->name); builder.serin_index = index; select_pins_rebuild_list(pokemon_fap); variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 1); @@ -76,7 +77,7 @@ static void select_pins_serout_callback(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); PokemonFap* pokemon_fap = variable_item_get_context(item); - variable_item_set_current_value_text(item, named_pins[index].text); + variable_item_set_current_value_text(item, named_pins[index]->name); builder.serout_index = index; select_pins_rebuild_list(pokemon_fap); variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 2); @@ -86,7 +87,7 @@ static void select_pins_clk_callback(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); PokemonFap* pokemon_fap = variable_item_get_context(item); - variable_item_set_current_value_text(item, named_pins[index].text); + variable_item_set_current_value_text(item, named_pins[index]->name); builder.clk_index = index; select_pins_rebuild_list(pokemon_fap); variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 3); @@ -116,9 +117,6 @@ static void select_pins_rebuild_list(PokemonFap* pokemon_fap) { break; } - /* HACK: */ - pokemon_fap->malveke_detected = builder.named_index; - select_pins_set(pokemon_fap); variable_item_list_reset(pokemon_fap->variable_item_list); @@ -136,29 +134,18 @@ static void select_pins_rebuild_list(PokemonFap* pokemon_fap) { variable_item_set_current_value_text(builder.named, named_groups[builder.named_index]); variable_item_set_current_value_index(builder.serin, (num == 1 ? 0 : builder.serin_index)); - variable_item_set_current_value_text(builder.serin, named_pins[builder.serin_index].text); + variable_item_set_current_value_text(builder.serin, named_pins[builder.serin_index]->name); variable_item_set_current_value_index(builder.serout, (num == 1 ? 0 : builder.serout_index)); - variable_item_set_current_value_text(builder.serout, named_pins[builder.serout_index].text); + variable_item_set_current_value_text(builder.serout, named_pins[builder.serout_index]->name); variable_item_set_current_value_index(builder.clk, (num == 1 ? 0 : builder.clk_index)); - variable_item_set_current_value_text(builder.clk, named_pins[builder.clk_index].text); -} - -void select_pins_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); + variable_item_set_current_value_text(builder.clk, named_pins[builder.clk_index]->name); } void select_pins_scene_on_enter(void* context) { PokemonFap* pokemon_fap = (PokemonFap*)context; - /* TODO: Figure out what defaults we should use for pins based on attached board! */ - /* HACK: */ - if(builder.named_index < 2) builder.named_index = pokemon_fap->malveke_detected; - select_pins_rebuild_list(pokemon_fap); view_dispatcher_add_view( diff --git a/scenes/pokemon_pins.h b/scenes/pokemon_pins.h index 3d1b8b4b367..7992be671b8 100644 --- a/scenes/pokemon_pins.h +++ b/scenes/pokemon_pins.h @@ -4,6 +4,5 @@ #pragma once void select_pins_scene_on_enter(void* context); -void select_pins_scene_on_exit(void* context); #endif // POKEMON_PINS_H diff --git a/scenes/pokemon_pokerus.c b/scenes/pokemon_pokerus.c new file mode 100644 index 00000000000..2cc370f4c74 --- /dev/null +++ b/scenes/pokemon_pokerus.c @@ -0,0 +1,172 @@ +#include +#include + +#include "../pokemon_app.h" +#include "pokemon_menu.h" + +static const char* pokerus_states[] = { + "Clean", + "Infected", + "Cured", + "", +}; + +static const char* strains[] = { + "None", + "A", + "B", + "C", + "D", + "", +}; + +const char* select_pokerus_status(PokemonFap* pokemon_fap) { + uint8_t pokerus; + + pokerus = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE); + + if(pokerus == 0x00) return pokerus_states[0]; + if((pokerus & 0x0f) != 0x00) return pokerus_states[1]; + return pokerus_states[2]; +} + +struct pokerus_itemlist { + VariableItem* strain; + VariableItem* days; +}; + +static struct pokerus_itemlist pokerus = {0}; +static void select_pokerus_rebuild_list(PokemonFap* pokemon_fap); + +static void select_strain_callback(VariableItem* item) { + uint8_t index = variable_item_get_current_value_index(item); + uint8_t pokerus; + PokemonFap* pokemon_fap = variable_item_get_context(item); + + /* Need to read/modify/write the existing stat */ + pokerus = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE); + pokerus &= 0x0f; + + /* Need to set the new text from the mangled index */ + variable_item_set_current_value_text(item, strains[index]); + + /* demangle the index to the value we need to set in trade struct */ + if(index == 0) + ; + else if(index == 0x01) + index = 0x04; // Map this back to the A strain + else + index--; + pokerus |= (index << 4); + if((pokerus & 0xf0) == 0x00) pokerus = 0; + pokemon_stat_set(pokemon_fap->pdata, STAT_POKERUS, NONE, pokerus); + + select_pokerus_rebuild_list(pokemon_fap); + variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 0); +} + +static void select_days_callback(VariableItem* item) { + uint8_t index = variable_item_get_current_value_index(item); + uint8_t pokerus; + PokemonFap* pokemon_fap = variable_item_get_context(item); + + /* Need to read/modify/write the existing stat */ + pokerus = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE); + pokerus &= 0xf0; + pokerus |= index; + pokemon_stat_set(pokemon_fap->pdata, STAT_POKERUS, NONE, pokerus); + + select_pokerus_rebuild_list(pokemon_fap); + variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 1); +} + +static void select_pokerus_rebuild_list(PokemonFap* pokemon_fap) { + uint8_t strain; + uint8_t days; + FuriString* daystring = NULL; + + days = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE); + strain = (days >> 4); + days &= 0x0f; + + variable_item_list_reset(pokemon_fap->variable_item_list); + + pokerus.strain = variable_item_list_add( + pokemon_fap->variable_item_list, "Strain:", 5, select_strain_callback, pokemon_fap); + pokerus.days = variable_item_list_add( + pokemon_fap->variable_item_list, + "Days remain:", + (strain == 0 ? 0 : 16), + select_days_callback, + pokemon_fap); + + /* Strain is a bit weird in that there are only 4 strains, but, a strain of + * 0 with a days remaining of 0 means the pokemon never had the pokerus. + * To combat this, we only ever set nibble values 4-7 for the 4 strains, + * with a value of 0 being specifically reserved for having never had it. + */ + /* A + * 0000 + * 0100 + * 1000 + * 1100 + * + * B + * 0001 + * 0101 + * 1001 + * 1101 + * + * C + * 0010 + * 0110 + * 1010 + * 1110 + * + * D + * 0011 + * 0111 + * 1011 + * 1111 + * + * So, if the whole thing is 0, then it should be considered "Clean" + * If the lower bits are cleared, but any of the upper bits are set, modify + * it to be equal to 0100 for our housekeeping. + * Anything else, we just clear the upper bits and are now in a known good + * state. + * + * So everything is in order, at this point, make a value of 0x04 == 0x1 "A", + * leave 0x0 as 0, and add 1 to the remaining. + * + * When setting, we need to translate this back to the above bit values. + */ + if(strain == 0) + ; + else if(((strain & 0x03) == 0) && ((strain & 0xc0) != 0)) + strain = 0x01; // This would be A + else { + strain &= 0x03; + strain++; + } + + daystring = furi_string_alloc_printf("%d", days); + + variable_item_set_current_value_index(pokerus.strain, strain); + variable_item_set_current_value_text(pokerus.strain, strains[strain]); + + variable_item_set_current_value_index(pokerus.days, (strain == 0 ? 0 : days)); + variable_item_set_current_value_text(pokerus.days, furi_string_get_cstr(daystring)); + furi_string_free(daystring); +} + +void select_pokerus_scene_on_enter(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + select_pokerus_rebuild_list(pokemon_fap); + + view_dispatcher_add_view( + pokemon_fap->view_dispatcher, + AppViewOpts, + variable_item_list_get_view(pokemon_fap->variable_item_list)); + view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts); +} diff --git a/scenes/pokemon_pokerus.h b/scenes/pokemon_pokerus.h new file mode 100644 index 00000000000..24c1eac8262 --- /dev/null +++ b/scenes/pokemon_pokerus.h @@ -0,0 +1,11 @@ +#ifndef __POKEMON_POKERUS_H__ +#define __POKEMON_POKERUS_H__ + +#include "../pokemon_app.h" + +#pragma once + +void select_pokerus_scene_on_enter(void* context); +const char* select_pokerus_status(PokemonFap* pokemon_fap); + +#endif // __POKEMON_POKERUS_H__ diff --git a/scenes/pokemon_select.c b/scenes/pokemon_select.c index c9b298640fb..001cdec0a52 100644 --- a/scenes/pokemon_select.c +++ b/scenes/pokemon_select.c @@ -7,16 +7,3 @@ void select_pokemon_scene_on_enter(void* context) { // at runtime rather than at the start of the whole application view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSelectPokemon); } - -void select_pokemon_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - /* If a new pokemon was selected, then recalculate all of the trade_block - * values for the first pokemon in the party. - */ - /* XXX: Find a way to see if exit was caused by an OK or a Back input? */ - if(pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].index != - pokemon_fap->trade_block->party[0].index) { - pokemon_trade_block_recalculate(pokemon_fap); - } -} diff --git a/scenes/pokemon_select.h b/scenes/pokemon_select.h index 62617c84b2d..199a89ac799 100644 --- a/scenes/pokemon_select.h +++ b/scenes/pokemon_select.h @@ -4,6 +4,5 @@ #pragma once void select_pokemon_scene_on_enter(void* context); -void select_pokemon_scene_on_exit(void* context); #endif // POKEMON_SELECT_H diff --git a/scenes/pokemon_shiny.c b/scenes/pokemon_shiny.c new file mode 100644 index 00000000000..cccdac5f4f0 --- /dev/null +++ b/scenes/pokemon_shiny.c @@ -0,0 +1,81 @@ +#include + +#include "../pokemon_app.h" +#include "../pokemon_data.h" + +#include "pokemon_menu.h" + +/* This just assumes gen ii for now */ +/* For a Gen II pokemon to be shiny, the following must be met: + * Spd, Def, and Spc must all be 10 + * Atk must be 2, 3, 6, 7, 10, 11, 14, or 15 + */ +bool select_shiny_is_shiny(PokemonData* pdata) { + uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE); + uint8_t def_iv = pokemon_stat_get(pdata, STAT_DEF_IV, NONE); + uint8_t spd_iv = pokemon_stat_get(pdata, STAT_SPD_IV, NONE); + uint8_t spc_iv = pokemon_stat_get(pdata, STAT_SPC_IV, NONE); + bool rc = 1; + + if(spd_iv != 10) rc = 0; + if(def_iv != 10) rc = 0; + if(spc_iv != 10) rc = 0; + switch(atk_iv) { + case 0: + case 1: + case 4: + case 5: + case 8: + case 9: + case 12: + case 13: + rc = 0; + break; + default: + break; + } + + return rc; +} + +static void select_shiny_selected_callback(void* context, uint32_t index) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + PokemonData* pdata = pokemon_fap->pdata; + + if(!index) { + do { + /* First, reset the IV to the selected stat */ + pokemon_stat_set(pdata, STAT_SEL, NONE, pokemon_stat_get(pdata, STAT_SEL, NONE)); + + /* Next, ensure the current IVs wouldn't make the pokemon shiny */ + } while(select_shiny_is_shiny(pdata)); + } else { + /* Set Def, Spd, Spc to 10 */ + pokemon_stat_set(pdata, STAT_DEF_IV, NONE, 10); + pokemon_stat_set(pdata, STAT_SPD_IV, NONE, 10); + pokemon_stat_set(pdata, STAT_SPC_IV, NONE, 10); + + /* Increase ATK IV until we hit a shiny number. Note that, this only + * affects IVs that are randomly generated, max IV will already be set + * at 15 which will make it shiny. + */ + while(!select_shiny_is_shiny(pdata)) { + pokemon_stat_set( + pdata, STAT_ATK_IV, NONE, pokemon_stat_get(pdata, STAT_ATK_IV, NONE) + 1); + } + } + + scene_manager_previous_scene(pokemon_fap->scene_manager); +} + +void select_shiny_scene_on_enter(void* context) { + PokemonFap* pokemon_fap = (PokemonFap*)context; + + submenu_reset(pokemon_fap->submenu); + + submenu_add_item( + pokemon_fap->submenu, "Shiny", 1, select_shiny_selected_callback, pokemon_fap); + + submenu_add_item( + pokemon_fap->submenu, "Not Shiny", 0, select_shiny_selected_callback, pokemon_fap); +} diff --git a/scenes/pokemon_shiny.h b/scenes/pokemon_shiny.h new file mode 100644 index 00000000000..6a01ed56b12 --- /dev/null +++ b/scenes/pokemon_shiny.h @@ -0,0 +1,9 @@ +#ifndef POKEMON_SHINY_H +#define POKEMON_SHINY_H + +#pragma once + +void select_shiny_scene_on_enter(void* context); +bool select_shiny_is_shiny(PokemonData* pdata); + +#endif // POKEMON_SHINY_H diff --git a/scenes/pokemon_stats.c b/scenes/pokemon_stats.c index 14437053a69..aa8aeed8bd8 100644 --- a/scenes/pokemon_stats.c +++ b/scenes/pokemon_stats.c @@ -1,43 +1,31 @@ #include +#include + #include "../pokemon_app.h" +#include "../pokemon_data.h" #include "pokemon_menu.h" -const char* stats_text[6] = { - "Random IV, Zero EV", - "Random IV, Max EV / Level", - "Random IV, Max EV", - "Max IV, Zero EV", - "Max IV, Max EV / Level", - "Max IV, Max EV", -}; - static void select_stats_selected_callback(void* context, uint32_t index) { PokemonFap* pokemon_fap = (PokemonFap*)context; - pokemon_fap->curr_stats = index; - - pokemon_trade_block_recalculate_stats_from_level(pokemon_fap); - - FURI_LOG_D(TAG, "[stats] Set stats to %s", stats_text[index]); + pokemon_stat_set(pokemon_fap->pdata, STAT_SEL, NONE, index); scene_manager_previous_scene(pokemon_fap->scene_manager); } void select_stats_scene_on_enter(void* context) { PokemonFap* pokemon_fap = (PokemonFap*)context; + int i; submenu_reset(pokemon_fap->submenu); - submenu_add_item( - pokemon_fap->submenu, stats_text[0], 0, select_stats_selected_callback, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, stats_text[1], 1, select_stats_selected_callback, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, stats_text[2], 2, select_stats_selected_callback, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, stats_text[3], 3, select_stats_selected_callback, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, stats_text[4], 4, select_stats_selected_callback, pokemon_fap); - submenu_add_item( - pokemon_fap->submenu, stats_text[5], 5, select_stats_selected_callback, pokemon_fap); + /* TODO: This is a magic number that this scene shouldn't need to know about */ + for(i = 0; i < 6; i++) { + submenu_add_item( + pokemon_fap->submenu, + namedlist_name_get_index(pokemon_fap->pdata->stat_list, i), + i, + select_stats_selected_callback, + pokemon_fap); + } } diff --git a/scenes/pokemon_stats.h b/scenes/pokemon_stats.h index 0b86b0463cb..2641f16e3ef 100644 --- a/scenes/pokemon_stats.h +++ b/scenes/pokemon_stats.h @@ -3,7 +3,6 @@ #pragma once -extern const char* stats_text[6]; void select_stats_scene_on_enter(void* context); #endif // POKEMON_STATS_H diff --git a/scenes/pokemon_type.c b/scenes/pokemon_type.c index 74165d85246..f91c36f9c2a 100644 --- a/scenes/pokemon_type.c +++ b/scenes/pokemon_type.c @@ -1,8 +1,22 @@ #include +#include + #include "../pokemon_app.h" +#include "../pokemon_data.h" #include "pokemon_menu.h" +struct type_cb { + DataStatSub type; + PokemonFap* pokemon_fap; +}; + +static struct type_cb type_cb[] = { + {TYPE_0, NULL}, + {TYPE_1, NULL}, + {}, +}; + /* TODO: In the future I would like to be able to set the types and then * require a "save" button to save them. This would require tracking of * the two different VariableItems in a way that I don't know how to do @@ -12,66 +26,47 @@ * an OK press or something to save both. But thats a problem for another * day. */ -static void select_type_1_callback(VariableItem* item) { - PokemonFap* pokemon_fap = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - variable_item_set_current_value_text(item, pokemon_fap->type_list[index].name); - pokemon_fap->trade_block->party[0].type[0] = pokemon_fap->type_list[index].index; - - FURI_LOG_D( - TAG, - "[type] Set type1 to %s", - pokemon_named_list_get_name_from_index( - pokemon_fap->type_list, pokemon_fap->type_list[index].index)); -} - -static void select_type_2_callback(VariableItem* item) { - PokemonFap* pokemon_fap = variable_item_get_context(item); - uint8_t index = variable_item_get_current_value_index(item); - - variable_item_set_current_value_text(item, pokemon_fap->type_list[index].name); - pokemon_fap->trade_block->party[0].type[1] = pokemon_fap->type_list[index].index; +static void select_type_callback(VariableItem* item) { + struct type_cb* context = variable_item_get_context(item); + uint8_t pos = variable_item_get_current_value_index(item); - FURI_LOG_D( - TAG, - "[type] Set type2 to %s", - pokemon_named_list_get_name_from_index( - pokemon_fap->type_list, pokemon_fap->type_list[index].index)); -} - -void select_type_scene_on_exit(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; - - view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu); - view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts); + variable_item_set_current_value_text( + item, namedlist_name_get_pos(context->pokemon_fap->pdata->type_list, pos)); + pokemon_stat_set( + context->pokemon_fap->pdata, + STAT_TYPE, + context->type, + namedlist_index_get(context->pokemon_fap->pdata->type_list, pos)); } void select_type_scene_on_enter(void* context) { PokemonFap* pokemon_fap = (PokemonFap*)context; - VariableItem* type1; - VariableItem* type2; - int curr_pokemon_type1 = pokemon_fap->trade_block->party[0].type[0]; - int curr_pokemon_type2 = pokemon_fap->trade_block->party[0].type[1]; - int num_types = pokemon_named_list_get_num_elements(pokemon_fap->type_list); - const NamedList* type_list = pokemon_fap->type_list; + VariableItem* vitype[2]; + char* strings[2] = {"Type 1:", "Type 2:"}; + int type; + int num_types = namedlist_cnt(pokemon_fap->pdata->type_list); + int pos; + int i; variable_item_list_reset(pokemon_fap->variable_item_list); - type1 = variable_item_list_add( - pokemon_fap->variable_item_list, "Type 1:", num_types, select_type_1_callback, pokemon_fap); - type2 = variable_item_list_add( - pokemon_fap->variable_item_list, "Type 2:", num_types, select_type_2_callback, pokemon_fap); + /* NOTE: 2 is a magic number, but pretty obvious */ + for(i = 0; i < 2; i++) { + type_cb[i].pokemon_fap = pokemon_fap; + type = pokemon_stat_get(pokemon_fap->pdata, STAT_TYPE, i); + pos = namedlist_pos_get(pokemon_fap->pdata->type_list, type); - variable_item_set_current_value_index( - type1, pokemon_named_list_get_list_pos_from_index(type_list, curr_pokemon_type1)); - variable_item_set_current_value_text( - type1, pokemon_named_list_get_name_from_index(type_list, curr_pokemon_type1)); + vitype[i] = variable_item_list_add( + pokemon_fap->variable_item_list, + strings[i], + num_types, + select_type_callback, + &type_cb[i]); - variable_item_set_current_value_index( - type2, pokemon_named_list_get_list_pos_from_index(type_list, curr_pokemon_type2)); - variable_item_set_current_value_text( - type2, pokemon_named_list_get_name_from_index(type_list, curr_pokemon_type2)); + variable_item_set_current_value_index(vitype[i], pos); + variable_item_set_current_value_text( + vitype[i], namedlist_name_get_pos(pokemon_fap->pdata->type_list, pos)); + } view_dispatcher_add_view( pokemon_fap->view_dispatcher, diff --git a/scenes/pokemon_type.h b/scenes/pokemon_type.h index a8f38b1c745..e361929bc65 100644 --- a/scenes/pokemon_type.h +++ b/scenes/pokemon_type.h @@ -4,6 +4,5 @@ #pragma once void select_type_scene_on_enter(void* context); -void select_type_scene_on_exit(void* context); #endif // POKEMON_TYPE_H diff --git a/scenes/unown_form.c b/scenes/unown_form.c new file mode 100644 index 00000000000..2f834d2d182 --- /dev/null +++ b/scenes/unown_form.c @@ -0,0 +1,73 @@ +#include +#include "../pokemon_data.h" + +#include "unown_form.h" + +/* This is used to get the current IVs from the trade struct. + * Unown form is calculated by taking the middle bytes of each nibble of IV, + * pressing them in order to a single byte, and dividing that by 10 (rounded + * down/floor). This will create a value from 0 to 25 that is a 1:1 mapping + * of the English alphabet and is how Unown forms are represented. + * + * C integer division truncates to 0 rather than does any proper rounding. + * + * https://bulbapedia.bulbagarden.net/wiki/Individual_values#Unown's_letter + */ +static uint8_t unown_ivs_get(PokemonData* pdata) { + furi_assert(pdata); + uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE); + uint8_t ivs_mid; + + ivs_mid = + (((ivs & 0x6000) >> 7) | ((ivs & 0x0600) >> 5) | ((ivs & 0x0060) >> 3) | + ((ivs & 0x0006) >> 1)); + + return ivs_mid; +} + +static void unown_ivs_set(PokemonData* pdata, uint8_t ivs_mid) { + furi_assert(pdata); + uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE); + + /* Clear the middle bits of each nibble */ + ivs &= ~(0x6666); + + /* Set the updated ivs_mid in to those cleared bits */ + ivs |= + (((ivs_mid & 0xC0) << 7) | ((ivs_mid & 0x30) << 5) | ((ivs_mid & 0x0C) << 3) | + ((ivs_mid & 0x03) << 1)); + pokemon_stat_set(pdata, STAT_IV, NONE, ivs); +} + +char unown_form_get(PokemonData* pdata) { + uint8_t form = unown_ivs_get(pdata); + + /* The forumula is specifically the center two bits of each IV slapped + * together and floor(/10) + */ + form /= 10; + form += 'A'; + + return form; +} + +/* Try and get to the desired form by adding/subtracting the current IVs */ +void unown_form_set(PokemonData* pdata, char letter) { + uint8_t ivs = unown_ivs_get(pdata); + uint8_t form; + + letter = toupper(letter); + furi_check(isalpha(letter)); + + while(1) { + form = ((ivs / 10) + 'A'); + if(form == letter) break; + if(form > letter) + ivs--; + else + ivs++; + } + + /* form is now the target letter, set IVs back up */ + unown_ivs_set(pdata, ivs); +} diff --git a/scenes/unown_form.h b/scenes/unown_form.h new file mode 100644 index 00000000000..e1b47ebfd0e --- /dev/null +++ b/scenes/unown_form.h @@ -0,0 +1,13 @@ +#ifndef __UNOWN_FORM_H__ +#define __UNOWN_FORM_H__ + +#pragma once + +#include "../pokemon_data.h" + +/* Returns ascii char, or 0 if unown is not the current pokemon */ +char unown_form_get(PokemonData* pdata); + +void unown_form_set(PokemonData* pdata, char letter); + +#endif // __UNOWN_FORM_H__ diff --git a/sprites/000.png b/sprites/000.png new file mode 100644 index 00000000000..807cb7562ab Binary files /dev/null and b/sprites/000.png differ diff --git a/sprites/001.png b/sprites/001.png new file mode 100644 index 00000000000..4a0192390b2 Binary files /dev/null and b/sprites/001.png differ diff --git a/sprites/002.png b/sprites/002.png new file mode 100644 index 00000000000..693ce1466d4 Binary files /dev/null and b/sprites/002.png differ diff --git a/sprites/003.png b/sprites/003.png new file mode 100644 index 00000000000..a8bbd9e4261 Binary files /dev/null and b/sprites/003.png differ diff --git a/sprites/004.png b/sprites/004.png new file mode 100644 index 00000000000..5a8654e8e6d Binary files /dev/null and b/sprites/004.png differ diff --git a/sprites/005.png b/sprites/005.png new file mode 100644 index 00000000000..bfd25ef150e Binary files /dev/null and b/sprites/005.png differ diff --git a/sprites/006.png b/sprites/006.png new file mode 100644 index 00000000000..e1330c425c6 Binary files /dev/null and b/sprites/006.png differ diff --git a/sprites/007.png b/sprites/007.png new file mode 100644 index 00000000000..e13b37d16a5 Binary files /dev/null and b/sprites/007.png differ diff --git a/sprites/008.png b/sprites/008.png new file mode 100644 index 00000000000..39c07b5d0db Binary files /dev/null and b/sprites/008.png differ diff --git a/sprites/009.png b/sprites/009.png new file mode 100644 index 00000000000..65b400edd4a Binary files /dev/null and b/sprites/009.png differ diff --git a/sprites/010.png b/sprites/010.png new file mode 100644 index 00000000000..506161a41f3 Binary files /dev/null and b/sprites/010.png differ diff --git a/sprites/011.png b/sprites/011.png new file mode 100644 index 00000000000..5a450679797 Binary files /dev/null and b/sprites/011.png differ diff --git a/sprites/012.png b/sprites/012.png new file mode 100644 index 00000000000..73ecfe581d0 Binary files /dev/null and b/sprites/012.png differ diff --git a/sprites/013.png b/sprites/013.png new file mode 100644 index 00000000000..fc5a16ff409 Binary files /dev/null and b/sprites/013.png differ diff --git a/sprites/014.png b/sprites/014.png new file mode 100644 index 00000000000..4f6522d5b99 Binary files /dev/null and b/sprites/014.png differ diff --git a/sprites/015.png b/sprites/015.png new file mode 100644 index 00000000000..35046b4a33f Binary files /dev/null and b/sprites/015.png differ diff --git a/sprites/016.png b/sprites/016.png new file mode 100644 index 00000000000..a76cb19a5d8 Binary files /dev/null and b/sprites/016.png differ diff --git a/sprites/017.png b/sprites/017.png new file mode 100644 index 00000000000..1619189c75f Binary files /dev/null and b/sprites/017.png differ diff --git a/sprites/018.png b/sprites/018.png new file mode 100644 index 00000000000..adae8ca76c9 Binary files /dev/null and b/sprites/018.png differ diff --git a/sprites/019.png b/sprites/019.png new file mode 100644 index 00000000000..ca4ed03c15c Binary files /dev/null and b/sprites/019.png differ diff --git a/sprites/020.png b/sprites/020.png new file mode 100644 index 00000000000..88962c6235f Binary files /dev/null and b/sprites/020.png differ diff --git a/sprites/021.png b/sprites/021.png new file mode 100644 index 00000000000..338afdb8d29 Binary files /dev/null and b/sprites/021.png differ diff --git a/sprites/022.png b/sprites/022.png new file mode 100644 index 00000000000..e341e026e32 Binary files /dev/null and b/sprites/022.png differ diff --git a/sprites/023.png b/sprites/023.png new file mode 100644 index 00000000000..6305aec9fde Binary files /dev/null and b/sprites/023.png differ diff --git a/sprites/024.png b/sprites/024.png new file mode 100644 index 00000000000..375601844dc Binary files /dev/null and b/sprites/024.png differ diff --git a/sprites/025.png b/sprites/025.png new file mode 100644 index 00000000000..da400940f44 Binary files /dev/null and b/sprites/025.png differ diff --git a/sprites/026.png b/sprites/026.png new file mode 100644 index 00000000000..64a34eb0c2f Binary files /dev/null and b/sprites/026.png differ diff --git a/sprites/027.png b/sprites/027.png new file mode 100644 index 00000000000..2d2e9d34552 Binary files /dev/null and b/sprites/027.png differ diff --git a/sprites/028.png b/sprites/028.png new file mode 100644 index 00000000000..a6e1ff7b340 Binary files /dev/null and b/sprites/028.png differ diff --git a/sprites/029.png b/sprites/029.png new file mode 100644 index 00000000000..37427b859fb Binary files /dev/null and b/sprites/029.png differ diff --git a/sprites/030.png b/sprites/030.png new file mode 100644 index 00000000000..9f3ae914890 Binary files /dev/null and b/sprites/030.png differ diff --git a/sprites/031.png b/sprites/031.png new file mode 100644 index 00000000000..ea35477a6ad Binary files /dev/null and b/sprites/031.png differ diff --git a/sprites/032.png b/sprites/032.png new file mode 100644 index 00000000000..2cee845ca50 Binary files /dev/null and b/sprites/032.png differ diff --git a/sprites/033.png b/sprites/033.png new file mode 100644 index 00000000000..2e5e38bdc8c Binary files /dev/null and b/sprites/033.png differ diff --git a/sprites/034.png b/sprites/034.png new file mode 100644 index 00000000000..5a525a51358 Binary files /dev/null and b/sprites/034.png differ diff --git a/sprites/035.png b/sprites/035.png new file mode 100644 index 00000000000..4cd31c39bbb Binary files /dev/null and b/sprites/035.png differ diff --git a/sprites/036.png b/sprites/036.png new file mode 100644 index 00000000000..fbfbf880b3c Binary files /dev/null and b/sprites/036.png differ diff --git a/sprites/037.png b/sprites/037.png new file mode 100644 index 00000000000..c6af98897ae Binary files /dev/null and b/sprites/037.png differ diff --git a/sprites/038.png b/sprites/038.png new file mode 100644 index 00000000000..7d81e1d060c Binary files /dev/null and b/sprites/038.png differ diff --git a/sprites/039.png b/sprites/039.png new file mode 100644 index 00000000000..c47df52ccda Binary files /dev/null and b/sprites/039.png differ diff --git a/sprites/040.png b/sprites/040.png new file mode 100644 index 00000000000..5b35a69e523 Binary files /dev/null and b/sprites/040.png differ diff --git a/sprites/041.png b/sprites/041.png new file mode 100644 index 00000000000..1cf7d04871f Binary files /dev/null and b/sprites/041.png differ diff --git a/sprites/042.png b/sprites/042.png new file mode 100644 index 00000000000..e637cc8239c Binary files /dev/null and b/sprites/042.png differ diff --git a/sprites/043.png b/sprites/043.png new file mode 100644 index 00000000000..80d34798dec Binary files /dev/null and b/sprites/043.png differ diff --git a/sprites/044.png b/sprites/044.png new file mode 100644 index 00000000000..d1663a68ef8 Binary files /dev/null and b/sprites/044.png differ diff --git a/sprites/045.png b/sprites/045.png new file mode 100644 index 00000000000..e25969acf41 Binary files /dev/null and b/sprites/045.png differ diff --git a/sprites/046.png b/sprites/046.png new file mode 100644 index 00000000000..9c697bb3cd6 Binary files /dev/null and b/sprites/046.png differ diff --git a/sprites/047.png b/sprites/047.png new file mode 100644 index 00000000000..64ac228e6fa Binary files /dev/null and b/sprites/047.png differ diff --git a/sprites/048.png b/sprites/048.png new file mode 100644 index 00000000000..93043e00dd5 Binary files /dev/null and b/sprites/048.png differ diff --git a/sprites/049.png b/sprites/049.png new file mode 100644 index 00000000000..6d4ea6a9956 Binary files /dev/null and b/sprites/049.png differ diff --git a/sprites/050.png b/sprites/050.png new file mode 100644 index 00000000000..d06b38a521e Binary files /dev/null and b/sprites/050.png differ diff --git a/sprites/051.png b/sprites/051.png new file mode 100644 index 00000000000..677fef0c617 Binary files /dev/null and b/sprites/051.png differ diff --git a/sprites/052.png b/sprites/052.png new file mode 100644 index 00000000000..bfd74349b8a Binary files /dev/null and b/sprites/052.png differ diff --git a/sprites/053.png b/sprites/053.png new file mode 100644 index 00000000000..6607eb06f32 Binary files /dev/null and b/sprites/053.png differ diff --git a/sprites/054.png b/sprites/054.png new file mode 100644 index 00000000000..573a1b7bd1d Binary files /dev/null and b/sprites/054.png differ diff --git a/sprites/055.png b/sprites/055.png new file mode 100644 index 00000000000..967aebc992b Binary files /dev/null and b/sprites/055.png differ diff --git a/sprites/056.png b/sprites/056.png new file mode 100644 index 00000000000..f91d5613e1e Binary files /dev/null and b/sprites/056.png differ diff --git a/sprites/057.png b/sprites/057.png new file mode 100644 index 00000000000..3ba1fa01f51 Binary files /dev/null and b/sprites/057.png differ diff --git a/sprites/058.png b/sprites/058.png new file mode 100644 index 00000000000..69090231593 Binary files /dev/null and b/sprites/058.png differ diff --git a/sprites/059.png b/sprites/059.png new file mode 100644 index 00000000000..4c13245964f Binary files /dev/null and b/sprites/059.png differ diff --git a/sprites/060.png b/sprites/060.png new file mode 100644 index 00000000000..c1603d467cc Binary files /dev/null and b/sprites/060.png differ diff --git a/sprites/061.png b/sprites/061.png new file mode 100644 index 00000000000..54377ff0506 Binary files /dev/null and b/sprites/061.png differ diff --git a/sprites/062.png b/sprites/062.png new file mode 100644 index 00000000000..27dad0d2bb3 Binary files /dev/null and b/sprites/062.png differ diff --git a/sprites/063.png b/sprites/063.png new file mode 100644 index 00000000000..4c772261977 Binary files /dev/null and b/sprites/063.png differ diff --git a/sprites/064.png b/sprites/064.png new file mode 100644 index 00000000000..fe4f4639ede Binary files /dev/null and b/sprites/064.png differ diff --git a/sprites/065.png b/sprites/065.png new file mode 100644 index 00000000000..9a999437658 Binary files /dev/null and b/sprites/065.png differ diff --git a/sprites/066.png b/sprites/066.png new file mode 100644 index 00000000000..54e29a92ca1 Binary files /dev/null and b/sprites/066.png differ diff --git a/sprites/067.png b/sprites/067.png new file mode 100644 index 00000000000..e560a18a0d2 Binary files /dev/null and b/sprites/067.png differ diff --git a/sprites/068.png b/sprites/068.png new file mode 100644 index 00000000000..36c9ac82087 Binary files /dev/null and b/sprites/068.png differ diff --git a/sprites/069.png b/sprites/069.png new file mode 100644 index 00000000000..aa820a9fb9a Binary files /dev/null and b/sprites/069.png differ diff --git a/sprites/070.png b/sprites/070.png new file mode 100644 index 00000000000..0e205b43137 Binary files /dev/null and b/sprites/070.png differ diff --git a/sprites/071.png b/sprites/071.png new file mode 100644 index 00000000000..476da2b4de4 Binary files /dev/null and b/sprites/071.png differ diff --git a/sprites/072.png b/sprites/072.png new file mode 100644 index 00000000000..0544f0e8bda Binary files /dev/null and b/sprites/072.png differ diff --git a/sprites/073.png b/sprites/073.png new file mode 100644 index 00000000000..19604a69e45 Binary files /dev/null and b/sprites/073.png differ diff --git a/sprites/074.png b/sprites/074.png new file mode 100644 index 00000000000..da888b7b74b Binary files /dev/null and b/sprites/074.png differ diff --git a/sprites/075.png b/sprites/075.png new file mode 100644 index 00000000000..a123a62f382 Binary files /dev/null and b/sprites/075.png differ diff --git a/sprites/076.png b/sprites/076.png new file mode 100644 index 00000000000..9db5590e581 Binary files /dev/null and b/sprites/076.png differ diff --git a/sprites/077.png b/sprites/077.png new file mode 100644 index 00000000000..d2ecc8d0d6e Binary files /dev/null and b/sprites/077.png differ diff --git a/sprites/078.png b/sprites/078.png new file mode 100644 index 00000000000..f98a31c8dfa Binary files /dev/null and b/sprites/078.png differ diff --git a/sprites/079.png b/sprites/079.png new file mode 100644 index 00000000000..43ba4a50408 Binary files /dev/null and b/sprites/079.png differ diff --git a/sprites/080.png b/sprites/080.png new file mode 100644 index 00000000000..c784e95fb5d Binary files /dev/null and b/sprites/080.png differ diff --git a/sprites/081.png b/sprites/081.png new file mode 100644 index 00000000000..dfdc58bade4 Binary files /dev/null and b/sprites/081.png differ diff --git a/sprites/082.png b/sprites/082.png new file mode 100644 index 00000000000..8b0b4d6eed0 Binary files /dev/null and b/sprites/082.png differ diff --git a/sprites/083.png b/sprites/083.png new file mode 100644 index 00000000000..6bc1389ca03 Binary files /dev/null and b/sprites/083.png differ diff --git a/sprites/084.png b/sprites/084.png new file mode 100644 index 00000000000..adb04e5f9de Binary files /dev/null and b/sprites/084.png differ diff --git a/sprites/085.png b/sprites/085.png new file mode 100644 index 00000000000..009ed4d61b2 Binary files /dev/null and b/sprites/085.png differ diff --git a/sprites/086.png b/sprites/086.png new file mode 100644 index 00000000000..64f85932ede Binary files /dev/null and b/sprites/086.png differ diff --git a/sprites/087.png b/sprites/087.png new file mode 100644 index 00000000000..07a0e785dfb Binary files /dev/null and b/sprites/087.png differ diff --git a/sprites/088.png b/sprites/088.png new file mode 100644 index 00000000000..83435dd4b33 Binary files /dev/null and b/sprites/088.png differ diff --git a/sprites/089.png b/sprites/089.png new file mode 100644 index 00000000000..12ea3b0f039 Binary files /dev/null and b/sprites/089.png differ diff --git a/sprites/090.png b/sprites/090.png new file mode 100644 index 00000000000..d1cd086e1e9 Binary files /dev/null and b/sprites/090.png differ diff --git a/sprites/091.png b/sprites/091.png new file mode 100644 index 00000000000..5b880f427be Binary files /dev/null and b/sprites/091.png differ diff --git a/sprites/092.png b/sprites/092.png new file mode 100644 index 00000000000..e44864a0444 Binary files /dev/null and b/sprites/092.png differ diff --git a/sprites/093.png b/sprites/093.png new file mode 100644 index 00000000000..70d522bff85 Binary files /dev/null and b/sprites/093.png differ diff --git a/sprites/094.png b/sprites/094.png new file mode 100644 index 00000000000..302ffbcd93a Binary files /dev/null and b/sprites/094.png differ diff --git a/sprites/095.png b/sprites/095.png new file mode 100644 index 00000000000..28d9737c58c Binary files /dev/null and b/sprites/095.png differ diff --git a/sprites/096.png b/sprites/096.png new file mode 100644 index 00000000000..eb85ab87ca0 Binary files /dev/null and b/sprites/096.png differ diff --git a/sprites/097.png b/sprites/097.png new file mode 100644 index 00000000000..a30fdbb1cdd Binary files /dev/null and b/sprites/097.png differ diff --git a/sprites/098.png b/sprites/098.png new file mode 100644 index 00000000000..eb91d6a9ab5 Binary files /dev/null and b/sprites/098.png differ diff --git a/sprites/099.png b/sprites/099.png new file mode 100644 index 00000000000..42bda2ea2a1 Binary files /dev/null and b/sprites/099.png differ diff --git a/sprites/100.png b/sprites/100.png new file mode 100644 index 00000000000..690b2a42f4d Binary files /dev/null and b/sprites/100.png differ diff --git a/sprites/101.png b/sprites/101.png new file mode 100644 index 00000000000..ff7e735f260 Binary files /dev/null and b/sprites/101.png differ diff --git a/sprites/102.png b/sprites/102.png new file mode 100644 index 00000000000..14e339beec6 Binary files /dev/null and b/sprites/102.png differ diff --git a/sprites/103.png b/sprites/103.png new file mode 100644 index 00000000000..2b85c1eb7cb Binary files /dev/null and b/sprites/103.png differ diff --git a/sprites/104.png b/sprites/104.png new file mode 100644 index 00000000000..9a108432302 Binary files /dev/null and b/sprites/104.png differ diff --git a/sprites/105.png b/sprites/105.png new file mode 100644 index 00000000000..53fb1877507 Binary files /dev/null and b/sprites/105.png differ diff --git a/sprites/106.png b/sprites/106.png new file mode 100644 index 00000000000..f6abb10c774 Binary files /dev/null and b/sprites/106.png differ diff --git a/sprites/107.png b/sprites/107.png new file mode 100644 index 00000000000..3b4a968037b Binary files /dev/null and b/sprites/107.png differ diff --git a/sprites/108.png b/sprites/108.png new file mode 100644 index 00000000000..3d95764a96e Binary files /dev/null and b/sprites/108.png differ diff --git a/sprites/109.png b/sprites/109.png new file mode 100644 index 00000000000..8b77f2e9dee Binary files /dev/null and b/sprites/109.png differ diff --git a/sprites/110.png b/sprites/110.png new file mode 100644 index 00000000000..7670ceddecc Binary files /dev/null and b/sprites/110.png differ diff --git a/sprites/111.png b/sprites/111.png new file mode 100644 index 00000000000..0a25d8fd49e Binary files /dev/null and b/sprites/111.png differ diff --git a/sprites/112.png b/sprites/112.png new file mode 100644 index 00000000000..6630c445a38 Binary files /dev/null and b/sprites/112.png differ diff --git a/sprites/113.png b/sprites/113.png new file mode 100644 index 00000000000..04fadc30b28 Binary files /dev/null and b/sprites/113.png differ diff --git a/sprites/114.png b/sprites/114.png new file mode 100644 index 00000000000..45f3be735f5 Binary files /dev/null and b/sprites/114.png differ diff --git a/sprites/115.png b/sprites/115.png new file mode 100644 index 00000000000..e74e71c0afb Binary files /dev/null and b/sprites/115.png differ diff --git a/sprites/116.png b/sprites/116.png new file mode 100644 index 00000000000..0bfc8a5f9fe Binary files /dev/null and b/sprites/116.png differ diff --git a/sprites/117.png b/sprites/117.png new file mode 100644 index 00000000000..6c7d72a9a5a Binary files /dev/null and b/sprites/117.png differ diff --git a/sprites/118.png b/sprites/118.png new file mode 100644 index 00000000000..b2651886c90 Binary files /dev/null and b/sprites/118.png differ diff --git a/sprites/119.png b/sprites/119.png new file mode 100644 index 00000000000..d23d7261310 Binary files /dev/null and b/sprites/119.png differ diff --git a/sprites/120.png b/sprites/120.png new file mode 100644 index 00000000000..aaf23f47b2d Binary files /dev/null and b/sprites/120.png differ diff --git a/sprites/121.png b/sprites/121.png new file mode 100644 index 00000000000..c65859cfd08 Binary files /dev/null and b/sprites/121.png differ diff --git a/sprites/122.png b/sprites/122.png new file mode 100644 index 00000000000..4399d5cc955 Binary files /dev/null and b/sprites/122.png differ diff --git a/sprites/123.png b/sprites/123.png new file mode 100644 index 00000000000..95c1906b022 Binary files /dev/null and b/sprites/123.png differ diff --git a/sprites/124.png b/sprites/124.png new file mode 100644 index 00000000000..2c978e5d7cd Binary files /dev/null and b/sprites/124.png differ diff --git a/sprites/125.png b/sprites/125.png new file mode 100644 index 00000000000..30ab0baf140 Binary files /dev/null and b/sprites/125.png differ diff --git a/sprites/126.png b/sprites/126.png new file mode 100644 index 00000000000..dc294054c96 Binary files /dev/null and b/sprites/126.png differ diff --git a/sprites/127.png b/sprites/127.png new file mode 100644 index 00000000000..4ef098d6c31 Binary files /dev/null and b/sprites/127.png differ diff --git a/sprites/128.png b/sprites/128.png new file mode 100644 index 00000000000..88b8c9e4dd5 Binary files /dev/null and b/sprites/128.png differ diff --git a/sprites/129.png b/sprites/129.png new file mode 100644 index 00000000000..7fc72c0c1ef Binary files /dev/null and b/sprites/129.png differ diff --git a/sprites/130.png b/sprites/130.png new file mode 100644 index 00000000000..47cc8d7ebd6 Binary files /dev/null and b/sprites/130.png differ diff --git a/sprites/131.png b/sprites/131.png new file mode 100644 index 00000000000..57b17bcea50 Binary files /dev/null and b/sprites/131.png differ diff --git a/sprites/132.png b/sprites/132.png new file mode 100644 index 00000000000..179322c66be Binary files /dev/null and b/sprites/132.png differ diff --git a/sprites/133.png b/sprites/133.png new file mode 100644 index 00000000000..53d95f1e2c9 Binary files /dev/null and b/sprites/133.png differ diff --git a/sprites/134.png b/sprites/134.png new file mode 100644 index 00000000000..75b18841ef8 Binary files /dev/null and b/sprites/134.png differ diff --git a/sprites/135.png b/sprites/135.png new file mode 100644 index 00000000000..f9e0496e391 Binary files /dev/null and b/sprites/135.png differ diff --git a/sprites/136.png b/sprites/136.png new file mode 100644 index 00000000000..0c7120367ae Binary files /dev/null and b/sprites/136.png differ diff --git a/sprites/137.png b/sprites/137.png new file mode 100644 index 00000000000..eee76a03511 Binary files /dev/null and b/sprites/137.png differ diff --git a/sprites/138.png b/sprites/138.png new file mode 100644 index 00000000000..0f253d45d63 Binary files /dev/null and b/sprites/138.png differ diff --git a/sprites/139.png b/sprites/139.png new file mode 100644 index 00000000000..3712925660f Binary files /dev/null and b/sprites/139.png differ diff --git a/sprites/140.png b/sprites/140.png new file mode 100644 index 00000000000..2614da11951 Binary files /dev/null and b/sprites/140.png differ diff --git a/sprites/141.png b/sprites/141.png new file mode 100644 index 00000000000..7d1ea3e889c Binary files /dev/null and b/sprites/141.png differ diff --git a/sprites/142.png b/sprites/142.png new file mode 100644 index 00000000000..a218f81f655 Binary files /dev/null and b/sprites/142.png differ diff --git a/sprites/143.png b/sprites/143.png new file mode 100644 index 00000000000..6fec6b2e38e Binary files /dev/null and b/sprites/143.png differ diff --git a/sprites/144.png b/sprites/144.png new file mode 100644 index 00000000000..9dc8a8276ec Binary files /dev/null and b/sprites/144.png differ diff --git a/sprites/145.png b/sprites/145.png new file mode 100644 index 00000000000..1b2f3f78632 Binary files /dev/null and b/sprites/145.png differ diff --git a/sprites/146.png b/sprites/146.png new file mode 100644 index 00000000000..2cfa6d2747b Binary files /dev/null and b/sprites/146.png differ diff --git a/sprites/147.png b/sprites/147.png new file mode 100644 index 00000000000..131f1a79711 Binary files /dev/null and b/sprites/147.png differ diff --git a/sprites/148.png b/sprites/148.png new file mode 100644 index 00000000000..8c6398dd858 Binary files /dev/null and b/sprites/148.png differ diff --git a/sprites/149.png b/sprites/149.png new file mode 100644 index 00000000000..b8c4889cb70 Binary files /dev/null and b/sprites/149.png differ diff --git a/sprites/150.png b/sprites/150.png new file mode 100644 index 00000000000..3ba3019b6d8 Binary files /dev/null and b/sprites/150.png differ diff --git a/sprites/151.png b/sprites/151.png new file mode 100644 index 00000000000..e6e74e8948d Binary files /dev/null and b/sprites/151.png differ diff --git a/sprites/152.png b/sprites/152.png new file mode 100644 index 00000000000..50b42dc0892 Binary files /dev/null and b/sprites/152.png differ diff --git a/sprites/153.png b/sprites/153.png new file mode 100644 index 00000000000..96a8402031b Binary files /dev/null and b/sprites/153.png differ diff --git a/sprites/154.png b/sprites/154.png new file mode 100644 index 00000000000..65a44953de3 Binary files /dev/null and b/sprites/154.png differ diff --git a/sprites/155.png b/sprites/155.png new file mode 100644 index 00000000000..895b597307d Binary files /dev/null and b/sprites/155.png differ diff --git a/sprites/156.png b/sprites/156.png new file mode 100644 index 00000000000..b37199f6847 Binary files /dev/null and b/sprites/156.png differ diff --git a/sprites/157.png b/sprites/157.png new file mode 100644 index 00000000000..8b80caa0968 Binary files /dev/null and b/sprites/157.png differ diff --git a/sprites/158.png b/sprites/158.png new file mode 100644 index 00000000000..bafdfd2add3 Binary files /dev/null and b/sprites/158.png differ diff --git a/sprites/159.png b/sprites/159.png new file mode 100644 index 00000000000..0aaec4da691 Binary files /dev/null and b/sprites/159.png differ diff --git a/sprites/160.png b/sprites/160.png new file mode 100644 index 00000000000..97743160205 Binary files /dev/null and b/sprites/160.png differ diff --git a/sprites/161.png b/sprites/161.png new file mode 100644 index 00000000000..4ef4f1c16d0 Binary files /dev/null and b/sprites/161.png differ diff --git a/sprites/162.png b/sprites/162.png new file mode 100644 index 00000000000..4fb1f33b599 Binary files /dev/null and b/sprites/162.png differ diff --git a/sprites/163.png b/sprites/163.png new file mode 100644 index 00000000000..080663b643e Binary files /dev/null and b/sprites/163.png differ diff --git a/sprites/164.png b/sprites/164.png new file mode 100644 index 00000000000..04731e82f4b Binary files /dev/null and b/sprites/164.png differ diff --git a/sprites/165.png b/sprites/165.png new file mode 100644 index 00000000000..029986f682c Binary files /dev/null and b/sprites/165.png differ diff --git a/sprites/166.png b/sprites/166.png new file mode 100644 index 00000000000..09707e5819e Binary files /dev/null and b/sprites/166.png differ diff --git a/sprites/167.png b/sprites/167.png new file mode 100644 index 00000000000..69338cd8934 Binary files /dev/null and b/sprites/167.png differ diff --git a/sprites/168.png b/sprites/168.png new file mode 100644 index 00000000000..3d0776be3b9 Binary files /dev/null and b/sprites/168.png differ diff --git a/sprites/169.png b/sprites/169.png new file mode 100644 index 00000000000..a02eac36a94 Binary files /dev/null and b/sprites/169.png differ diff --git a/sprites/170.png b/sprites/170.png new file mode 100644 index 00000000000..7e09353fa91 Binary files /dev/null and b/sprites/170.png differ diff --git a/sprites/171.png b/sprites/171.png new file mode 100644 index 00000000000..3363c4a3856 Binary files /dev/null and b/sprites/171.png differ diff --git a/sprites/172.png b/sprites/172.png new file mode 100644 index 00000000000..347f585772b Binary files /dev/null and b/sprites/172.png differ diff --git a/sprites/173.png b/sprites/173.png new file mode 100644 index 00000000000..2acfc98912f Binary files /dev/null and b/sprites/173.png differ diff --git a/sprites/174.png b/sprites/174.png new file mode 100644 index 00000000000..4a2c9848986 Binary files /dev/null and b/sprites/174.png differ diff --git a/sprites/175.png b/sprites/175.png new file mode 100644 index 00000000000..f81f3efae27 Binary files /dev/null and b/sprites/175.png differ diff --git a/sprites/176.png b/sprites/176.png new file mode 100644 index 00000000000..b14f5fa83dc Binary files /dev/null and b/sprites/176.png differ diff --git a/sprites/177.png b/sprites/177.png new file mode 100644 index 00000000000..6758b8049d1 Binary files /dev/null and b/sprites/177.png differ diff --git a/sprites/178.png b/sprites/178.png new file mode 100644 index 00000000000..b4dea171540 Binary files /dev/null and b/sprites/178.png differ diff --git a/sprites/179.png b/sprites/179.png new file mode 100644 index 00000000000..acd5242d634 Binary files /dev/null and b/sprites/179.png differ diff --git a/sprites/180.png b/sprites/180.png new file mode 100644 index 00000000000..8012755f477 Binary files /dev/null and b/sprites/180.png differ diff --git a/sprites/181.png b/sprites/181.png new file mode 100644 index 00000000000..69929183a7b Binary files /dev/null and b/sprites/181.png differ diff --git a/sprites/182.png b/sprites/182.png new file mode 100644 index 00000000000..046272c44fd Binary files /dev/null and b/sprites/182.png differ diff --git a/sprites/183.png b/sprites/183.png new file mode 100644 index 00000000000..ad4fcf436fe Binary files /dev/null and b/sprites/183.png differ diff --git a/sprites/184.png b/sprites/184.png new file mode 100644 index 00000000000..01860d1cdfe Binary files /dev/null and b/sprites/184.png differ diff --git a/sprites/185.png b/sprites/185.png new file mode 100644 index 00000000000..d5d7cd0566a Binary files /dev/null and b/sprites/185.png differ diff --git a/sprites/186.png b/sprites/186.png new file mode 100644 index 00000000000..8ce9458f3f3 Binary files /dev/null and b/sprites/186.png differ diff --git a/sprites/187.png b/sprites/187.png new file mode 100644 index 00000000000..c6f2bcb4e52 Binary files /dev/null and b/sprites/187.png differ diff --git a/sprites/188.png b/sprites/188.png new file mode 100644 index 00000000000..f44d94c0321 Binary files /dev/null and b/sprites/188.png differ diff --git a/sprites/189.png b/sprites/189.png new file mode 100644 index 00000000000..a20e96d42fe Binary files /dev/null and b/sprites/189.png differ diff --git a/sprites/190.png b/sprites/190.png new file mode 100644 index 00000000000..41e44b1a3bf Binary files /dev/null and b/sprites/190.png differ diff --git a/sprites/191.png b/sprites/191.png new file mode 100644 index 00000000000..88e6eb06a5c Binary files /dev/null and b/sprites/191.png differ diff --git a/sprites/192.png b/sprites/192.png new file mode 100644 index 00000000000..e993df7e03a Binary files /dev/null and b/sprites/192.png differ diff --git a/sprites/193.png b/sprites/193.png new file mode 100644 index 00000000000..95f6ab3b584 Binary files /dev/null and b/sprites/193.png differ diff --git a/sprites/194.png b/sprites/194.png new file mode 100644 index 00000000000..10350145930 Binary files /dev/null and b/sprites/194.png differ diff --git a/sprites/195.png b/sprites/195.png new file mode 100644 index 00000000000..81951d0afa5 Binary files /dev/null and b/sprites/195.png differ diff --git a/sprites/196.png b/sprites/196.png new file mode 100644 index 00000000000..7360ef1b973 Binary files /dev/null and b/sprites/196.png differ diff --git a/sprites/197.png b/sprites/197.png new file mode 100644 index 00000000000..6cde91dda2a Binary files /dev/null and b/sprites/197.png differ diff --git a/sprites/198.png b/sprites/198.png new file mode 100644 index 00000000000..ce754343bb6 Binary files /dev/null and b/sprites/198.png differ diff --git a/sprites/199.png b/sprites/199.png new file mode 100644 index 00000000000..6bb88c66415 Binary files /dev/null and b/sprites/199.png differ diff --git a/sprites/200.png b/sprites/200.png new file mode 100644 index 00000000000..fa60d822a3b Binary files /dev/null and b/sprites/200.png differ diff --git a/sprites/201.png b/sprites/201.png new file mode 100644 index 00000000000..6565b07e453 Binary files /dev/null and b/sprites/201.png differ diff --git a/sprites/202.png b/sprites/202.png new file mode 100644 index 00000000000..e12140da2be Binary files /dev/null and b/sprites/202.png differ diff --git a/sprites/203.png b/sprites/203.png new file mode 100644 index 00000000000..eab4331144a Binary files /dev/null and b/sprites/203.png differ diff --git a/sprites/204.png b/sprites/204.png new file mode 100644 index 00000000000..ec98d7580f4 Binary files /dev/null and b/sprites/204.png differ diff --git a/sprites/205.png b/sprites/205.png new file mode 100644 index 00000000000..52e97cef917 Binary files /dev/null and b/sprites/205.png differ diff --git a/sprites/206.png b/sprites/206.png new file mode 100644 index 00000000000..60952e4f43e Binary files /dev/null and b/sprites/206.png differ diff --git a/sprites/207.png b/sprites/207.png new file mode 100644 index 00000000000..d69a1a1e8ba Binary files /dev/null and b/sprites/207.png differ diff --git a/sprites/208.png b/sprites/208.png new file mode 100644 index 00000000000..99455a694e1 Binary files /dev/null and b/sprites/208.png differ diff --git a/sprites/209.png b/sprites/209.png new file mode 100644 index 00000000000..123860618c8 Binary files /dev/null and b/sprites/209.png differ diff --git a/sprites/210.png b/sprites/210.png new file mode 100644 index 00000000000..8ff274e029b Binary files /dev/null and b/sprites/210.png differ diff --git a/sprites/211.png b/sprites/211.png new file mode 100644 index 00000000000..4ec501b51bb Binary files /dev/null and b/sprites/211.png differ diff --git a/sprites/212.png b/sprites/212.png new file mode 100644 index 00000000000..d3dd478193f Binary files /dev/null and b/sprites/212.png differ diff --git a/sprites/213.png b/sprites/213.png new file mode 100644 index 00000000000..3cdbcd8ff6d Binary files /dev/null and b/sprites/213.png differ diff --git a/sprites/214.png b/sprites/214.png new file mode 100644 index 00000000000..afd3779b088 Binary files /dev/null and b/sprites/214.png differ diff --git a/sprites/215.png b/sprites/215.png new file mode 100644 index 00000000000..0b854e30311 Binary files /dev/null and b/sprites/215.png differ diff --git a/sprites/216.png b/sprites/216.png new file mode 100644 index 00000000000..1455c045cbb Binary files /dev/null and b/sprites/216.png differ diff --git a/sprites/217.png b/sprites/217.png new file mode 100644 index 00000000000..0bafe57204a Binary files /dev/null and b/sprites/217.png differ diff --git a/sprites/218.png b/sprites/218.png new file mode 100644 index 00000000000..bcd166323b3 Binary files /dev/null and b/sprites/218.png differ diff --git a/sprites/219.png b/sprites/219.png new file mode 100644 index 00000000000..cfbdbbdfb52 Binary files /dev/null and b/sprites/219.png differ diff --git a/sprites/220.png b/sprites/220.png new file mode 100644 index 00000000000..2114bd241b2 Binary files /dev/null and b/sprites/220.png differ diff --git a/sprites/221.png b/sprites/221.png new file mode 100644 index 00000000000..4ad72bde3f3 Binary files /dev/null and b/sprites/221.png differ diff --git a/sprites/222.png b/sprites/222.png new file mode 100644 index 00000000000..e2cf5b77af3 Binary files /dev/null and b/sprites/222.png differ diff --git a/sprites/223.png b/sprites/223.png new file mode 100644 index 00000000000..d3972d839d2 Binary files /dev/null and b/sprites/223.png differ diff --git a/sprites/224.png b/sprites/224.png new file mode 100644 index 00000000000..1b3100d48d2 Binary files /dev/null and b/sprites/224.png differ diff --git a/sprites/225.png b/sprites/225.png new file mode 100644 index 00000000000..569956b44d3 Binary files /dev/null and b/sprites/225.png differ diff --git a/sprites/226.png b/sprites/226.png new file mode 100644 index 00000000000..c9fb007134d Binary files /dev/null and b/sprites/226.png differ diff --git a/sprites/227.png b/sprites/227.png new file mode 100644 index 00000000000..2991b3bbdd2 Binary files /dev/null and b/sprites/227.png differ diff --git a/sprites/228.png b/sprites/228.png new file mode 100644 index 00000000000..a3e1016f71d Binary files /dev/null and b/sprites/228.png differ diff --git a/sprites/229.png b/sprites/229.png new file mode 100644 index 00000000000..7d0a80a7b2d Binary files /dev/null and b/sprites/229.png differ diff --git a/sprites/230.png b/sprites/230.png new file mode 100644 index 00000000000..5cee01dde1a Binary files /dev/null and b/sprites/230.png differ diff --git a/sprites/231.png b/sprites/231.png new file mode 100644 index 00000000000..187cce46545 Binary files /dev/null and b/sprites/231.png differ diff --git a/sprites/232.png b/sprites/232.png new file mode 100644 index 00000000000..00a51b4e60c Binary files /dev/null and b/sprites/232.png differ diff --git a/sprites/233.png b/sprites/233.png new file mode 100644 index 00000000000..d6eb4304395 Binary files /dev/null and b/sprites/233.png differ diff --git a/sprites/234.png b/sprites/234.png new file mode 100644 index 00000000000..0c2ac66ca6b Binary files /dev/null and b/sprites/234.png differ diff --git a/sprites/235.png b/sprites/235.png new file mode 100644 index 00000000000..60d1255bb69 Binary files /dev/null and b/sprites/235.png differ diff --git a/sprites/236.png b/sprites/236.png new file mode 100644 index 00000000000..0c7a164c180 Binary files /dev/null and b/sprites/236.png differ diff --git a/sprites/237.png b/sprites/237.png new file mode 100644 index 00000000000..2ea4ea2fad2 Binary files /dev/null and b/sprites/237.png differ diff --git a/sprites/238.png b/sprites/238.png new file mode 100644 index 00000000000..c1a355f8211 Binary files /dev/null and b/sprites/238.png differ diff --git a/sprites/239.png b/sprites/239.png new file mode 100644 index 00000000000..a038ec2e6a3 Binary files /dev/null and b/sprites/239.png differ diff --git a/sprites/240.png b/sprites/240.png new file mode 100644 index 00000000000..6828274229d Binary files /dev/null and b/sprites/240.png differ diff --git a/sprites/241.png b/sprites/241.png new file mode 100644 index 00000000000..9cd9d03aba0 Binary files /dev/null and b/sprites/241.png differ diff --git a/sprites/242.png b/sprites/242.png new file mode 100644 index 00000000000..1e72703728d Binary files /dev/null and b/sprites/242.png differ diff --git a/sprites/243.png b/sprites/243.png new file mode 100644 index 00000000000..fdcc11eac8c Binary files /dev/null and b/sprites/243.png differ diff --git a/sprites/244.png b/sprites/244.png new file mode 100644 index 00000000000..98bae539b57 Binary files /dev/null and b/sprites/244.png differ diff --git a/sprites/245.png b/sprites/245.png new file mode 100644 index 00000000000..2173d88e596 Binary files /dev/null and b/sprites/245.png differ diff --git a/sprites/246.png b/sprites/246.png new file mode 100644 index 00000000000..05a87e9e80f Binary files /dev/null and b/sprites/246.png differ diff --git a/sprites/247.png b/sprites/247.png new file mode 100644 index 00000000000..e78d7c17357 Binary files /dev/null and b/sprites/247.png differ diff --git a/sprites/248.png b/sprites/248.png new file mode 100644 index 00000000000..65a50ca8687 Binary files /dev/null and b/sprites/248.png differ diff --git a/sprites/249.png b/sprites/249.png new file mode 100644 index 00000000000..e66c8f80b24 Binary files /dev/null and b/sprites/249.png differ diff --git a/sprites/250.png b/sprites/250.png new file mode 100644 index 00000000000..b7cd2136330 Binary files /dev/null and b/sprites/250.png differ diff --git a/sprites/251.png b/sprites/251.png new file mode 100644 index 00000000000..87e49f63a59 Binary files /dev/null and b/sprites/251.png differ diff --git a/sprites/README.md b/sprites/README.md new file mode 100644 index 00000000000..9ccdea32004 --- /dev/null +++ b/sprites/README.md @@ -0,0 +1,20 @@ +# Sprite Assets + +In this folder are the Pokemon sprite sources. They should all be 3 digits and numbered in the national Pokedex order. + + +## Building + +The final sprites on the SD card are expected to be in the "fxbm" format as used by [https://github.com/flipperdevices/flipperzero-game-engine](https://github.com/flipperdevices/flipperzero-game-engine). This is XBM format with a short header with the size, width, and height. + +In order to generate the fxbm formatted file, the following steps can be used from the root directory of the project (do not perform the steps from this directory, it won't work): +``` +git clone https://github.com/flipperdevices/flipperzero-game-engine +python3 flipperzero-game-engine/scripts/sprite_builder.py sprites files +cd files +xxd -i 000.fxbm > ../missingno_i.h +rm 000.fxbm +rm all_sprites.fxbm +for I in *; do cat $I >> all_sprites.fxbm; rm $I; done +cd - +``` diff --git a/stat_nl.c b/stat_nl.c new file mode 100644 index 00000000000..4446fba6338 --- /dev/null +++ b/stat_nl.c @@ -0,0 +1,12 @@ +#include +#include + +const NamedList stat_list[] = { + {"Random IV, Zero EV", RANDIV_ZEROEV, 0}, + {"Random IV, Max EV / Level", RANDIV_LEVELEV, 0}, + {"Random IV, Max EV", RANDIV_MAXEV, 0}, + {"Max IV, Zero EV", MAXIV_ZEROEV, 0}, + {"Max IV, Max EV / Level", MAXIV_LEVELEV, 0}, + {"Max IV, Max EV", MAXIV_MAXEV, 0}, + {}, +}; diff --git a/stat_nl.h b/stat_nl.h new file mode 100644 index 00000000000..753cfa0f5db --- /dev/null +++ b/stat_nl.h @@ -0,0 +1,17 @@ +#ifndef __STAT_NL_H__ +#define __STAT_NL_H__ + +#pragma once + +extern const NamedList stat_list[]; + +typedef enum { + RANDIV_ZEROEV, + RANDIV_LEVELEV, + RANDIV_MAXEV, + MAXIV_ZEROEV, + MAXIV_LEVELEV, + MAXIV_MAXEV, +} EvIv; + +#endif // __STAT_NL_H__ diff --git a/stats.h b/stats.h new file mode 100644 index 00000000000..7c04d905745 --- /dev/null +++ b/stats.h @@ -0,0 +1,104 @@ +#ifndef __STATS_H__ +#define __STATS_H__ + +#pragma once + +typedef enum { + /* Base stats */ + STAT_BASE = 0, // Sentry value + STAT_BASE_ATK = 0, + STAT_BASE_DEF, + STAT_BASE_SPD, + /* NOTE! While accessing SPC/APC_AT will do the correct thing for both + * Gen I and Gen II, accessing SPC_DEF for Gen I will return a value + * that is not used in Gen I games. This normally isn't an issue, but + * is a potential gotcha to be aware of. + */ + STAT_BASE_SPC, + STAT_BASE_SPC_ATK, + STAT_BASE_SPC_DEF, + STAT_BASE_HP, + STAT_BASE_TYPE, + STAT_BASE_MOVE, + STAT_BASE_GROWTH, + STAT_BASE_GENDER_RATIO, + STAT_BASE_INDEX, + STAT_BASE_END, // Sentry value + + /* In-party stats */ + STAT = 0, // Sentry value + STAT_ATK = 0, + STAT_DEF, + STAT_SPD, + /* Gen I uses SPC, Gen II uses SPC_ATK and SPC_DEF */ + STAT_SPC, + STAT_SPC_ATK, + STAT_SPC_DEF, + STAT_HP, + STAT_END = 7, // Sentry value + STAT_TYPE = 7, + /* Move is left here to line up with the table base stats */ + STAT_MOVE, + + STAT_EV = 10, // Sentry value + STAT_EV_OFFS = 10, + STAT_ATK_EV = 10, + STAT_DEF_EV, + STAT_SPD_EV, + /* There is only SPC EV, there is no SPC_ATK/DEF. However, for the sake + * of making calculations easier, we pretend there are. This means that + * SPC/SPC_ATK/SPC_DEF calculations all grab the SPC EV. + */ + STAT_SPC_EV, + STAT_SPC_ATK_EV, + STAT_SPC_DEF_EV, + STAT_HP_EV = 16, + STAT_EV_END, // Sentry value + + STAT_IV = 19, + STAT_IV_OFFS = 20, // Sentry value + STAT_ATK_IV = 20, + STAT_DEF_IV, + STAT_SPD_IV, + /* There is only SPC IV, there is no SPC_ATK/DEF. However, for the sake + * of making calculations easier, we pretend there are. This means that + * SPC/SPC_ATK/SPC_DEF calculations all grab the SPC IV. + */ + STAT_SPC_IV, + STAT_SPC_ATK_IV, + STAT_SPC_DEF_IV, + STAT_HP_IV = 26, + STAT_IV_END, // Sentry value + + /* These won't ever really be needed in groups */ + STAT_LEVEL = 28, + STAT_INDEX, + STAT_NUM, + STAT_CONDITION, + STAT_NICKNAME, + STAT_OT_NAME, + STAT_OT_ID, + STAT_TRAINER_NAME, + STAT_SEL, // which EV/IV calc to use + STAT_EXP, + STAT_HELD_ITEM, + STAT_POKERUS, +} DataStat; + +typedef enum { + MOVE_0 = 0, + MOVE_1, + MOVE_2, + MOVE_3, + + TYPE_0 = 0, + TYPE_1, + + EXP_0 = 0, + EXP_1, + EXP_2, + + NONE = 0, // Just a filler value +} DataStatSub; + +#endif // __STATS_H__ diff --git a/type_nl.c b/type_nl.c new file mode 100644 index 00000000000..a135326ff5d --- /dev/null +++ b/type_nl.c @@ -0,0 +1,22 @@ +#include +#include + +const NamedList type_list[] = { + {"Bug", 0x07, GEN_I}, + {"Dragon", 0x1A, GEN_I}, + {"Electric", 0x17, GEN_I}, + {"Fighting", 0x01, GEN_I}, + {"Fire", 0x14, GEN_I}, + {"Flying", 0x02, GEN_I}, + {"Ghost", 0x08, GEN_I}, + {"Grass", 0x16, GEN_I}, + {"Ground", 0x04, GEN_I}, + {"Ice", 0x19, GEN_I}, + {"Normal", 0x00, GEN_I}, + {"Poison", 0x03, GEN_I}, + {"Psychic", 0x18, GEN_I}, + {"Rock", 0x05, GEN_I}, + {"Water", 0x15, GEN_I}, + /* Types are not transferred in gen ii */ + {}, +}; diff --git a/type_nl.h b/type_nl.h new file mode 100644 index 00000000000..4e454eb1824 --- /dev/null +++ b/type_nl.h @@ -0,0 +1,8 @@ +#ifndef __TYPE_NL_H__ +#define __TYPE_NL_H__ + +#pragma once + +extern const NamedList type_list[]; + +#endif // __TYPE_NL_H__ diff --git a/views/select_pokemon.c b/views/select_pokemon.c index 5dd9d862598..fcbb4fbab92 100644 --- a/views/select_pokemon.c +++ b/views/select_pokemon.c @@ -3,10 +3,19 @@ #include "../scenes/pokemon_menu.h" #include "../pokemon_app.h" +#include "../pokemon_data.h" struct select_model { uint8_t curr_pokemon; - const PokemonTable* pokemon_table; + const void* pokemon_table; + PokemonData* pdata; +}; + +/* Anonymous struct */ +struct select_ctx { + View* view; + PokemonData* pdata; + SceneManager* scene_manager; }; static void select_pokemon_render_callback(Canvas* canvas, void* model) { @@ -15,22 +24,37 @@ static void select_pokemon_render_callback(Canvas* canvas, void* model) { char pokedex_num[5]; snprintf(pokedex_num, sizeof(pokedex_num), "#%03d", curr_pokemon + 1); + + /* Update the bitmap in pdata if needed */ + pokemon_icon_get(view_model->pdata, curr_pokemon + 1); + canvas_draw_xbm( + canvas, + 0, + 0, + view_model->pdata->bitmap->width, + view_model->pdata->bitmap->height, + view_model->pdata->bitmap->data); + canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned( - canvas, 55, 54 / 2, AlignLeft, AlignTop, view_model->pokemon_table[curr_pokemon].name); + canvas, + 58, + 27, + AlignLeft, + AlignTop, + table_stat_name_get(view_model->pokemon_table, curr_pokemon)); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, pokedex_num); - canvas_draw_icon(canvas, 0, 0, view_model->pokemon_table[curr_pokemon].icon); - canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18); - canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Pokemon"); + canvas_draw_str_aligned(canvas, 58, 38, AlignLeft, AlignTop, pokedex_num); + elements_frame(canvas, 55, 0, 71, 18); + canvas_draw_str_aligned(canvas, 90, 5, AlignCenter, AlignTop, "Select Pokemon"); canvas_set_font(canvas, FontPrimary); elements_button_center(canvas, "OK"); } static bool select_pokemon_input_callback(InputEvent* event, void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; + struct select_ctx* select = (struct select_ctx*)context; bool consumed = false; uint8_t selected_pokemon; @@ -40,7 +64,7 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) { if(event->type != InputTypePress) return consumed; with_view_model( - pokemon_fap->select_view, + select->view, struct select_model * model, { selected_pokemon = model->curr_pokemon; }, false); @@ -48,16 +72,15 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) { switch(event->key) { /* Advance to next view with the selected pokemon */ case InputKeyOk: - pokemon_fap->curr_pokemon = selected_pokemon; - FURI_LOG_D(TAG, "[Select] Selected %s", pokemon_fap->pokemon_table[selected_pokemon].name); - scene_manager_previous_scene(pokemon_fap->scene_manager); + pokemon_stat_set(select->pdata, STAT_NUM, NONE, selected_pokemon); + scene_manager_previous_scene(select->scene_manager); consumed = true; break; /* Move back one through the pokedex listing */ case InputKeyLeft: if(selected_pokemon == 0) - selected_pokemon = 150; + selected_pokemon = select->pdata->dex_max; else selected_pokemon--; consumed = true; @@ -70,13 +93,13 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) { if(selected_pokemon >= 10) selected_pokemon -= 10; else - selected_pokemon = 150; + selected_pokemon = select->pdata->dex_max; consumed = true; break; /* Move forward one through the pokedex listing */ case InputKeyRight: - if(selected_pokemon == 150) + if(selected_pokemon == select->pdata->dex_max) selected_pokemon = 0; else selected_pokemon++; @@ -87,7 +110,7 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) { * overflow. */ case InputKeyUp: - if(selected_pokemon <= 140) + if(selected_pokemon <= (select->pdata->dex_max - 10)) selected_pokemon += 10; else selected_pokemon = 0; @@ -100,7 +123,7 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) { } with_view_model( - pokemon_fap->select_view, + select->view, struct select_model * model, { model->curr_pokemon = selected_pokemon; }, true); @@ -109,33 +132,50 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) { } void select_pokemon_enter_callback(void* context) { - PokemonFap* pokemon_fap = (PokemonFap*)context; + struct select_ctx* select = (struct select_ctx*)context; with_view_model( - pokemon_fap->select_view, + select->view, struct select_model * model, { - model->curr_pokemon = (uint8_t)pokemon_fap->curr_pokemon; - model->pokemon_table = pokemon_fap->pokemon_table; + model->curr_pokemon = pokemon_stat_get(select->pdata, STAT_NUM, NONE); + model->pokemon_table = select->pdata->pokemon_table; + model->pdata = select->pdata; }, true); } -View* select_pokemon_alloc(PokemonFap* pokemon_fap) { - View* view; +void* select_pokemon_alloc( + PokemonData* pdata, + ViewDispatcher* view_dispatcher, + SceneManager* scene_manager, + uint32_t viewid) { + furi_assert(pdata); - view = view_alloc(); + struct select_ctx* select = malloc(sizeof(struct select_ctx)); - view_set_context(view, pokemon_fap); - view_allocate_model(view, ViewModelTypeLockFree, sizeof(struct select_model)); + select->view = view_alloc(); + select->pdata = pdata; + select->scene_manager = scene_manager; + select->pdata = pdata; - view_set_draw_callback(view, select_pokemon_render_callback); - view_set_input_callback(view, select_pokemon_input_callback); - view_set_enter_callback(view, select_pokemon_enter_callback); - return view; + view_set_context(select->view, select); + view_allocate_model(select->view, ViewModelTypeLockFree, sizeof(struct select_model)); + + view_set_draw_callback(select->view, select_pokemon_render_callback); + view_set_input_callback(select->view, select_pokemon_input_callback); + view_set_enter_callback(select->view, select_pokemon_enter_callback); + + view_dispatcher_add_view(view_dispatcher, viewid, select->view); + + return select; } -void select_pokemon_free(PokemonFap* pokemon_fap) { - furi_assert(pokemon_fap); - view_free(pokemon_fap->select_view); +void select_pokemon_free(ViewDispatcher* view_dispatcher, uint32_t viewid, void* select_ctx) { + struct select_ctx* select = (struct select_ctx*)select_ctx; + + view_dispatcher_remove_view(view_dispatcher, viewid); + + view_free(select->view); + free(select); } diff --git a/views/select_pokemon.h b/views/select_pokemon.h index e4b936283c3..2564a595989 100644 --- a/views/select_pokemon.h +++ b/views/select_pokemon.h @@ -1,13 +1,17 @@ -#ifndef SELECCT_POKEMON_H -#define SELECCT_POKEMON_H +#ifndef SELECT_POKEMON_H +#define SELECT_POKEMON_H #pragma once #include #include "../pokemon_app.h" -View* select_pokemon_alloc(PokemonFap* pokemon_fap); +void* select_pokemon_alloc( + PokemonData* pdata, + ViewDispatcher* view_dispatcher, + SceneManager* scene_manager, + uint32_t viewid); -void select_pokemon_free(PokemonFap* pokemon_fap); +void select_pokemon_free(ViewDispatcher* view_dispatcher, uint32_t viewid, void* select_ctx); -#endif /* SELECCT_POKEMON_H */ +#endif /* SELECT_POKEMON_H */ diff --git a/views/trade.c b/views/trade.c index 8d898135b04..9636fea4667 100644 --- a/views/trade.c +++ b/views/trade.c @@ -1,4 +1,12 @@ /* + * NOTE: + * The documentation below is slightly out of date but mostly still correct, + * and only for gen i trades. Gen ii trades are very similar but have a few + * different patterns. I'm currently lazy and working on features, so better + * documentation on the trade protocol to follow, and potentially will push + * it all to bulbapedia or similar for the world to benefit from. + * + * * This setup always forces the flipper to the follower/slave role in the link. * This just makes our logic consistent and since we're going to be gobs faster * than a real Game Boy, we can be guaranteed to always be ready to respond. @@ -23,6 +31,9 @@ * * 7) Once the player on the Game Boy side uses the trade table, a block of data is * transmitted. This starts with 10x PREAMBLE(0xFD) bytes, 10x random bytes (to + * + * I missed another 9x fd bytes after rand? State machine below confirms these bytes + * * sync the RNG between two devices, unused at this time), and then the 415 trade_block, * struct gets transferred. At the end of this is 3 ending bytes, DF FE 15. And, weirdly, * 3 PREAMBLE(0xFD) bytes. @@ -73,21 +84,30 @@ * trade_blocks will re-sync between them with the new data. If the Game Boy * leave the trade menu while the Flipper is in the WAITING state, the * Flipper will go back to the READY state. - * - * TODO: Set up requiring a long back press to go back to the main menu - * from the TRADING state or from the main menu to exit the application. */ #include #include +#include +#include + +#include #include #include #include #include "../pokemon_app.h" +#include "../pokemon_data.h" #include "trade_patch_list.h" +/* Uncomment the following line to enable graphics testing for the different + * phases of the trade view. Pressing the okay button will step through each + * gameboy_status. Note that while trades will still function with this enabled, + * forcing the advance of the status will certainly break trades. + */ +//#define GRAPHICS_TESTING + #define DELAY_MICROSECONDS 15 #define PKMN_BLANK 0x00 @@ -109,12 +129,19 @@ #define PKMN_MASTER 0x01 #define PKMN_SLAVE 0x02 + #define PKMN_CONNECTED 0x60 -#define PKMN_TRADE_ACCEPT 0x62 -#define PKMN_TRADE_REJECT 0x61 -#define PKMN_TABLE_LEAVE 0x6f -#define PKMN_SEL_NUM_MASK 0x60 -#define PKMN_SEL_NUM_ONE 0x60 +#define PKMN_CONNECTED_II 0x61 +#define PKMN_TRADE_ACCEPT_GEN_I 0x62 +#define PKMN_TRADE_ACCEPT_GEN_II 0x72 +#define PKMN_TRADE_REJECT_GEN_I 0x61 +#define PKMN_TRADE_REJECT_GEN_II 0x71 +#define PKMN_TABLE_LEAVE_GEN_I 0x6f +#define PKMN_TABLE_LEAVE_GEN_II 0x7f +#define PKMN_SEL_NUM_MASK_GEN_I 0x60 +#define PKMN_SEL_NUM_MASK_GEN_II 0x70 +#define PKMN_SEL_NUM_ONE_GEN_I 0x60 +#define PKMN_SEL_NUM_ONE_GEN_II 0x70 #define PKMN_ACTION 0x60 @@ -122,6 +149,33 @@ #define PKMN_COLOSSEUM ITEM_2_SELECTED #define PKMN_BREAK_LINK ITEM_3_SELECTED +struct important_bytes { + const uint8_t connected; + const uint8_t trade_accept; + const uint8_t trade_reject; + const uint8_t table_leave; + const uint8_t sel_num_mask; + const uint8_t sel_num_one; +}; + +static const struct important_bytes gen_i = { + PKMN_CONNECTED, + PKMN_TRADE_ACCEPT_GEN_I, + PKMN_TRADE_REJECT_GEN_I, + PKMN_TABLE_LEAVE_GEN_I, + PKMN_SEL_NUM_MASK_GEN_I, + PKMN_SEL_NUM_ONE_GEN_I, +}; + +static const struct important_bytes gen_ii = { + PKMN_CONNECTED_II, + PKMN_TRADE_ACCEPT_GEN_II, + PKMN_TRADE_REJECT_GEN_II, + PKMN_TABLE_LEAVE_GEN_II, + PKMN_SEL_NUM_MASK_GEN_II, + PKMN_SEL_NUM_ONE_GEN_II, +}; + /* States specific to the trade process. */ typedef enum { TRADE_RESET, @@ -131,9 +185,11 @@ typedef enum { TRADE_PATCH_HEADER, TRADE_PATCH_DATA, TRADE_SELECT, + TRADE_MAIL, TRADE_PENDING, TRADE_CONFIRMATION, - TRADE_DONE + TRADE_DONE, + TRADE_CANCEL } trade_centre_state_t; /* Global states for the trade logic. These are used to dictate what gets drawn @@ -149,7 +205,9 @@ typedef enum { GAMEBOY_WAITING, GAMEBOY_TRADE_PENDING, GAMEBOY_TRADING, - GAMEBOY_COLOSSEUM + GAMEBOY_TRADE_CANCEL, + GAMEBOY_COLOSSEUM, + GAMEBOY_STATE_COUNT } render_gameboy_state_t; /* Anonymous struct */ @@ -160,12 +218,12 @@ struct trade_ctx { uint8_t in_data; uint8_t out_data; uint8_t shift; - TradeBlock* trade_block; - TradeBlock* input_block; - const PokemonTable* pokemon_table; + PokemonData* input_pdata; struct patch_list* patch_list; void* gblink_handle; struct gblink_pins* gblink_pins; + PokemonData* pdata; + NotificationApp* notifications; }; /* These are the needed variables for the draw callback */ @@ -173,9 +231,80 @@ struct trade_model { render_gameboy_state_t gameboy_status; bool ledon; // Controls the blue LED during trade uint8_t curr_pokemon; - const PokemonTable* pokemon_table; + PokemonData* pdata; }; +/* Input callback, used to handle the user trying to back out of the trade + * screen. + * Normally, when trade_centre_state is <= READY, pressing back would just go + * back without issue. However, when WAITING, we need to tell the gameboy that + * the flipper wants to exit the trade menu. Anything beyond WAITING should not + * go back nor try to tell the gameboy to cancel; instead, by holding back in + * these states, we can forcefully go back one menu. + * + * Returning false here then ends up calling the view_dispatcher nav callback + * if the button pressed/held is Back. Returning true tells the OS that we + * dealt with the button press and no further action is needed. + */ +static bool trade_input_callback(InputEvent* event, void* context) { + furi_assert(context); + struct trade_ctx* trade = context; + render_gameboy_state_t gameboy_status; + +#ifdef GRAPHICS_TESTING + if(event->type == InputTypePress) { + with_view_model( + trade->view, + struct trade_model * model, + { + if(event->key == InputKeyRight) { + model->gameboy_status++; + if(model->gameboy_status == GAMEBOY_STATE_COUNT) + model->gameboy_status = GAMEBOY_CONN_FALSE; + } else if(event->key == InputKeyLeft) { + if(model->gameboy_status == GAMEBOY_CONN_FALSE) + model->gameboy_status = GAMEBOY_COLOSSEUM; + else + model->gameboy_status--; + } + }, + true); + } +#endif + + /* Only handling back button */ + if(event->key != InputKeyBack) return false; + + with_view_model( + trade->view, + struct trade_model * model, + { gameboy_status = model->gameboy_status; }, + false); + + /* States READY or lower can be exited without issue, let the view_dispatcher + * nav callback handle it. + */ + if(gameboy_status <= GAMEBOY_READY) return false; + + /* Long presses we want the view_dispatcher nav callback to handle */ + if(event->type == InputTypeLong) return false; + + /* In the waiting state, we need to move to cancelled. This locks us up + * until the gameboy side gets the hint and cancels as well. + */ + if(gameboy_status == GAMEBOY_WAITING && event->type == InputTypeShort) { + with_view_model( + trade->view, + struct trade_model * model, + { model->gameboy_status = GAMEBOY_TRADE_CANCEL; }, + false); + trade->trade_centre_state = TRADE_CANCEL; + } + + /* Anything here, we should consider handled */ + return true; +} + /* A callback function that must be called outside of an interrupt context, * This will completely destroy the current patch list, and then rebuild it from * the current trade_block state. This is used mostly after a trade to rebuild @@ -186,31 +315,61 @@ static void pokemon_plist_recreate_callback(void* context, uint32_t arg) { UNUSED(arg); struct trade_ctx* trade = context; - plist_create(&(trade->patch_list), trade->trade_block); + /* Award some XP to the dolphin after a completed trade. This needs to + * happen outside of an ISR context, so we slap it here. + */ + dolphin_deed(DolphinDeedPluginGameWin); + plist_create(&(trade->patch_list), trade->pdata); } -/* Draws a whole screen image with Flipper mascot, Game Boy, etc. */ -static void trade_draw_connect(Canvas* const canvas) { +/* Call this at any point to reset the timer on the backlight turning off. + * During trade, this should get called pretty frequently so long as data + * is moving in and out. + * + * I hesitate to force the backlight on, as I don't want to be responsible + * for draining someone's battery on accident. + */ +static void trade_backlight_bump_callback(void* context, uint32_t arg) { + furi_assert(context); + UNUSED(arg); + struct trade_ctx* trade = context; + + notification_message(trade->notifications, &sequence_display_backlight_on); +} + +static void trade_draw_bottom_bar(Canvas* const canvas) { furi_assert(canvas); - canvas_draw_frame(canvas, 0, 0, 128, 64); - canvas_draw_icon(canvas, 1, 21, &I_Connect_me_62x31); + /* Paint the area behind the bottom background bar white to prevent overlap */ + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 0, 53, 9, 7); + canvas_draw_box(canvas, 6, 56, 59, 6); + canvas_draw_box(canvas, 60, 53, 32, 7); + canvas_draw_box(canvas, 87, 56, 38, 6); + canvas_set_color(canvas, ColorBlack); + + /* Draw bar with transparencies */ + canvas_set_bitmap_mode(canvas, 1); canvas_draw_icon(canvas, 0, 53, &I_Background_128x11); - canvas_draw_icon(canvas, 80, 0, &I_game_boy); - canvas_draw_icon(canvas, 8, 2, &I_Space_65x18); - canvas_draw_str(canvas, 18, 13, "Connect GB"); + canvas_set_bitmap_mode(canvas, 0); } /* Draws a whole screen image with Flipper mascot, Game Boy, etc. */ -static void trade_draw_connected(Canvas* const canvas) { +static void trade_draw_connection(Canvas* const canvas, bool connected) { furi_assert(canvas); - canvas_draw_frame(canvas, 0, 0, 128, 64); - canvas_draw_icon(canvas, 1, 21, &I_Connected_62x31); - canvas_draw_icon(canvas, 0, 53, &I_Background_128x11); + canvas_draw_icon(canvas, 9, 26, &I_dolphin); + trade_draw_bottom_bar(canvas); canvas_draw_icon(canvas, 80, 0, &I_game_boy); - canvas_draw_icon(canvas, 8, 2, &I_Space_65x18); - canvas_draw_str(canvas, 18, 13, "Connected!"); + elements_frame(canvas, 9, 2, 64, 17); + + if(connected) { + canvas_draw_str(canvas, 18, 13, "Connected!"); + canvas_draw_icon(canvas, 61, 23, &I_hand_thumbsup); + } else { + canvas_draw_str(canvas, 18, 13, "Connect GB"); + canvas_draw_icon(canvas, 56, 23, &I_hand_cable); + } } /* Draws a frame around the screen, with a box at the top for a text string, @@ -219,19 +378,30 @@ static void trade_draw_connected(Canvas* const canvas) { static void trade_draw_frame(Canvas* canvas, const char* str) { furi_assert(canvas); - canvas_draw_icon(canvas, 0, 53, &I_Background_128x11); - canvas_draw_frame(canvas, 0, 0, 128, 64); - canvas_draw_icon(canvas, 24, 0, &I_Space_80x18); - canvas_draw_str(canvas, 48, 12, str); - canvas_draw_icon(canvas, 27, 1, &I_red_16x15); + trade_draw_bottom_bar(canvas); + + /* Paint the area behind the text box white to prevent overlap, similar + * to the bottom background bar */ + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 59, 0, 67, 19); + canvas_set_color(canvas, ColorBlack); + + /* Draw text box and populate it with string and Red icon */ + elements_frame(canvas, 59, 0, 67, 19); + canvas_draw_str(canvas, 82, 12, str); + canvas_draw_icon(canvas, 61, 2, &I_red_16x15); } /* Draws the Pokemon's image in the middle of the screen */ -static void trade_draw_pkmn_avatar(Canvas* canvas, const Icon* icon) { +static void trade_draw_pkmn_avatar(Canvas* canvas, PokemonData* pdata) { furi_assert(canvas); - furi_assert(icon); + furi_assert(pdata); + + /* First, ensure the icon we want is already loaded in to pdata->bitmap */ + pokemon_icon_get(pdata, pokemon_stat_get(pdata, STAT_NUM, NONE) + 1); + canvas_draw_xbm( + canvas, 0, 0, pdata->bitmap->width, pdata->bitmap->height, pdata->bitmap->data); - canvas_draw_icon(canvas, 38, 11, icon); furi_hal_light_set(LightBlue, 0x00); furi_hal_light_set(LightGreen, 0x00); } @@ -254,43 +424,45 @@ static void trade_draw_timer_callback(void* context) { static void trade_draw_callback(Canvas* canvas, void* view_model) { furi_assert(view_model); struct trade_model* model = view_model; - const Icon* icon = model->pokemon_table[model->curr_pokemon].icon; canvas_clear(canvas); switch(model->gameboy_status) { case GAMEBOY_CONN_FALSE: furi_hal_light_set(LightGreen, 0x00); furi_hal_light_set(LightRed, 0xff); - trade_draw_connect(canvas); + trade_draw_connection(canvas, false); break; case GAMEBOY_CONN_TRUE: furi_hal_light_set(LightGreen, 0xff); furi_hal_light_set(LightRed, 0x00); - trade_draw_connected(canvas); + trade_draw_connection(canvas, true); break; case GAMEBOY_READY: - trade_draw_pkmn_avatar(canvas, icon); + trade_draw_pkmn_avatar(canvas, model->pdata); trade_draw_frame(canvas, "READY"); break; case GAMEBOY_WAITING: - trade_draw_pkmn_avatar(canvas, icon); + trade_draw_pkmn_avatar(canvas, model->pdata); trade_draw_frame(canvas, "WAITING"); break; case GAMEBOY_TRADE_PENDING: - trade_draw_pkmn_avatar(canvas, icon); + trade_draw_pkmn_avatar(canvas, model->pdata); trade_draw_frame(canvas, "DEAL?"); break; case GAMEBOY_TRADING: furi_hal_light_set(LightGreen, 0x00); if(model->ledon) { furi_hal_light_set(LightBlue, 0xff); - canvas_draw_icon(canvas, 0, 0, &I_gb_step_1); + canvas_draw_icon(canvas, 0, 5, &I_gb_step_1); } else { furi_hal_light_set(LightBlue, 0x00); - canvas_draw_icon(canvas, 0, 0, &I_gb_step_2); + canvas_draw_icon(canvas, 0, 5, &I_gb_step_2); } trade_draw_frame(canvas, "TRADING"); break; + case GAMEBOY_TRADE_CANCEL: + trade_draw_frame(canvas, "CANCEL"); + break; case GAMEBOY_COLOSSEUM: trade_draw_frame(canvas, "FIGHT!"); break; @@ -305,16 +477,16 @@ static void trade_draw_callback(Canvas* canvas, void* view_model) { */ static uint8_t getConnectResponse(struct trade_ctx* trade) { furi_assert(trade); - uint8_t ret; + uint8_t ret = trade->in_data; switch(trade->in_data) { case PKMN_CONNECTED: + case PKMN_CONNECTED_II: with_view_model( trade->view, struct trade_model * model, { model->gameboy_status = GAMEBOY_CONN_TRUE; }, false); - ret = PKMN_CONNECTED; break; case PKMN_MASTER: ret = PKMN_SLAVE; @@ -361,8 +533,15 @@ static uint8_t getMenuResponse(struct trade_ctx* trade) { switch(trade->in_data) { case PKMN_CONNECTED: - response = PKMN_CONNECTED; + case PKMN_CONNECTED_II: + response = trade->in_data; break; + case ITEM_2_HIGHLIGHTED: + if(trade->pdata->gen == GEN_I) { + response = trade->in_data; + break; + } + [[fallthrough]]; case PKMN_TRADE_CENTRE: with_view_model( trade->view, @@ -397,15 +576,19 @@ static uint8_t getMenuResponse(struct trade_ctx* trade) { static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { furi_assert(trade); - uint8_t* trade_block_flat = (uint8_t*)trade->trade_block; - uint8_t* input_block_flat = (uint8_t*)trade->input_block; - uint8_t* input_party_flat = (uint8_t*)trade->input_block->party; + uint8_t* trade_block_flat = (uint8_t*)trade->pdata->trade_block; + uint8_t* input_block_flat = (uint8_t*)trade->input_pdata->trade_block; + uint8_t* input_party_flat = (uint8_t*)trade->input_pdata->party; struct trade_model* model = NULL; uint8_t in = trade->in_data; uint8_t send = in; static bool patch_pt_2; - static int counter; + static size_t counter; static uint8_t in_pkmn_idx; + const struct important_bytes* bytes = NULL; + + if(trade->pdata->gen == GEN_I) bytes = &gen_i; + if(trade->pdata->gen == GEN_II) bytes = &gen_ii; /* TODO: Figure out how we should respond to a no_data_byte and/or how to * send one and what response to expect. @@ -441,8 +624,6 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { if(in == SERIAL_PREAMBLE_BYTE) { counter++; model->gameboy_status = GAMEBOY_WAITING; - } else if((in & PKMN_SEL_NUM_MASK) == PKMN_SEL_NUM_MASK) { - send = PKMN_TABLE_LEAVE; } if(counter == SERIAL_RNS_LENGTH) { trade->trade_centre_state = TRADE_RANDOM; @@ -455,7 +636,7 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { * numbers are for synchronizing the PRNG between the two systems, * we do not use these numbers at this time. * - * This waits through the end of the trade block preamble, a total of 20 + * This waits through the end of the trade block preamble, a total of 19 * bytes. */ case TRADE_RANDOM: @@ -472,7 +653,7 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { send = trade_block_flat[counter]; counter++; - if(counter == sizeof(TradeBlock)) { + if(counter == trade->input_pdata->trade_block_sz) { trade->trade_centre_state = TRADE_PATCH_HEADER; counter = 0; } @@ -503,8 +684,8 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { * the 3x 0xFD that we should be transmitting as part of the patch * list header. */ - if(counter > 7) { - send = plist_index_get(trade->patch_list, (counter - 8)); + if(counter > 8) { + send = plist_index_get(trade->patch_list, (counter - 9)); } /* Patch received data */ @@ -537,8 +718,26 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { * preamble bytes, 7x 0x00, then 189 bytes for the patch list. A * total of 199 bytes transmitted. */ - if(counter == 196) trade->trade_centre_state = TRADE_SELECT; + /* Gen I and II patch lists seem to be the same length */ + if(counter == 196) { + if(trade->pdata->gen == GEN_I) + trade->trade_centre_state = TRADE_SELECT; + else if(trade->pdata->gen == GEN_II) + trade->trade_centre_state = TRADE_MAIL; + + counter = 0; + } + + break; + /* Preambled with 6x 0x20 bytes; 33*6 == 198 bytes of Mail, for each pokemon, + * even if they have no mail set; 14*6 == 84 bytes, for each pokemon's mail, + * the OT Name and ID; a 0xff; 100 zero bytes (unsure if they are always 0). + * This is 6 + 198 + 84 + 1 + 100 == 389. + */ + case TRADE_MAIL: + counter++; + if(counter == 389) trade->trade_centre_state = TRADE_SELECT; break; /* Resets the incoming Pokemon index, and once a BLANK byte is received, @@ -553,16 +752,19 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { } [[fallthrough]]; /* Handle the Game Boy selecting a Pokemon to trade, or leaving the table */ + /* XXX: TODO: Clean this up. Easiest is probably to use vars rather than + * macros to check against and set output to. + */ case TRADE_PENDING: /* If the player leaves the trade menu and returns to the room */ - if(in == PKMN_TABLE_LEAVE) { + if(in == bytes->table_leave) { trade->trade_centre_state = TRADE_RESET; - send = PKMN_TABLE_LEAVE; + send = bytes->table_leave; model->gameboy_status = GAMEBOY_READY; /* If the player selected a Pokemon to send from the Game Boy */ - } else if((in & PKMN_SEL_NUM_MASK) == PKMN_SEL_NUM_MASK) { + } else if((in & bytes->sel_num_mask) == bytes->sel_num_mask) { in_pkmn_idx = in; - send = PKMN_SEL_NUM_ONE; // We always send the first Pokemon + send = bytes->sel_num_one; // We always send the first pokemon model->gameboy_status = GAMEBOY_TRADE_PENDING; /* BLANKs are sent in a few places, we want to do nothing about them * unless the Game Boy already sent us an index they want to trade. @@ -578,10 +780,10 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { /* Handle the Game Boy accepting or rejecting a trade deal */ case TRADE_CONFIRMATION: - if(in == PKMN_TRADE_REJECT) { + if(in == bytes->trade_reject) { trade->trade_centre_state = TRADE_SELECT; model->gameboy_status = GAMEBOY_WAITING; - } else if(in == PKMN_TRADE_ACCEPT) { + } else if(in == bytes->trade_accept) { trade->trade_centre_state = TRADE_DONE; } break; @@ -595,21 +797,8 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { model->gameboy_status = GAMEBOY_TRADING; /* Copy the traded-in Pokemon's main data to our struct */ - trade->trade_block->party_members[0] = trade->input_block->party_members[in_pkmn_idx]; - memcpy( - &(trade->trade_block->party[0]), - &(trade->input_block->party[in_pkmn_idx]), - sizeof(struct pokemon_structure)); - memcpy( - &(trade->trade_block->nickname[0]), - &(trade->input_block->nickname[in_pkmn_idx]), - sizeof(struct name)); - memcpy( - &(trade->trade_block->ot_name[0]), - &(trade->input_block->ot_name[in_pkmn_idx]), - sizeof(struct name)); - model->curr_pokemon = pokemon_table_get_num_from_index( - trade->pokemon_table, trade->trade_block->party_members[0]); + pokemon_stat_memcpy(trade->pdata, trade->input_pdata, in_pkmn_idx); + model->curr_pokemon = pokemon_stat_get(trade->pdata, STAT_NUM, NONE); /* Schedule a callback outside of ISR context to rebuild the patch * list with the new Pokemon that we just accepted. @@ -618,6 +807,14 @@ static uint8_t getTradeCentreResponse(struct trade_ctx* trade) { } break; + case TRADE_CANCEL: + if(in == bytes->table_leave) { + trade->trade_centre_state = TRADE_RESET; + model->gameboy_status = GAMEBOY_READY; + } + send = bytes->table_leave; + break; + default: // Do Nothing break; @@ -655,6 +852,9 @@ static void transferBit(void* context, uint8_t in_byte) { gblink_transfer(trade->gblink_handle, getTradeCentreResponse(trade)); break; } + + /* Each byte that comes in, bump the backlight timer so it stays on during a trade */ + furi_timer_pending_callback(trade_backlight_bump_callback, trade, 0); } void trade_enter_callback(void* context) { @@ -671,16 +871,11 @@ void trade_enter_callback(void* context) { model->gameboy_status = GAMEBOY_READY; } trade->trade_centre_state = TRADE_RESET; - model->pokemon_table = trade->pokemon_table; - model->curr_pokemon = pokemon_table_get_num_from_index( - trade->pokemon_table, trade->trade_block->party_members[0]); + model->curr_pokemon = pokemon_stat_get(trade->pdata, STAT_NUM, NONE); model->ledon = false; view_commit_model(trade->view, true); - /* TODO: This should be moved further back to struct pokemon_fap for whole - * app flexibility since it would probably be written to by a different scene - */ gblink_def.pins = trade->gblink_pins; gblink_def.callback = transferBit; gblink_def.cb_context = trade; @@ -696,7 +891,7 @@ void trade_enter_callback(void* context) { furi_timer_start(trade->draw_timer, furi_ms_to_ticks(250)); /* Create a trade patch list from the current trade block */ - plist_create(&(trade->patch_list), trade->trade_block); + plist_create(&(trade->patch_list), trade->pdata); } void disconnect_pin(const GpioPin* pin) { @@ -726,27 +921,29 @@ void trade_exit_callback(void* context) { } void* trade_alloc( - TradeBlock* trade_block, - const PokemonTable* table, + PokemonData* pdata, struct gblink_pins* gblink_pins, ViewDispatcher* view_dispatcher, uint32_t view_id) { - furi_assert(trade_block); + furi_assert(pdata); struct trade_ctx* trade = malloc(sizeof(struct trade_ctx)); memset(trade, '\0', sizeof(struct trade_ctx)); trade->view = view_alloc(); - trade->trade_block = trade_block; - trade->input_block = malloc(sizeof(TradeBlock)); - trade->pokemon_table = table; + trade->pdata = pdata; + trade->input_pdata = pokemon_data_alloc(pdata->gen); trade->patch_list = NULL; trade->gblink_pins = gblink_pins; + trade->notifications = furi_record_open(RECORD_NOTIFICATION); view_set_context(trade->view, trade); view_allocate_model(trade->view, ViewModelTypeLockFree, sizeof(struct trade_model)); + with_view_model( + trade->view, struct trade_model * model, { model->pdata = pdata; }, false); view_set_draw_callback(trade->view, trade_draw_callback); + view_set_input_callback(trade->view, trade_input_callback); view_set_enter_callback(trade->view, trade_enter_callback); view_set_exit_callback(trade->view, trade_exit_callback); @@ -762,7 +959,9 @@ void trade_free(ViewDispatcher* view_dispatcher, uint32_t view_id, void* trade_c view_dispatcher_remove_view(view_dispatcher, view_id); + furi_record_close(RECORD_NOTIFICATION); + view_free(trade->view); - free(trade->input_block); + pokemon_data_free(trade->input_pdata); free(trade); } diff --git a/views/trade.h b/views/trade.h index 8aa32f5c937..1c428420d49 100644 --- a/views/trade.h +++ b/views/trade.h @@ -4,11 +4,10 @@ #pragma once #include -#include "../pokemon_app.h" +#include "../pokemon_data.h" void* trade_alloc( - TradeBlock* trade_block, - const PokemonTable* table, + PokemonData* pdata, struct gblink_pins* gblink_pins, ViewDispatcher* view_dispatcher, uint32_t view_id); diff --git a/views/trade_patch_list.c b/views/trade_patch_list.c index 2251d8bf5fb..4bde3984106 100644 --- a/views/trade_patch_list.c +++ b/views/trade_patch_list.c @@ -46,10 +46,10 @@ uint8_t plist_index_get(struct patch_list* plist, int offset) { return plist->index; } -void plist_create(struct patch_list** pplist, TradeBlock* trade_block) { - furi_assert(trade_block); - uint8_t* trade_party_flat = (uint8_t*)trade_block->party; - int i; +void plist_create(struct patch_list** pplist, PokemonData* pdata) { + furi_assert(pdata); + uint8_t* trade_party_flat = pdata->party; + size_t i; /* If plist is non-NULL that means its already been created. Tear it down * first. @@ -60,15 +60,13 @@ void plist_create(struct patch_list** pplist, TradeBlock* trade_block) { } *pplist = plist_alloc(); - /* NOTE: 264 magic number is the length of the party block, 44 * 6 */ /* The first half of the patch list covers offsets 0x00 - 0xfb, which * is expressed as 0x01 - 0xfc. An 0xFF byte is added to signify the * end of the first part. The second half of the patch list covers - * offsets 0xfc - 0x107. Which is expressed as 0x01 - 0xc. A 0xFF byte - * is added to signify the end of the second part/ + * offsets 0xfc - 0x107 (more in gen ii). Which is expressed as + * 0x01 - 0xc. A 0xFF byte is added to signify the end of the second part. */ - for(i = 0; i < 264; i++) { - FURI_LOG_D(TAG, "%02X", trade_party_flat[i]); + for(i = 0; i < pdata->party_sz; i++) { if(i == 0xFC) { FURI_LOG_D(TAG, "[plist] part 1 end"); plist_append(*pplist, 0xFF); diff --git a/views/trade_patch_list.h b/views/trade_patch_list.h index 649c990f852..d28e2ce2edf 100644 --- a/views/trade_patch_list.h +++ b/views/trade_patch_list.h @@ -5,6 +5,7 @@ #include #include "../pokemon_app.h" +#include "../pokemon_data.h" struct patch_list { uint8_t index; @@ -19,6 +20,6 @@ void plist_free(struct patch_list* plist); uint8_t plist_index_get(struct patch_list* plist, int offset); -void plist_create(struct patch_list** pplist, TradeBlock* trade_block); +void plist_create(struct patch_list** pplist, PokemonData* pdata); #endif /* TRADE_PATCH_LIST_H */