Преглед изворни кода

Merge pull request #17 from R4g3D/main

Extended Functionality
Esteban Fuentealba пре 2 година
родитељ
комит
50b4da1846

+ 95 - 20
README.md

@@ -16,9 +16,9 @@
 
 ## Introduction
 
-This is a Pokemon exchange application from Flipper Zero to Game Boy [(Generacn 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 [(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.
 
-It is a Proof of Concept (POC) for using views, GPIO, and FURI (Flipper Universal Registry Implementation).
+It currently trades a Pokemon based on your choice of Pokemon, Level, Stats and 4 Moves.
 
 ## Installation Directions
 
@@ -49,7 +49,7 @@ And use [**qFlipper**](https://flipperzero.one/update) to copy the generated **p
 These instructions assume that you are starting at the Flipper Zero desktop. Otherwise, press the Back button until you are at the desktop.
 
 - Press the `OK` button on the Flipper to open the main menu.
-- Choose `Aplicaciones` from the menu.
+- Choose `Applications` from the menu.
 - Choose `Game Boy` from the submenu.
 - Choose `Pokemon Trading`
 - The Flipper Zero should show the selection of Pokemon that you want to trade, and by default, it appears as bulbasaur.
@@ -63,69 +63,145 @@ These instructions assume that you are starting at the Flipper Zero desktop. Oth
 - 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.
+
     <p align='center'>
          <br />
         <img src="./docs/images/flipper-zero-flat-2.png" width="400" /><br />
     </p>
+
+- The Flipper Zero should show the selection of the Pokemon's level that you want to trade, and by default, it appears as level 1.
+
+    <p align='center'>
+        <br />
+        <img src="./docs/images/flipper-zero-flat-3.png" width="400" />
+        <br />
+    </p>
+
+- Press the `LEFT`/`RIGHT` buttons to paginate the selection of the Pokemon's level by 1.
+- Press the `UP`/`DOWN` buttons to paginate the selection of the Pokemon's level by 10.
+- Press the `OK` button to select the Pokemon's level to trade.
+
+    <p align='center'>
+        <br />
+        <img src="./docs/images/flipper-zero-flat-4.png" width="400" />
+        <br />
+    </p>
+
+- The Flipper Zero should show the selection for the Pokemon's moves that you want to trade, this will happen 4 times with default bing no move.
+
+    <p align='center'>
+        <br />
+        <img src="./docs/images/flipper-zero-flat-5.png" width="400" />
+        <br />
+    </p>
+
+- Press the `LEFT`/`RIGHT` buttons to paginate the selection of the Pokemon's current move selection by 1.
+- Press the `UP`/`DOWN` buttons to paginate the selection of the Pokemon's current move selection by 10.
+- Press the `OK` button to select the Pokemon's current move selection to trade.
+
+    <p align='center'>
+        <br />
+        <img src="./docs/images/flipper-zero-flat-6.png" width="400" />
+        <br />
+    </p>
+
+- The Flipper Zero should show the selection for the Pokemon's stats that you want to trade, and by default, it appears as random IV and zero EV.
+
+    <p align='center'>
+        <br />
+        <img src="./docs/images/flipper-zero-flat-7.png" width="400" />
+        <br />
+    </p>
+
+- Press the `RIGHT`/`UP` buttons to paginate the selection of the Pokemon's stats selection by 1 positively.
+- Press the `LEFT`/`DOWN` buttons to paginate the selection of the Pokemon's stats selection by 1 negatively.
+- Press the `OK` button to select the Pokemon's current move selection to trade.
+
+    <p align='center'>
+        <br />
+        <img src="./docs/images/flipper-zero-flat-8.png" width="400" />
+        <br />
+    </p>
+
 - The Flipper Zero will display the view to connect the Game Boy.
+
     <p align='center'>
         <br />
-        <img src="./docs/images/flipper-zero-flat-3.png" width="400" /><br />
+        <img src="./docs/images/flipper-zero-flat-9.png" width="400" /><br />
     </p>
+
 - 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**.
+
     <p align='center'>
         <br />
         <img src="./docs/images/game_boy_pokemon_center.png" width="400" /><br />
     </p>
+
 - 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.
 
-.
     <p align='center'>
         <br />
         <img src="./docs/images/game_boy_save.png" width="400" /><br />
     </p>
+
 - The Flipper Zero will show that we are connected.
+
     <p align='center'>
         <br />
-        <img src="./docs/images/flipper-zero-flat-4.png" width="400" /><br />
+        <img src="./docs/images/flipper-zero-flat-10.png" width="400" /><br />
     </p>
+
 - On the Game Boy, we will be asked which option we want, and we select **TRADE CENTER**.
+
     <p align='center'>
         <br />
         <img src="./docs/images/game_boy_save_trade.png" width="400" /><br />
     </p>
+
 - You will enter the Trade Center where you must press the A button on the Game Boy on your side of the table.
+
     <p align='center'>
         <br />
         <img src="./docs/images/game_boy_trade_room_2.png" width="400" /><br />
     </p>
+
 - Flipper Zero will remain on a waiting screen with the Pokemon you selected.
+
     <p align='center'>
         <br />
-        <img src="./docs/images/flipper-zero-flat-5.png" width="400" /><br />
+        <img src="./docs/images/flipper-zero-flat-10.png" width="400" /><br />
     </p>
+
 - 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**.
+
     <p align='center'>
         <br />
         <img src="./docs/images/game_boy_trade_list_select_trade.png" width="400" /><br />
     </p>
+
 - You must confirm the selected trade by selecting **TRADE**.
+
     <p align='center'>
         <br />
         <img src="./docs/images/game_boy_trade_list_select_trade_confirm.png" width="400" /><br />
     </p>
+
 - Flipper Zero will remain on a waiting screen with the Pokemon you selected.
+
     <p align='center'>
         <br />
-        <img src="./docs/images/flipper-zero-flat-6.png" width="400" /><br />
+        <img src="./docs/images/flipper-zero-flat-11.png" width="400" /><br />
     </p>
+
 - Finally, the Pokemon exchange will start from **Flipper Zero** to the **Game Boy**.
+
     <p align='center'>
         <br />
-        <img src="./docs/images/flipper-zero-flat-7.png" width="400" /><br />
+        <img src="./docs/images/flipper-zero-flat-12.png" width="400" /><br />
     </p>
 
     If the Flipper Zero gets stuck at the end of the exchange, you must reboot it by pressing the <img src="./docs/images/left.png" /> LEFT + <img src="./docs/images/back.png" /> BACK key combination.
+
     <p align='center'>
         <br />
         <img src="./docs/images/reboot.png" width="400" /><br />
@@ -226,13 +302,18 @@ For each image, the color `#aaa` was transformed to `#fff` so that Flipper Zero
 - Game Boy Advance (GBA)
 
 ## Implemented by
-<a href="https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/issues?q=is%3Aissue+label%3AImplemented+is%3Aclosed+is%3Aopen+" target="_blank"><img src="./docs/images/implemented.svg" /></a>
+<a href="https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/">EstebanFuentealba</a><br />
+<a href="https://github.com/R4g3D/Flipper-Zero-Game-Boy-Pokemon-Trading/">R4g3D</a>
 
 ## TODO
-- [ ] Refactor the code
-- [x] The OK button stops working when exiting the app, so it needs to be restarted 🤔
-- [ ] Set each Pokemon's characteristics, attacks, and default levels
-- [ ] Improve animations
+- [x] Change the default traded Pokemon's naming to be no nickname
+- [x] Add view to allow the traded Pokemon's level to be chosen between 3 and 100
+- [x] Add view to allow the traded Pokemon's hidden stats to be chosen (IV and EV) from some options
+- [x] Add view to allow the traded Pokemon's moveset to be chosen (all 4 moves) allowing no move as an option
+- [ ] Debug traded Pokemon level issue where after a battle the Pokemon's level drops (doesn't affect all traded Pokemon)
+- [x] Add images for the level selection screen, stats selection screen, and move selection screens as per the original README
+- [ ] Optimise the level selection screen to be a number slider input instead of the current slideshow style selector
+- [ ] Add a view to allow for a custom Pokemon nickname (11 chars, 10 chars max used, fill and terminate with TERM_)
 
 ## Links
 
@@ -244,9 +325,3 @@ For each image, the color `#aaa` was transformed to `#fff` so that Flipper Zero
 - [Disassembly of Pokemon Yellow](https://github.com/pret/pokeyellow)
 - [Arduino-Spoofing-Gameboy-Pokemon-Trades](https://github.com/EstebanFuentealba/Arduino-Spoofing-Gameboy-Pokemon-Trades)
 - [🎮 Gameboy link cable breakout PCB](https://github.com/Palmr/gb-link-cable)
-
-<p align='center'>
-<br />
-<br />
-From Talcahuano 🇨🇱 with ❤ 
-</p>

+ 0 - 38
README_catalog.md

@@ -1,38 +0,0 @@
-# 🐬 Flipper Zero - Pokemon Trading in Game Boy
-
-## Introduction
-
-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.
-
-It is a Proof of Concept (POC) for using views, GPIO, and FURI (Flipper Universal Registry Implementation).
-
-
-## Connection: Flipper Zero GPIO - Game Boy
-
-The pins should be connected as follows:
-
-| Cable Game Link (Socket) | Flipper Zero GPIO |
-| ------------------------ | ----------------- |
-| 6 (GND)                  | 8 (GND)           |
-| 5 (CLK)                  | 6 (B2)            |
-| 3 (SI)                   | 7 (C3)            |
-| 2 (SO)                   | 5 (B3)            |
-
-## 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:
-
-- 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.
-
-
-##  Tested In
-- Game Boy Color (GBC)
-- Game Boy Advance (GBA)
-
-

+ 0 - 249
README_es.md

@@ -1,249 +0,0 @@
-# 🐬 Flipper Zero - Pokemon Trading in Game Boy
-
-<p align="center">
-<a target="_blank" href="https://www.reddit.com/r/flipperzero/comments/121ncot/flipper_zero_game_boy_pokemon_trading/">
-  <img align="center" alt="Flipper Zero - Pokemon Trading Game Boy" src="./docs/images/youtube.png" />
-  <br />
-</p>
-<div align="center">
-
-**FW Official** | **FW Unleashed** | **FW RogueMaster**
-:- | :- | :- 
-[![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)
-</div>
-
-## Introducción
-
-Esta es una aplicación de intercambio de Pokemon's desde de Flipper Zero a Game Boy [(Generación I)](https://bulbapedia.bulbagarden.net/wiki/Generation_I). Flipper Zero emula un Game Boy "Esclavo" conectado a **Cable Game Link** para poder intercambiar cualquier Pokemon de la Primera Generación (Red, Blue, Yellow) a un Game Boy Real.
-
-Es una Prueba de concepto (POC) para utilizar vistas, GPIO y FURI (Flipper Universal Registry Implementation).
-
-## Instrucciones de instalación
-
-Este proyecto está destinado a ser superpuesto encima de un repositorio de firmware existente, en mi caso la versión **Release 0.79.1**.
-
-- Clona el [Repositorio del firmware de Flipper Zero](https://github.com/flipperdevices/flipperzero-firmware). Consulta este [tutorial](https://github.com/jamisonderek/flipper-zero-tutorials/tree/main/firmware/updating/README.md) para actualizar el firmware.
-- Copia la [carpeta "pokemon"](..) en la carpeta `/applications_user/pokemon` del firmware que clonaste.
-- Corre el comando `fbt launch_app` para correr en tu Flipper Zero.
-
-```bash
-./fbt launch_app APPSRC=pokemon
-```
-
-- NOTA: Si sólo quieres generar el archivo `fap` debes correr el siguiente comando.
-
-```bash
-./fbt fap_pokemon
-```
-
-y usa [**qFlipper**](https://flipperzero.one/update) para copiar el archivo **pokemon.fap** generado a la carpeta `SD Card/apps/Game Boy`.
-
-<p align='center'>
-<img src="./docs/images/qFlipper.png" width="400" /><br />
-</p>
-
-## Instrucciones de Uso
-
-Estas instrucciones asumen que está comenzando en el escritorio de Flipper Zero. De lo contrario, presione el botón Atrás hasta que esté en el escritorio.
-
-- Presione el botón `OK` en el flipper para abrir el menú principal.
-- Elija `Aplicaciones` en el menú.
-- Elija `Game Boy` en el submenú.
-- Elija `Pokemon Trading`
-- El Flipper Zero debe mostrar la selección de Pokemon que se desea intercambiar y por defecto parece bulbasaur.
-
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-flat-1.png" width="400" />
-        <br />
-    </p>
-
-- Pulse los botones `IZQUIERDA`/`DERECHA` para paginar de 1 en 1 la selección de Pokemon.
-- Pulse los botones `ARRIBA`/`ABAJO` para paginar de 10 en 10 la selección de Pokemon.
-- Pulse el botón `OK` para seleccionar el Pokemon a Intercambiar.
-    <p align='center'>
-         <br />
-        <img src="./docs/images/flipper-zero-flat-2.png" width="400" /><br />
-    </p>
-- En el Flipper Zero se muestra la vista para conectar el Game Boy.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-flat-3.png" width="400" /><br />
-    </p>
-- En tu Game Boy debes conectar el **Cable Game Link** al Game Boy, en el juego dirigirte a un **Centro Pokémon** que tengas más cercano.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/game_boy_pokemon_center.png" width="400" /><br />
-    </p>
-- Habla con la chica que está en el mostrador de la derecha. La chica nos dirá que para poder jugar antes tendremos que salvar el juego, le contestaremos que _SI_ pulsando el botón _A_.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/game_boy_save.png" width="400" /><br />
-    </p>
-- El Flipper Zero nos mostrará que estámos conectados.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-flat-4.png" width="400" /><br />
-    </p>
-- En el Game Boy nos preguntará que opción queremos y Seleccionamos **CENT. CAMBIO**.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/game_boy_save_trade.png" width="400" /><br />
-    </p>
-- Entrarás a la sala de Intercambio donde debes presionar el botón A del Game Boy en el lado de tu mesa.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/game_boy_trade_room_2.png" width="400" /><br />
-    </p>
-- Flipper Zero quedará en una pantalla de espera con el Pokemon que seleccionaste.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-flat-5.png" width="400" /><br />
-    </p>
-- Se te mostrarán tus Pokemon y el Pokemon que seleccionaste en el Flipper Zero, en este Caso **Mew**. Debes seleccionar el pokemon que quieres intercambiar y presionar **TRATO**.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/game_boy_trade_list_select_trade.png" width="400" /><br />
-    </p>
-- Debes confirmar el intercambio seleccionado **TRATO**.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/game_boy_trade_list_select_trade_confirm.png" width="400" /><br />
-    </p>
-- Flipper Zero quedará en una pantalla de espera con el Pokemon que seleccionaste.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-flat-6.png" width="400" /><br />
-    </p>
-- Finalmente comenzará el intercambio de Pokemon desde **Flipper Zero** al **Game Boy**.
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-flat-7.png" width="400" /><br />
-    </p>
-- **NOTA**: Si al final del Intercambio se te bloquea el Flipper Zero debes Rebootear presionando la combinación de teclas <img src="./docs/images/left.png" /> IZQUIERDA + <img src="./docs/images/back.png" /> ATRAS
-    <p align='center'>
-        <br />
-        <img src="./docs/images/reboot.png" width="400" /><br />
-    </p>
-
-## ¿Cómo trabaja?
-
-El método utilizado para comunicar 2 Game Boy se basa en el protocolo SPI, que es un protocolo de comunicación serial muy simple en el que un dispositivo maestro se comunica con uno o más dispositivos esclavos. El protocolo es bidireccional y sincrónico, y utiliza tres señales básicas:
-
-- Una señal de reloj (CLK).
-- Una señal de salida (Serial Out o SO).
-- Una señal de entrada (Serial In o SI).
-
-En el Game Boy, los juegos almacenan los datos en un registro de cambio interno que se utiliza para enviar y recibir información. El protocolo SPI utilizado por el Game Boy utiliza la señal de reloj para indicar cuándo se transfieren los datos.
-
-El protocolo de enlace de Game Boy es síncrono y requiere que el dispositivo esclavo responda al mismo ritmo que el dispositivo maestro. El dispositivo maestro suministra un reloj de 8KHz (velocidad de transferencia de datos de 1KB/s). La ventana de tiempo para responder es de solo **~120μs**. Sin embargo, el dispositivo esclavo no tiene restricciones y puede responder cuando recibe los datos. El reloj puede variar y no hay un límite inferior.
-
-<p align='center'>
-<br />
-<img src="./docs/images/gb_spi.png" width="400" /><br />
-</p>
-
-_Una transferencia de ejemplo de GB SPI. Aquí, el maestro envía 0xD9 (217) y el esclavo envía 0x45 (69)._
-
-<br />
-
-Se puede conocer mas al respecto en el siguiente Video [**Analyzing the Different Versions of the Link Cable**](https://youtu.be/h1KKkCfzOws?t=151).
-
-## Placa para Flipper Zero con Socket PortData EXT Link
-
-Para la placa del Fipper Zero se utilizó un [PortData EXT Link](https://es.aliexpress.com/item/1005004116983895.html) y una [place de prototipo](https://es.aliexpress.com/item/32478242317.html) de 2x8.
-
-<p align='center'>
-<br />
-<img src="./docs/images/EXT-Link.png" width="400" /><br />
-</p>
-
-_PortData EXT Link para Game Boy Color, Game Boy Pocket, GBC, GBP, GBL._
-
-<p align='center'>
-<br />
-<img src="./docs/images/pcb.png" width="400" /><br />
-</p>
-<p align='center'>
-<br />
-<img src="./docs/images/flipper-zero-pcb.png" width="400" /><br />
-</p>
-Usé una resistencia de 33kΩ en CLK, pero es opcional, se puede conectar directamente.
-
-## Conexión: Flipper Zero GPIO - Game Boy
-
-Se deben conectar los Pines de la siguiente manera
-
-<p align='center'>
-<br />
-<img src="./docs/images/wgbl-0.png" width="400" /><br />
-</p>
-
-<picture>
-    <source media="(prefers-color-scheme: dark)" srcset="./docs/images/GPIO-GBPIN_light-v2.png">
-    <source media="(prefers-color-scheme: light)" srcset="./docs/images/GPIO-GBPIN-v2.png">
-    <img
-        alt="Connect Flipper Zero GPIO to Game Boy Pins"
-        src="./docs/images/GPIO-GBPIN-v2.png">
-</picture>
-
-| Cable Game Link (Socket) | Flipper Zero GPIO |
-| ------------------------ | ----------------- |
-| 6 (GND)                  | 8 (GND)           |
-| 5 (CLK)                  | 6 (B2)            |
-| 3 (SI)                   | 7 (C3)            |
-| 2 (SO)                   | 5 (B3)            |
-
-
-## Conectar a Flipper Zero sin Socket PortData EXT Link
-
-Pudes cortar un cable directamente sin usar el socket pero debes tener en cuenta que el es un cable cruzado SI-SO.
-
-<p align='center'>
-<br />
-<img src="./docs/images/cut-cable-v3.png" width="400" /><br />
-</p>
-
-*"Cable Game Link" cortado y conectado directamente a los pines de Flipper Zero.*
-
-
-**NOTA**: No guiarse por los colores porque dependiendo del fabricante estos pueden cambiar, con un multímetro medir continuidad e identificar que cable es de que pin
-
-
-## GUI
-
-Para generar la Interfaz gráfica se utilizó la herramienta [**FUI-Editor**](https://ilin.pt/stuff/fui-editor/).
-Además se utilizaron los sprites originales del juego _Pokemon Yellow_ que se encuentran en el repositorio [**Disassembly of Pokemon Yellow**](https://github.com/pret/pokeyellow/tree/master/gfx/pokemon/front).
-
-De cada imagen se transformó el color `#aaa` a `#fff` para que Flipper Zero la renderizara bien. Para eso se utilizó un **Batch** para [Photopea](https://www.photopea.com/), el editor de imagenes online.
-
-##  Implementado en
-- Game Boy Color (GBC)
-- Game Boy Advance (GBA)
-
-## Implementado por
-<a href="https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/issues?q=is%3Aissue+label%3AImplemented+is%3Aclosed+is%3Aopen+" target="_blank"><img src="./docs/images/implemented.svg" /></a>
-
-## TODO
-
-- [ ] Refactorizar el código
-- [ ] Al salir de la app el botón `OK` deja de funcionar por lo que hay que reiniciarlo 🤔
-- [ ] Setear a cada pokemon sus características, ataques, niveles por defecto
-- [ ] Mejorar animaciones
-
-## Links
-
-- [Flipper Zero firmware source code](https://github.com/flipperdevices/flipperzero-firmware)
-- Adan Scotney's pokemon [trade protocol specification](http://www.adanscotney.com/2014/01/spoofing-pokemon-trades-with-stellaris.html) and implementation
-- Derek Jamison - [Youtube Channel](https://www.youtube.com/@MrDerekJamison)
-- Matt Penny - [GBPlay Blog](https://blog.gbplay.io/)
-- [Pokémon data structure (Generation I)](<https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_data_structure_(Generation_I)>)
-- [Disassembly of Pokemon Yellow](https://github.com/pret/pokeyellow)
-- [Arduino-Spoofing-Gameboy-Pokemon-Trades](https://github.com/EstebanFuentealba/Arduino-Spoofing-Gameboy-Pokemon-Trades)
-- [🎮 Gameboy link cable breakout PCB](https://github.com/Palmr/gb-link-cable)
-
-<p align='center'>
-<br />
-<br />
-Desde Talcahuano 🇨🇱 con ❤ 
-</p>

+ 0 - 5
changelog.md

@@ -1,5 +0,0 @@
-# Changelog - Patch Notes
-
-## Version 1.2.0
-- **Cleanup data structs:** This refactors the main data blocks for defining pokemon, the icon, their species/hex value, as well as the large trade array in to more human friendly structs. Laying some groundwork to be able to adjust pokemon details pre-trade by @kbembedded .
-- **Bug Fixes:** Fix furi crash, Fixes #9 by @kbembedded .

BIN
docs/images/flipper-zero-flat-1.png


BIN
docs/images/flipper-zero-flat-10.png


BIN
docs/images/flipper-zero-flat-11.png


BIN
docs/images/flipper-zero-flat-12.png


BIN
docs/images/flipper-zero-flat-13.png


BIN
docs/images/flipper-zero-flat-2.png


BIN
docs/images/flipper-zero-flat-3.png


BIN
docs/images/flipper-zero-flat-4.png


BIN
docs/images/flipper-zero-flat-5.png


BIN
docs/images/flipper-zero-flat-6.png


BIN
docs/images/flipper-zero-flat-7.png


BIN
docs/images/flipper-zero-flat-8.png


BIN
docs/images/flipper-zero-flat-9.png


BIN
docs/images/flipper-zero-flat.xcf


Разлика између датотеке није приказан због своје велике величине
+ 0 - 7
docs/images/implemented.svg


+ 380 - 151
pokemon_app.cpp

@@ -1,160 +1,329 @@
 #include "pokemon_app.h"
 
 struct pokemon_lut pokemon_table[] = {
-    {"Bulbasaur", &I_bulbasaur, 0x99},
-    {"Ivysaur", &I_ivysaur, 0x09},
-    {"Venusaur", &I_venusaur, 0x9A},
-    {"Charmander", &I_charmander, 0xB0},
-    {"Charmeleon", &I_charmeleon, 0xB2},
-    {"Charizard", &I_charizard, 0xB4},
-    {"Squirtle", &I_squirtle, 0xB1},
-    {"Wartortle", &I_wartortle, 0xB3},
-    {"Blastoise", &I_blastoise, 0x1C},
-    {"Caterpie", &I_caterpie, 0x7B},
-    {"Metapod", &I_metapod, 0x7C},
-    {"Butterfree", &I_butterfree, 0x7D},
-    {"Weedle", &I_weedle, 0x70},
-    {"Kakuna", &I_kakuna, 0x71},
-    {"Beedrill", &I_beedrill, 0x72},
-    {"Pidgey", &I_pidgey, 0x24},
-    {"Pidgeotto", &I_pidgeotto, 0x96},
-    {"Pidgeot", &I_pidgeot, 0x97},
-    {"Rattata", &I_rattata, 0xA5},
-    {"Raticate", &I_raticate, 0xA6},
-    {"Spearow", &I_spearow, 0x05},
-    {"Fearow", &I_fearow, 0x23},
-    {"Ekans", &I_ekans, 0x6C},
-    {"Arbok", &I_arbok, 0x2D},
-    {"Pikachu", &I_pikachu, 0x54},
-    {"Raichu", &I_raichu, 0x55},
-    {"Sandshrew", &I_sandshrew, 0x60},
-    {"Sandslash", &I_sandslash, 0x61},
-    {"Nidoran ♀", &I_nidoranf, 0x0F},
-    {"Nidorina", &I_nidorina, 0xA8},
-    {"Nidoqueen", &I_nidoqueen, 0x10},
-    {"Nidoran ♂", &I_nidoranm, 0x03},
-    {"Nidorino", &I_nidorino, 0xA7},
-    {"Nidoking", &I_nidoking, 0x07},
-    {"Clefairy", &I_clefairy, 0x04},
-    {"Clefable", &I_clefable, 0x8E},
-    {"Vulpix", &I_vulpix, 0x52},
-    {"Ninetales", &I_ninetales, 0x53},
-    {"Jigglypuff", &I_jigglypuff, 0x64},
-    {"Wigglytuff", &I_wigglytuff, 0x65},
-    {"Zubat", &I_zubat, 0x6B},
-    {"Golbat", &I_golbat, 0x82},
-    {"Oddish", &I_oddish, 0xB9},
-    {"Gloom", &I_gloom, 0xBA},
-    {"Vileplume", &I_vileplume, 0xBB},
-    {"Paras", &I_paras, 0x6D},
-    {"Parasect", &I_parasect, 0x2E},
-    {"Venonat", &I_venonat, 0x41},
-    {"Venomoth", &I_venomoth, 0x77},
-    {"Diglett", &I_diglett, 0x3B},
-    {"Dugtrio", &I_dugtrio, 0x76},
-    {"Meowth", &I_meowth, 0x4D},
-    {"Persian", &I_persian, 0x90},
-    {"Psyduck", &I_psyduck, 0x2F},
-    {"Golduck", &I_golduck, 0x80},
-    {"Mankey", &I_mankey, 0x39},
-    {"Primeape", &I_primeape, 0x75},
-    {"Growlithe", &I_growlithe, 0x21},
-    {"Arcanine", &I_arcanine, 0x14},
-    {"Poliwag", &I_poliwag, 0x47},
-    {"Poliwhirl", &I_poliwhirl, 0x6E},
-    {"Poliwrath", &I_poliwrath, 0x6F},
-    {"Abra", &I_abra, 0x94},
-    {"Kadabra", &I_kadabra, 0x26},
-    {"Alakazam", &I_alakazam, 0x95},
-    {"Machop", &I_machop, 0x6A},
-    {"Machoke", &I_machoke, 0x29},
-    {"Machamp", &I_machamp, 0x7E},
-    {"Bellsprout", &I_bellsprout, 0xBC},
-    {"Weepinbell", &I_weepinbell, 0xBD},
-    {"Victreebel", &I_victreebel, 0xBE},
-    {"Tentacool", &I_tentacool, 0x18},
-    {"Tentacruel", &I_tentacruel, 0x9B},
-    {"Geodude", &I_geodude, 0xA9},
-    {"Graveler", &I_graveler, 0x27},
-    {"Golem", &I_golem, 0x31},
-    {"Ponyta", &I_ponyta, 0xA3},
-    {"Rapidash", &I_rapidash, 0xA4},
-    {"Slowpoke", &I_slowpoke, 0x25},
-    {"Slowbro", &I_slowbro, 0x08},
-    {"Magnemite", &I_magnemite, 0xAD},
-    {"Magneton", &I_magneton, 0x36},
-    {"Farfetch'd", &I_farfetchd, 0x40},
-    {"Doduo", &I_doduo, 0x46},
-    {"Dodrio", &I_dodrio, 0x74},
-    {"Seel", &I_seel, 0x3A},
-    {"Dewgong", &I_dewgong, 0x78},
-    {"Grimer", &I_grimer, 0x0D},
-    {"Muk", &I_muk, 0x88},
-    {"Shellder", &I_shellder, 0x17},
-    {"Cloyster", &I_cloyster, 0x8B},
-    {"Gastly", &I_gastly, 0x19},
-    {"Haunter", &I_haunter, 0x93},
-    {"Gengar", &I_gengar, 0x0E},
-    {"Onix", &I_onix, 0x22},
-    {"Drowzee", &I_drowzee, 0x30},
-    {"Hypno", &I_hypno, 0x81},
-    {"Krabby", &I_krabby, 0x4E},
-    {"Kingler", &I_kingler, 0x8A},
-    {"Voltorb", &I_voltorb, 0x06},
-    {"Electrode", &I_electrode, 0x8D},
-    {"Exeggcute", &I_exeggcute, 0x0C},
-    {"Exeggutor", &I_exeggutor, 0x0A},
-    {"Cubone", &I_cubone, 0x11},
-    {"Marowak", &I_marowak, 0x91},
-    {"Hitmonlee", &I_hitmonlee, 0x2B},
-    {"Hitmonchan", &I_hitmonchan, 0x2C},
-    {"Lickitung", &I_lickitung, 0x0B},
-    {"Koffing", &I_koffing, 0x37},
-    {"Weezing", &I_weezing, 0x8F},
-    {"Rhyhorn", &I_rhyhorn, 0x12},
-    {"Rhydon", &I_rhydon, 0x01},
-    {"Chansey", &I_chansey, 0x28},
-    {"Tangela", &I_tangela, 0x1E},
-    {"Kangaskhan", &I_kangaskhan, 0x02},
-    {"Horsea", &I_horsea, 0x5C},
-    {"Seadra", &I_seadra, 0x5D},
-    {"Goldeen", &I_goldeen, 0x9D},
-    {"Seaking", &I_seaking, 0x9E},
-    {"Staryu", &I_staryu, 0x1B},
-    {"Starmie", &I_starmie, 0x98},
-    {"Mr. Mime", &I_mr_mime, 0x2A},
-    {"Scyther", &I_scyther, 0x1A},
-    {"Jynx", &I_jynx, 0x48},
-    {"Electabuzz", &I_electabuzz, 0x35},
-    {"Magmar", &I_magmar, 0x33},
-    {"Pinsir", &I_pinsir, 0x1D},
-    {"Tauros", &I_tauros, 0x3C},
-    {"Magikarp", &I_magikarp, 0x85},
-    {"Gyarados", &I_gyarados, 0x16},
-    {"Lapras", &I_lapras, 0x13},
-    {"Ditto", &I_ditto, 0x4C},
-    {"Eevee", &I_eevee, 0x66},
-    {"Vaporeon", &I_vaporeon, 0x69},
-    {"Jolteon", &I_jolteon, 0x68},
-    {"Flareon", &I_flareon, 0x67},
-    {"Porygon", &I_porygon, 0xAA},
-    {"Omanyte", &I_omanyte, 0x62},
-    {"Omastar", &I_omastar, 0x63},
-    {"Kabuto", &I_kabuto, 0x5A},
-    {"Kabutops", &I_kabutops, 0x5B},
-    {"Aerodactyl", &I_aerodactyl, 0xAB},
-    {"Snorlax", &I_snorlax, 0x84},
-    {"Articuno", &I_articuno, 0x4A},
-    {"Zapdos", &I_zapdos, 0x4B},
-    {"Moltres", &I_moltres, 0x49},
-    {"Dratini", &I_dratini, 0x58},
-    {"Dragonair", &I_dragonair, 0x59},
-    {"Dragonite", &I_dragonite, 0x42},
-    {"Mewtwo", &I_mewtwo, 0x83},
-    {"Mew", &I_mew, 0x15},
+    {"Bulbasaur", &I_bulbasaur, 0x99, 0x16, 0x03, 1, 45, 49, 49, 45, 65},
+    {"Ivysaur", &I_ivysaur, 0x09, 0x16, 0x03, 1, 60, 62, 63, 60, 80},
+    {"Venusaur", &I_venusaur, 0x9A, 0x16, 0x03, 1, 80, 82, 83, 80, 100},
+    {"Charmander", &I_charmander, 0xB0, 0x14, 0xFF, 1, 39, 52, 43, 65, 50},
+    {"Charmeleon", &I_charmeleon, 0xB2, 0x14, 0xFF, 1, 58, 64, 58, 80, 65},
+    {"Charizard", &I_charizard, 0xB4, 0x14, 0x02, 1, 78, 84, 78, 100, 85},
+    {"Squirtle", &I_squirtle, 0xB1, 0x15, 0xFF, 1, 44, 48, 65, 43, 50},
+    {"Wartortle", &I_wartortle, 0xB3, 0x15, 0xFF, 1, 59, 63, 80, 58, 65},
+    {"Blastoise", &I_blastoise, 0x1C, 0x15, 0xFF, 1, 79, 83, 100, 78, 85},
+    {"Caterpie", &I_caterpie, 0x7B, 0x07, 0xFF, 2, 45, 30, 35, 45, 20},
+    {"Metapod", &I_metapod, 0x7C, 0x07, 0xFF, 2, 50, 20, 55, 30, 25},
+    {"Butterfree", &I_butterfree, 0x7D, 0x07, 0x02, 2, 60, 45, 50, 70, 80},
+    {"Weedle", &I_weedle, 0x70, 0x07, 0x03, 2, 40, 35, 30, 50, 20},
+    {"Kakuna", &I_kakuna, 0x71, 0x07, 0x03, 2, 45, 25, 50, 35, 25},
+    {"Beedrill", &I_beedrill, 0x72, 0x07, 0x03, 2, 65, 80, 40, 75, 45},
+    {"Pidgey", &I_pidgey, 0x24, 0x00, 0x02, 1, 40, 45, 40, 56, 35},
+    {"Pidgeotto", &I_pidgeotto, 0x96, 0x00, 0x02, 1, 63, 60, 55, 71, 50},
+    {"Pidgeot", &I_pidgeot, 0x97, 0x00, 0x02, 1, 83, 80, 75, 91, 70},
+    {"Rattata", &I_rattata, 0xA5, 0x00, 0xFF, 2, 30, 56, 35, 72, 25},
+    {"Raticate", &I_raticate, 0xA6, 0x00, 0xFF, 2, 55, 81, 60, 97, 50},
+    {"Spearow", &I_spearow, 0x05, 0x00, 0x02, 2, 40, 60, 30, 70, 31},
+    {"Fearow", &I_fearow, 0x23, 0x00, 0x02, 2, 65, 90, 65, 100, 61},
+    {"Ekans", &I_ekans, 0x6C, 0x03, 0xFF, 2, 35, 60, 44, 55, 40},
+    {"Arbok", &I_arbok, 0x2D, 0x03, 0xFF, 2, 60, 85, 69, 80, 65},
+    {"Pikachu", &I_pikachu, 0x54, 0x17, 0xFF, 2, 35, 55, 30, 90, 50},
+    {"Raichu", &I_raichu, 0x55, 0x17, 0xFF, 2, 60, 90, 55, 100, 90},
+    {"Sandshrew", &I_sandshrew, 0x60, 0x04, 0xFF, 2, 50, 75, 85, 40, 30},
+    {"Sandslash", &I_sandslash, 0x61, 0x04, 0xFF, 2, 75, 100, 110, 65, 55},
+    {"Nidoran♀", &I_nidoranf, 0x0F, 0x03, 0xFF, 1, 55, 47, 52, 41, 40},
+    {"Nidorina", &I_nidorina, 0xA8, 0x03, 0xFF, 1, 70, 62, 67, 56, 55},
+    {"Nidoqueen", &I_nidoqueen, 0x10, 0x03, 0x04, 1, 90, 82, 87, 76, 75},
+    {"Nidoran♂", &I_nidoranm, 0x03, 0x03, 0xFF, 1, 46, 57, 40, 50, 40},
+    {"Nidorino", &I_nidorino, 0xA7, 0x03, 0xFF, 1, 61, 72, 57, 65, 55},
+    {"Nidoking", &I_nidoking, 0x07, 0x03, 0x04, 1, 81, 92, 77, 85, 75},
+    {"Clefairy", &I_clefairy, 0x04, 0x00, 0xFF, 3, 70, 45, 48, 35, 60},
+    {"Clefable", &I_clefable, 0x8E, 0x00, 0xFF, 3, 95, 70, 73, 60, 85},
+    {"Vulpix", &I_vulpix, 0x52, 0x14, 0xFF, 2, 38, 41, 40, 65, 65},
+    {"Ninetales", &I_ninetales, 0x53, 0x14, 0xFF, 2, 73, 76, 75, 100, 100},
+    {"Jigglypuff", &I_jigglypuff, 0x64, 0x00, 0xFF, 3, 115, 45, 20, 20, 25},
+    {"Wigglytuff", &I_wigglytuff, 0x65, 0x00, 0xFF, 3, 140, 70, 45, 45, 50},
+    {"Zubat", &I_zubat, 0x6B, 0x03, 0x02, 2, 40, 45, 35, 55, 40},
+    {"Golbat", &I_golbat, 0x82, 0x03, 0x02, 2, 75, 80, 70, 90, 75},
+    {"Oddish", &I_oddish, 0xB9, 0x16, 0x03, 1, 45, 50, 55, 30, 75},
+    {"Gloom", &I_gloom, 0xBA, 0x16, 0x03, 1, 60, 65, 70, 40, 85},
+    {"Vileplume", &I_vileplume, 0xBB, 0x16, 0x03, 1, 75, 80, 85, 50, 100},
+    {"Paras", &I_paras, 0x6D, 0x07, 0x16, 2, 35, 70, 55, 25, 55},
+    {"Parasect", &I_parasect, 0x2E, 0x07, 0x16, 2, 60, 95, 80, 30, 80},
+    {"Venonat", &I_venonat, 0x41, 0x07, 0x03, 2, 60, 55, 50, 45, 40},
+    {"Venomoth", &I_venomoth, 0x77, 0x07, 0x03, 2, 70, 65, 60, 90, 90},
+    {"Diglett", &I_diglett, 0x3B, 0x04, 0xFF, 2, 10, 55, 25, 95, 45},
+    {"Dugtrio", &I_dugtrio, 0x76, 0x04, 0xFF, 2, 35, 80, 50, 120, 70},
+    {"Meowth", &I_meowth, 0x4D, 0x00, 0xFF, 2, 40, 45, 35, 90, 40},
+    {"Persian", &I_persian, 0x90, 0x00, 0xFF, 2, 65, 70, 60, 115, 65},
+    {"Psyduck", &I_psyduck, 0x2F, 0x15, 0xFF, 2, 50, 52, 48, 55, 50},
+    {"Golduck", &I_golduck, 0x80, 0x15, 0xFF, 2, 80, 82, 78, 85, 80},
+    {"Mankey", &I_mankey, 0x39, 0x01, 0xFF, 2, 40, 80, 35, 70, 35},
+    {"Primeape", &I_primeape, 0x75, 0x01, 0xFF, 2, 65, 105, 60, 95, 60},
+    {"Growlithe", &I_growlithe, 0x21, 0x14, 0xFF, 0, 55, 70, 45, 60, 50},
+    {"Arcanine", &I_arcanine, 0x14, 0x14, 0xFF, 0, 90, 110, 80, 95, 80},
+    {"Poliwag", &I_poliwag, 0x47, 0x15, 0xFF, 1, 40, 50, 40, 90, 40},
+    {"Poliwhirl", &I_poliwhirl, 0x6E, 0x15, 0xFF, 1, 65, 65, 65, 90, 50},
+    {"Poliwrath", &I_poliwrath, 0x6F, 0x15, 0x01, 1, 90, 85, 95, 70, 70},
+    {"Abra", &I_abra, 0x94, 0x18, 0xFF, 1, 25, 20, 15, 90, 105},
+    {"Kadabra", &I_kadabra, 0x26, 0x18, 0xFF, 1, 40, 35, 30, 105, 120},
+    {"Alakazam", &I_alakazam, 0x95, 0x18, 0xFF, 1, 55, 50, 45, 120, 135},
+    {"Machop", &I_machop, 0x6A, 0x01, 0xFF, 1, 70, 80, 50, 35, 35},
+    {"Machoke", &I_machoke, 0x29, 0x01, 0xFF, 1, 80, 100, 70, 45, 50},
+    {"Machamp", &I_machamp, 0x7E, 0x01, 0xFF, 1, 90, 130, 80, 55, 65},
+    {"Bellsprout", &I_bellsprout, 0xBC, 0x16, 0x03, 1, 50, 75, 35, 40, 70},
+    {"Weepinbell", &I_weepinbell, 0xBD, 0x16, 0x03, 1, 65, 90, 50, 55, 85},
+    {"Victreebel", &I_victreebel, 0xBE, 0x16, 0x03, 1, 80, 105, 65, 70, 100},
+    {"Tentacool", &I_tentacool, 0x18, 0x15, 0x03, 0, 40, 40, 35, 70, 100},
+    {"Tentacruel", &I_tentacruel, 0x9B, 0x15, 0x03, 0, 80, 70, 65, 100, 120},
+    {"Geodude", &I_geodude, 0xA9, 0x05, 0x04, 1, 40, 80, 100, 20, 30},
+    {"Graveler", &I_graveler, 0x27, 0x05, 0x04, 1, 55, 95, 115, 35, 45},
+    {"Golem", &I_golem, 0x31, 0x05, 0x04, 1, 80, 110, 130, 45, 55},
+    {"Ponyta", &I_ponyta, 0xA3, 0x14, 0xFF, 2, 50, 85, 55, 90, 65},
+    {"Rapidash", &I_rapidash, 0xA4, 0x14, 0xFF, 2, 65, 100, 70, 105, 80},
+    {"Slowpoke", &I_slowpoke, 0x25, 0x15, 0x18, 2, 90, 65, 65, 15, 40},
+    {"Slowbro", &I_slowbro, 0x08, 0x15, 0x18, 2, 95, 75, 110, 30, 80},
+    {"Magnemite", &I_magnemite, 0xAD, 0x17, 0xFF, 2, 25, 35, 70, 45, 95},
+    {"Magneton", &I_magneton, 0x36, 0x17, 0xFF, 2, 50, 60, 95, 70, 120},
+    {"Farfetch'd", &I_farfetchd, 0x40, 0x00, 0x02, 2, 52, 65, 55, 60, 58},
+    {"Doduo", &I_doduo, 0x46, 0x00, 0x02, 2, 35, 85, 45, 75, 35},
+    {"Dodrio", &I_dodrio, 0x74, 0x00, 0x02, 2, 60, 110, 70, 100, 60},
+    {"Seel", &I_seel, 0x3A, 0x15, 0xFF, 2, 65, 45, 55, 45, 70},
+    {"Dewgong", &I_dewgong, 0x78, 0x15, 0x19, 2, 90, 70, 80, 70, 95},
+    {"Grimer", &I_grimer, 0x0D, 0x03, 0xFF, 2, 80, 80, 50, 25, 40},
+    {"Muk", &I_muk, 0x88, 0x03, 0xFF, 2, 105, 105, 75, 50, 65},
+    {"Shellder", &I_shellder, 0x17, 0x15, 0xFF, 0, 30, 65, 100, 40, 45},
+    {"Cloyster", &I_cloyster, 0x8B, 0x15, 0x19, 0, 50, 95, 180, 70, 85},
+    {"Gastly", &I_gastly, 0x19, 0x08, 0x03, 1, 30, 35, 30, 80, 100},
+    {"Haunter", &I_haunter, 0x93, 0x08, 0x03, 1, 45, 50, 45, 95, 115},
+    {"Gengar", &I_gengar, 0x0E, 0x08, 0x03, 1, 60, 65, 60, 110, 130},
+    {"Onix", &I_onix, 0x22, 0x05, 0x04, 2, 35, 45, 160, 70, 30},
+    {"Drowzee", &I_drowzee, 0x30, 0x18, 0xFF, 2, 60, 48, 45, 42, 90},
+    {"Hypno", &I_hypno, 0x81, 0x18, 0xFF, 2, 85, 73, 70, 67, 115},
+    {"Krabby", &I_krabby, 0x4E, 0x15, 0xFF, 2, 30, 105, 90, 50, 25},
+    {"Kingler", &I_kingler, 0x8A, 0x15, 0xFF, 2, 55, 130, 115, 75, 50},
+    {"Voltorb", &I_voltorb, 0x06, 0x17, 0xFF, 2, 40, 30, 50, 100, 55},
+    {"Electrode", &I_electrode, 0x8D, 0x17, 0xFF, 2, 60, 50, 70, 140, 80},
+    {"Exeggcute", &I_exeggcute, 0x0C, 0x16, 0x18, 0, 60, 40, 80, 40, 60},
+    {"Exeggutor", &I_exeggutor, 0x0A, 0x16, 0x18, 0, 95, 95, 85, 55, 125},
+    {"Cubone", &I_cubone, 0x11, 0x04, 0xFF, 2, 50, 50, 95, 35, 40},
+    {"Marowak", &I_marowak, 0x91, 0x04, 0xFF, 2, 60, 80, 110, 45, 50},
+    {"Hitmonlee", &I_hitmonlee, 0x2B, 0x01, 0xFF, 2, 50, 120, 53, 87, 35},
+    {"Hitmonchan", &I_hitmonchan, 0x2C, 0x01, 0xFF, 2, 50, 105, 79, 76, 35},
+    {"Lickitung", &I_lickitung, 0x0B, 0x00, 0xFF, 2, 90, 55, 75, 30, 60},
+    {"Koffing", &I_koffing, 0x37, 0x03, 0xFF, 2, 40, 65, 95, 35, 60},
+    {"Weezing", &I_weezing, 0x8F, 0x03, 0xFF, 2, 65, 90, 120, 60, 85},
+    {"Rhyhorn", &I_rhyhorn, 0x12, 0x04, 0x05, 0, 80, 85, 95, 25, 30},
+    {"Rhydon", &I_rhydon, 0x01, 0x04, 0x05, 0, 105, 130, 120, 40, 45},
+    {"Chansey", &I_chansey, 0x28, 0x00, 0xFF, 3, 250, 5, 5, 50, 105},
+    {"Tangela", &I_tangela, 0x1E, 0x16, 0xFF, 2, 65, 55, 115, 60, 100},
+    {"Kangaskhan", &I_kangaskhan, 0x02, 0x00, 0xFF, 2, 105, 95, 80, 90, 40},
+    {"Horsea", &I_horsea, 0x5C, 0x15, 0xFF, 2, 30, 40, 70, 60, 70},
+    {"Seadra", &I_seadra, 0x5D, 0x15, 0xFF, 2, 55, 65, 95, 85, 95},
+    {"Goldeen", &I_goldeen, 0x9D, 0x15, 0xFF, 2, 45, 67, 60, 63, 50},
+    {"Seaking", &I_seaking, 0x9E, 0x15, 0xFF, 2, 80, 92, 65, 68, 80},
+    {"Staryu", &I_staryu, 0x1B, 0x15, 0xFF, 0, 30, 45, 55, 85, 70},
+    {"Starmie", &I_starmie, 0x98, 0x15, 0x18, 0, 60, 75, 85, 115, 100},
+    {"Mr. Mime", &I_mr_mime, 0x2A, 0x18, 0xFF, 2, 40, 45, 65, 90, 100},
+    {"Scyther", &I_scyther, 0x1A, 0x07, 0x02, 2, 70, 110, 80, 105, 55},
+    {"Jynx", &I_jynx, 0x48, 0x19, 0x18, 2, 65, 50, 35, 95, 95},
+    {"Electabuzz", &I_electabuzz, 0x35, 0x17, 0xFF, 2, 65, 83, 57, 105, 85},
+    {"Magmar", &I_magmar, 0x33, 0x14, 0xFF, 2, 65, 95, 57, 93, 85},
+    {"Pinsir", &I_pinsir, 0x1D, 0x07, 0xFF, 0, 65, 125, 100, 85, 55},
+    {"Tauros", &I_tauros, 0x3C, 0x00, 0xFF, 0, 75, 100, 95, 110, 70},
+    {"Magikarp", &I_magikarp, 0x85, 0x15, 0xFF, 0, 20, 10, 55, 80, 20},
+    {"Gyarados", &I_gyarados, 0x16, 0x15, 0x02, 0, 95, 125, 79, 81, 100},
+    {"Lapras", &I_lapras, 0x13, 0x15, 0x19, 0, 130, 85, 80, 60, 95},
+    {"Ditto", &I_ditto, 0x4C, 0x00, 0xFF, 2, 48, 48, 48, 48, 48},
+    {"Eevee", &I_eevee, 0x66, 0x00, 0xFF, 2, 55, 55, 50, 55, 65},
+    {"Vaporeon", &I_vaporeon, 0x69, 0x15, 0xFF, 2, 130, 65, 60, 65, 110},
+    {"Jolteon", &I_jolteon, 0x68, 0x17, 0xFF, 2, 65, 65, 60, 130, 110},
+    {"Flareon", &I_flareon, 0x67, 0x14, 0xFF, 2, 65, 130, 60, 65, 110},
+    {"Porygon", &I_porygon, 0xAA, 0x00, 0xFF, 2, 65, 60, 70, 40, 75},
+    {"Omanyte", &I_omanyte, 0x62, 0x05, 0x15, 2, 35, 40, 100, 35, 90},
+    {"Omastar", &I_omastar, 0x63, 0x05, 0x15, 2, 70, 60, 125, 55, 115},
+    {"Kabuto", &I_kabuto, 0x5A, 0x05, 0x15, 2, 30, 80, 90, 55, 45},
+    {"Kabutops", &I_kabutops, 0x5B, 0x05, 0x15, 2, 60, 115, 105, 80, 70},
+    {"Aerodactyl", &I_aerodactyl, 0xAB, 0x05, 0x02, 0, 80, 105, 65, 130, 60},
+    {"Snorlax", &I_snorlax, 0x84, 0x00, 0xFF, 0, 160, 110, 65, 30, 65},
+    {"Articuno", &I_articuno, 0x4A, 0x19, 0x02, 0, 90, 85, 100, 85, 125},
+    {"Zapdos", &I_zapdos, 0x4B, 0x17, 0x02, 0, 90, 90, 85, 100, 125},
+    {"Moltres", &I_moltres, 0x49, 0x14, 0x02, 0, 90, 100, 90, 90, 125},
+    {"Dratini", &I_dratini, 0x58, 0x1A, 0xFF, 0, 41, 64, 45, 50, 50},
+    {"Dragonair", &I_dragonair, 0x59, 0x1A, 0xFF, 0, 61, 84, 65, 70, 70},
+    {"Dragonite", &I_dragonite, 0x42, 0x1A, 0x02, 0, 91, 134, 95, 80, 100},
+    {"Mewtwo", &I_mewtwo, 0x83, 0x18, 0xFF, 0, 106, 110, 90, 130, 154},
+    {"Mew", &I_mew, 0x15, 0x18, 0xFF, 1, 100, 100, 100, 100, 100},
     {},
 };
 
+struct pokemon_mv move_table[] = {
+    {"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},
+};
+
 uint32_t pokemon_exit_confirm_view(void* context) {
     UNUSED(context);
     return AppViewExitConfirm;
@@ -179,6 +348,54 @@ App* pokemon_alloc() {
     view_dispatcher_add_view(
         app->view_dispatcher, AppViewSelectPokemon, select_pokemon_get_view(app));
 
+    //  Start Index first level
+    app->current_level = 3;
+    // Select Level View
+    app->select_level = select_level_alloc(app);
+    view_set_previous_callback(select_level_get_view(app), pokemon_exit_confirm_view);
+    view_dispatcher_add_view(
+        app->view_dispatcher, AppViewSelectLevel, select_level_get_view(app));
+
+    //  Start Index first stat
+    app->current_stats = 0;
+    // Select Level View
+    app->select_stats = select_stats_alloc(app);
+    view_set_previous_callback(select_stats_get_view(app), pokemon_exit_confirm_view);
+    view_dispatcher_add_view(
+        app->view_dispatcher, AppViewSelectStats, select_stats_get_view(app));
+
+    //  Start Index first move
+    app->current_move = 0;
+    // Select Move View
+    app->select_move1 = select_move1_alloc(app);
+    view_set_previous_callback(select_move1_get_view(app), pokemon_exit_confirm_view);
+    view_dispatcher_add_view(
+        app->view_dispatcher, AppViewSelectMove1, select_move1_get_view(app));
+
+    //  Start Index first move
+    app->current_move = 0;
+    // Select Move View
+    app->select_move2 = select_move2_alloc(app);
+    view_set_previous_callback(select_move1_get_view(app), pokemon_exit_confirm_view);
+    view_dispatcher_add_view(
+        app->view_dispatcher, AppViewSelectMove2, select_move2_get_view(app));
+
+    //  Start Index first move
+    app->current_move = 0;
+    // Select Move View
+    app->select_move3 = select_move3_alloc(app);
+    view_set_previous_callback(select_move3_get_view(app), pokemon_exit_confirm_view);
+    view_dispatcher_add_view(
+        app->view_dispatcher, AppViewSelectMove3, select_move3_get_view(app));
+
+    //  Start Index first move
+    app->current_move = 0;
+    // Select Move View
+    app->select_move4 = select_move4_alloc(app);
+    view_set_previous_callback(select_move4_get_view(app), pokemon_exit_confirm_view);
+    view_dispatcher_add_view(
+        app->view_dispatcher, AppViewSelectMove4, select_move4_get_view(app));
+
     // Trade View
     app->trade = trade_alloc(app);
     view_set_previous_callback(trade_get_view(app), pokemon_exit_confirm_view);
@@ -195,6 +412,18 @@ void free_app(App* app) {
     // Free views
     view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectPokemon);
     select_pokemon_free(app);
+    view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectLevel);
+    select_level_free(app);
+    view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectStats);
+    select_stats_free(app);
+    view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectMove1);
+    select_move1_free(app);
+    view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectMove2);
+    select_move2_free(app);
+    view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectMove3);
+    select_move3_free(app);
+    view_dispatcher_remove_view(app->view_dispatcher, AppViewSelectMove4);
+    select_move4_free(app);
     view_dispatcher_remove_view(app->view_dispatcher, AppViewTrade);
     trade_free(app);
     // Close records

+ 46 - 0
pokemon_app.h

@@ -11,6 +11,12 @@
 #include <pokemon_icons.h>
 
 #include "views/select_pokemon.hpp"
+#include "views/select_level.hpp"
+#include "views/select_stats.hpp"
+#include "views/select_move1.hpp"
+#include "views/select_move2.hpp"
+#include "views/select_move3.hpp"
+#include "views/select_move4.hpp"
 #include "views/trade.hpp"
 
 #define TAG "Pokemon"
@@ -19,6 +25,19 @@ struct pokemon_lut {
     const char* name;
     const Icon* icon;
     const uint8_t hex;
+    const uint8_t type1;
+    const uint8_t type2;
+    const int xp_group;
+    const int base_hp;
+    const int base_atk;
+    const int base_def;
+    const int base_spd;
+    const int base_special;
+};
+
+struct pokemon_mv {
+    const char* name;
+    const uint8_t hex;
 };
 
 typedef struct App App;
@@ -36,15 +55,34 @@ struct App {
     Gui* gui;
     ViewDispatcher* view_dispatcher;
     SelectPokemon* select_pokemon;
+    SelectLevel* select_level;
+    SelectStats* select_stats;
+    SelectMove1* select_move1;
+    SelectMove2* select_move2;
+    SelectMove3* select_move3;
+    SelectMove4* select_move4;
     Trade* trade;
     uint32_t view_id;
 
     int current_pokemon = 0;
+    int current_level = 3;
+    int current_stats = 0;
+    int current_move = 0;
     char pokemon_hex_code = ' ';
+    char move1_hex_code = ' ';
+    char move2_hex_code = ' ';
+    char move3_hex_code = ' ';
+    char move4_hex_code = ' ';
 };
 
 typedef enum {
     AppViewSelectPokemon,
+    AppViewSelectLevel,
+    AppViewSelectStats,
+    AppViewSelectMove1,
+    AppViewSelectMove2,
+    AppViewSelectMove3,
+    AppViewSelectMove4,
     AppViewTrade,
     AppViewExitConfirm,
 } AppView;
@@ -52,7 +90,14 @@ typedef enum {
 typedef void (*SelectPokemonCallback)(void* context, uint32_t index);
 typedef struct SelectPokemonModel {
     int current_pokemon = 0;
+    int current_level = 3;
+    int current_stats = 0;
+    int current_move = 0;
     char pokemon_hex_code = ' ';
+    char move1_hex_code = ' ';
+    char move2_hex_code = ' ';
+    char move3_hex_code = ' ';
+    char move4_hex_code = ' ';
     bool trading = false;
     bool connected = false;
     render_gameboy_state_t gameboy_status = GAMEBOY_INITIAL;
@@ -61,5 +106,6 @@ typedef struct SelectPokemonModel {
 } SelectPokemonModel;
 
 extern struct pokemon_lut pokemon_table[];
+extern struct pokemon_mv move_table[];
 
 #endif /* POKEMON_APP_H */

+ 13 - 14
pokemon_data.h

@@ -143,7 +143,7 @@ struct __attribute__((__packed__)) trade_data_block {
 };
 
 struct trade_data_block DATA_BLOCK2 =
-    {.trainer_name = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00, 0x00},
+    {.trainer_name = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_},
      .party_cnt = 1,
      .party_members = {0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
      .party =
@@ -281,23 +281,22 @@ struct trade_data_block DATA_BLOCK2 =
               .spd = 0x9800,
               .special = 0x9900},
          },
-     /* NOTE: I think this shouldn't exceed 7 chars */
      .ot_name =
          {
-             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
+             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+             {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
          },
      .nickname = {
-         {.str = {F_, l_, o_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-         {.str = {F_, l_, o_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-         {.str = {F_, l_, o_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-         {.str = {F_, l_, o_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-         {.str = {F_, l_, o_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
-         {.str = {F_, l_, o_, p_, p_, e_, r_, TERM_, 0x00, 0x00}},
+         {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+         {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+         {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+         {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+         {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
+         {.str = {F_, l_, i_, p_, p_, e_, r_, TERM_, TERM_, TERM_, TERM_}},
      }};
 
 unsigned char INPUT_BLOCK[405];

+ 170 - 0
views/select_level.cpp

@@ -0,0 +1,170 @@
+#include "../pokemon_app.h"
+#include "select_level.hpp"
+
+static void select_level_render_callback(Canvas* canvas, void* context) {
+    canvas_clear(canvas);
+
+    SelectPokemonModel* model = (SelectPokemonModel*)context;
+    const uint8_t current_index = model->current_level;
+
+    char level_num[5];
+
+    snprintf(level_num, sizeof(level_num), "#%03d", current_index);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(
+        canvas, 55, 54 / 2, AlignLeft, AlignTop, "Level:");
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, level_num);
+    canvas_draw_icon(canvas, 0, 0, pokemon_table[model->current_pokemon].icon);
+    canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
+    canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Level");
+
+    canvas_set_font(canvas, FontPrimary);
+    elements_button_center(canvas, "OK");
+}
+
+static bool select_level_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    SelectLevel* select_level = (SelectLevel*)context;
+    bool consumed = false;
+
+    if(event->type == InputTypePress && event->key == InputKeyOk) {
+        with_view_model_cpp(
+            select_level->view,
+            SelectPokemonModel*,
+            model,
+            {
+                select_level->app->current_level = model->current_level;
+            },
+            false);
+        
+        view_dispatcher_switch_to_view(select_level->app->view_dispatcher, AppViewSelectStats);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyBack) {
+        view_dispatcher_switch_to_view(select_level->app->view_dispatcher, AppViewSelectPokemon);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyLeft) {
+        with_view_model_cpp(
+            select_level->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_level == 3) {
+                    model->current_level = 100;
+                } else {
+                    model->current_level--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyDown) {
+        with_view_model_cpp(
+            select_level->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_level >= 10) {
+                    model->current_level -= 10;
+                } else {
+                    model->current_level = 100;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyRight) {
+        with_view_model_cpp(
+            select_level->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_level == 100) {
+                    model->current_level = 3;
+                } else {
+                    model->current_level++;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyUp) {
+        with_view_model_cpp(
+            select_level->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_level <= 90) {
+                    model->current_level += 10;
+                } else {
+                    model->current_level = 3;
+                    ;
+                }
+            },
+            true);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void select_level_enter_callback(void* context) {
+    furi_assert(context);
+    SelectLevel* select_level = (SelectLevel*)context;
+    with_view_model_cpp(
+        select_level->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_pokemon = select_level->app->current_pokemon;
+            model->pokemon_hex_code = select_level->app->pokemon_hex_code;
+            model->current_level = select_level->app->current_level;
+        },
+        true);
+}
+
+bool select_level_custom_callback(uint32_t event, void* context) {
+    UNUSED(event);
+    furi_assert(context);
+    SelectLevel* select_level = (SelectLevel*)context;
+    view_dispatcher_send_custom_event(select_level->app->view_dispatcher, 0);
+    return true;
+}
+
+void select_level_exit_callback(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+SelectLevel* select_level_alloc(App* app) {
+    SelectLevel* select_level = (SelectLevel*)malloc(sizeof(SelectLevel));
+    select_level->app = app;
+    select_level->view = view_alloc();
+    view_set_context(select_level->view, select_level);
+    view_allocate_model(select_level->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
+    with_view_model_cpp(
+        select_level->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_level = app->current_level;
+        },
+        true);
+
+    view_set_draw_callback(select_level->view, select_level_render_callback);
+    view_set_input_callback(select_level->view, select_level_input_callback);
+    view_set_enter_callback(select_level->view, select_level_enter_callback);
+    view_set_custom_callback(select_level->view, select_level_custom_callback);
+
+    view_set_exit_callback(select_level->view, select_level_exit_callback);
+    return select_level;
+}
+
+void select_level_free(App* app) {
+    furi_assert(app->select_level);
+    view_free(app->select_level->view);
+    free(app->select_level);
+}
+
+View* select_level_get_view(App* app) {
+    furi_assert(app->select_level);
+    return app->select_level->view;
+}

+ 25 - 0
views/select_level.hpp

@@ -0,0 +1,25 @@
+#ifndef SELECCT_LEVEL_HPP
+#define SELECCT_LEVEL_HPP
+
+#pragma once
+#include <furi.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+
+#include <gui/elements.h>
+#include <string>
+
+typedef struct App App;
+
+typedef struct {
+    View* view;
+    App* app;
+} SelectLevel;
+
+SelectLevel* select_level_alloc(App* app);
+
+void select_level_free(App* app);
+
+View* select_level_get_view(App* app);
+
+#endif /* SELECCT_LEVEL_HPP */

+ 172 - 0
views/select_move1.cpp

@@ -0,0 +1,172 @@
+#include "../pokemon_app.h"
+#include "select_move1.hpp"
+
+static void select_move1_render_callback(Canvas* canvas, void* context) {
+    canvas_clear(canvas);
+
+    SelectPokemonModel* model = (SelectPokemonModel*)context;
+    const uint8_t current_index = model->current_move;
+    char move_num[5];
+
+    snprintf(move_num, sizeof(move_num), "#%03d", current_index + 1);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(
+        canvas, 55, 54 / 2, AlignLeft, AlignTop, move_table[current_index].name);
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, move_num);
+    canvas_draw_icon(canvas, 0, 0, pokemon_table[model->current_pokemon].icon);
+    canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
+    canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Move #1");
+
+    canvas_set_font(canvas, FontPrimary);
+    elements_button_center(canvas, "OK");
+}
+
+static bool select_move1_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    SelectMove1* select_move1 = (SelectMove1*)context;
+    bool consumed = false;
+
+    if(event->type == InputTypePress && event->key == InputKeyOk) {
+        with_view_model_cpp(
+            select_move1->view,
+            SelectPokemonModel*,
+            model,
+            {
+                select_move1->app->current_move = model->current_move;
+                select_move1->app->move1_hex_code = move_table[model->current_move].hex;
+            },
+            false);
+        view_dispatcher_switch_to_view(select_move1->app->view_dispatcher, AppViewSelectMove2);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyBack) {
+        view_dispatcher_switch_to_view(select_move1->app->view_dispatcher, AppViewSelectStats);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyLeft) {
+        with_view_model_cpp(
+            select_move1->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 0) {
+                    model->current_move = 165;
+                } else {
+                    model->current_move--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyDown) {
+        with_view_model_cpp(
+            select_move1->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move >= 10) {
+                    model->current_move -= 10;
+                } else {
+                    model->current_move = 165;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyRight) {
+        with_view_model_cpp(
+            select_move1->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 165) {
+                    model->current_move = 0;
+                } else {
+                    model->current_move++;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyUp) {
+        with_view_model_cpp(
+            select_move1->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move <= 155) {
+                    model->current_move += 10;
+                } else {
+                    model->current_move = 0;
+                    ;
+                }
+            },
+            true);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void select_move1_enter_callback(void* context) {
+    furi_assert(context);
+    SelectMove1* select_move1 = (SelectMove1*)context;
+    with_view_model_cpp(
+        select_move1->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_pokemon = select_move1->app->current_pokemon;
+            model->pokemon_hex_code = select_move1->app->pokemon_hex_code;
+            model->current_level = select_move1->app->current_level;
+            model->current_stats = select_move1->app->current_stats;
+            model->move1_hex_code = select_move1->app->move1_hex_code;
+        },
+        true);
+}
+
+bool select_move1_custom_callback(uint32_t event, void* context) {
+    UNUSED(event);
+    furi_assert(context);
+    SelectMove1* select_move1 = (SelectMove1*)context;
+    view_dispatcher_send_custom_event(select_move1->app->view_dispatcher, 0);
+    return true;
+}
+
+void select_move1_exit_callback(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+SelectMove1* select_move1_alloc(App* app) {
+    SelectMove1* select_move1 = (SelectMove1*)malloc(sizeof(SelectMove1));
+    select_move1->app = app;
+    select_move1->view = view_alloc();
+    view_set_context(select_move1->view, select_move1);
+    view_allocate_model(select_move1->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
+    with_view_model_cpp(
+        select_move1->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_move = app->current_move;
+            model->move1_hex_code = app->move1_hex_code;
+        },
+        true);
+
+    view_set_draw_callback(select_move1->view, select_move1_render_callback);
+    view_set_input_callback(select_move1->view, select_move1_input_callback);
+    view_set_enter_callback(select_move1->view, select_move1_enter_callback);
+    view_set_custom_callback(select_move1->view, select_move1_custom_callback);
+
+    view_set_exit_callback(select_move1->view, select_move1_exit_callback);
+    return select_move1;
+}
+
+void select_move1_free(App* app) {
+    furi_assert(app->select_move1);
+    view_free(app->select_move1->view);
+    free(app->select_move1);
+}
+
+View* select_move1_get_view(App* app) {
+    furi_assert(app->select_move1);
+    return app->select_move1->view;
+}

+ 25 - 0
views/select_move1.hpp

@@ -0,0 +1,25 @@
+#ifndef SELECCT_MOVE1_HPP
+#define SELECCT_MOVE1_HPP
+
+#pragma once
+#include <furi.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+
+#include <gui/elements.h>
+#include <string>
+
+typedef struct App App;
+
+typedef struct {
+    View* view;
+    App* app;
+} SelectMove1;
+
+SelectMove1* select_move1_alloc(App* app);
+
+void select_move1_free(App* app);
+
+View* select_move1_get_view(App* app);
+
+#endif /* SELECCT_MOVE1_HPP */

+ 173 - 0
views/select_move2.cpp

@@ -0,0 +1,173 @@
+#include "../pokemon_app.h"
+#include "select_move2.hpp"
+
+static void select_move2_render_callback(Canvas* canvas, void* context) {
+    canvas_clear(canvas);
+
+    SelectPokemonModel* model = (SelectPokemonModel*)context;
+    const uint8_t current_index = model->current_move;
+    char move_num[5];
+
+    snprintf(move_num, sizeof(move_num), "#%03d", current_index + 1);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(
+        canvas, 55, 54 / 2, AlignLeft, AlignTop, move_table[current_index].name);
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, move_num);
+    canvas_draw_icon(canvas, 0, 0, pokemon_table[model->current_pokemon].icon);
+    canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
+    canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Move #2");
+
+    canvas_set_font(canvas, FontPrimary);
+    elements_button_center(canvas, "OK");
+}
+
+static bool select_move2_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    SelectMove2* select_move2 = (SelectMove2*)context;
+    bool consumed = false;
+
+    if(event->type == InputTypePress && event->key == InputKeyOk) {
+        with_view_model_cpp(
+            select_move2->view,
+            SelectPokemonModel*,
+            model,
+            {
+                select_move2->app->current_move = model->current_move;
+                select_move2->app->move2_hex_code = move_table[model->current_move].hex;
+            },
+            false);
+        view_dispatcher_switch_to_view(select_move2->app->view_dispatcher, AppViewSelectMove3);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyBack) {
+        view_dispatcher_switch_to_view(select_move2->app->view_dispatcher, AppViewSelectMove1);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyLeft) {
+        with_view_model_cpp(
+            select_move2->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 0) {
+                    model->current_move = 165;
+                } else {
+                    model->current_move--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyDown) {
+        with_view_model_cpp(
+            select_move2->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move >= 10) {
+                    model->current_move -= 10;
+                } else {
+                    model->current_move = 165;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyRight) {
+        with_view_model_cpp(
+            select_move2->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 165) {
+                    model->current_move = 0;
+                } else {
+                    model->current_move++;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyUp) {
+        with_view_model_cpp(
+            select_move2->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move <= 155) {
+                    model->current_move += 10;
+                } else {
+                    model->current_move = 0;
+                    ;
+                }
+            },
+            true);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void select_move2_enter_callback(void* context) {
+    furi_assert(context);
+    SelectMove2* select_move2 = (SelectMove2*)context;
+    with_view_model_cpp(
+        select_move2->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_pokemon = select_move2->app->current_pokemon;
+            model->pokemon_hex_code = select_move2->app->pokemon_hex_code;
+            model->current_level = select_move2->app->current_level;
+            model->current_stats = select_move2->app->current_stats;
+            model->move1_hex_code = select_move2->app->move1_hex_code;
+            model->move2_hex_code = select_move2->app->move2_hex_code;
+        },
+        true);
+}
+
+bool select_move2_custom_callback(uint32_t event, void* context) {
+    UNUSED(event);
+    furi_assert(context);
+    SelectMove2* select_move2 = (SelectMove2*)context;
+    view_dispatcher_send_custom_event(select_move2->app->view_dispatcher, 0);
+    return true;
+}
+
+void select_move2_exit_callback(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+SelectMove2* select_move2_alloc(App* app) {
+    SelectMove2* select_move2 = (SelectMove2*)malloc(sizeof(SelectMove2));
+    select_move2->app = app;
+    select_move2->view = view_alloc();
+    view_set_context(select_move2->view, select_move2);
+    view_allocate_model(select_move2->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
+    with_view_model_cpp(
+        select_move2->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_move = app->current_move;
+            model->move2_hex_code = app->move2_hex_code;
+        },
+        true);
+
+    view_set_draw_callback(select_move2->view, select_move2_render_callback);
+    view_set_input_callback(select_move2->view, select_move2_input_callback);
+    view_set_enter_callback(select_move2->view, select_move2_enter_callback);
+    view_set_custom_callback(select_move2->view, select_move2_custom_callback);
+
+    view_set_exit_callback(select_move2->view, select_move2_exit_callback);
+    return select_move2;
+}
+
+void select_move2_free(App* app) {
+    furi_assert(app->select_move2);
+    view_free(app->select_move2->view);
+    free(app->select_move2);
+}
+
+View* select_move2_get_view(App* app) {
+    furi_assert(app->select_move2);
+    return app->select_move2->view;
+}

+ 25 - 0
views/select_move2.hpp

@@ -0,0 +1,25 @@
+#ifndef SELECCT_MOVE2_HPP
+#define SELECCT_MOVE2_HPP
+
+#pragma once
+#include <furi.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+
+#include <gui/elements.h>
+#include <string>
+
+typedef struct App App;
+
+typedef struct {
+    View* view;
+    App* app;
+} SelectMove2;
+
+SelectMove2* select_move2_alloc(App* app);
+
+void select_move2_free(App* app);
+
+View* select_move2_get_view(App* app);
+
+#endif /* SELECCT_MOVE2_HPP */

+ 174 - 0
views/select_move3.cpp

@@ -0,0 +1,174 @@
+#include "../pokemon_app.h"
+#include "select_move3.hpp"
+
+static void select_move3_render_callback(Canvas* canvas, void* context) {
+    canvas_clear(canvas);
+
+    SelectPokemonModel* model = (SelectPokemonModel*)context;
+    const uint8_t current_index = model->current_move;
+    char move_num[5];
+
+    snprintf(move_num, sizeof(move_num), "#%03d", current_index + 1);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(
+        canvas, 55, 54 / 2, AlignLeft, AlignTop, move_table[current_index].name);
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, move_num);
+    canvas_draw_icon(canvas, 0, 0, pokemon_table[model->current_pokemon].icon);
+    canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
+    canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Move #3");
+
+    canvas_set_font(canvas, FontPrimary);
+    elements_button_center(canvas, "OK");
+}
+
+static bool select_move3_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    SelectMove3* select_move3 = (SelectMove3*)context;
+    bool consumed = false;
+
+    if(event->type == InputTypePress && event->key == InputKeyOk) {
+        with_view_model_cpp(
+            select_move3->view,
+            SelectPokemonModel*,
+            model,
+            {
+                select_move3->app->current_move = model->current_move;
+                select_move3->app->move3_hex_code = move_table[model->current_move].hex;
+            },
+            false);
+        view_dispatcher_switch_to_view(select_move3->app->view_dispatcher, AppViewSelectMove4);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyBack) {
+        view_dispatcher_switch_to_view(select_move3->app->view_dispatcher, AppViewSelectMove2);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyLeft) {
+        with_view_model_cpp(
+            select_move3->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 0) {
+                    model->current_move = 165;
+                } else {
+                    model->current_move--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyDown) {
+        with_view_model_cpp(
+            select_move3->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move >= 10) {
+                    model->current_move -= 10;
+                } else {
+                    model->current_move = 165;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyRight) {
+        with_view_model_cpp(
+            select_move3->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 165) {
+                    model->current_move = 0;
+                } else {
+                    model->current_move++;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyUp) {
+        with_view_model_cpp(
+            select_move3->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move <= 155) {
+                    model->current_move += 10;
+                } else {
+                    model->current_move = 0;
+                    ;
+                }
+            },
+            true);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void select_move3_enter_callback(void* context) {
+    furi_assert(context);
+    SelectMove3* select_move3 = (SelectMove3*)context;
+    with_view_model_cpp(
+        select_move3->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_pokemon = select_move3->app->current_pokemon;
+            model->pokemon_hex_code = select_move3->app->pokemon_hex_code;
+            model->current_level = select_move3->app->current_level;
+            model->current_stats = select_move3->app->current_stats;
+            model->move1_hex_code = select_move3->app->move1_hex_code;
+            model->move2_hex_code = select_move3->app->move2_hex_code;
+            model->move3_hex_code = select_move3->app->move3_hex_code;
+        },
+        true);
+}
+
+bool select_move3_custom_callback(uint32_t event, void* context) {
+    UNUSED(event);
+    furi_assert(context);
+    SelectMove3* select_move3 = (SelectMove3*)context;
+    view_dispatcher_send_custom_event(select_move3->app->view_dispatcher, 0);
+    return true;
+}
+
+void select_move3_exit_callback(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+SelectMove3* select_move3_alloc(App* app) {
+    SelectMove3* select_move3 = (SelectMove3*)malloc(sizeof(SelectMove3));
+    select_move3->app = app;
+    select_move3->view = view_alloc();
+    view_set_context(select_move3->view, select_move3);
+    view_allocate_model(select_move3->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
+    with_view_model_cpp(
+        select_move3->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_move = app->current_move;
+            model->move3_hex_code = app->move3_hex_code;
+        },
+        true);
+
+    view_set_draw_callback(select_move3->view, select_move3_render_callback);
+    view_set_input_callback(select_move3->view, select_move3_input_callback);
+    view_set_enter_callback(select_move3->view, select_move3_enter_callback);
+    view_set_custom_callback(select_move3->view, select_move3_custom_callback);
+
+    view_set_exit_callback(select_move3->view, select_move3_exit_callback);
+    return select_move3;
+}
+
+void select_move3_free(App* app) {
+    furi_assert(app->select_move3);
+    view_free(app->select_move3->view);
+    free(app->select_move3);
+}
+
+View* select_move3_get_view(App* app) {
+    furi_assert(app->select_move3);
+    return app->select_move3->view;
+}

+ 25 - 0
views/select_move3.hpp

@@ -0,0 +1,25 @@
+#ifndef SELECCT_MOVE3_HPP
+#define SELECCT_MOVE3_HPP
+
+#pragma once
+#include <furi.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+
+#include <gui/elements.h>
+#include <string>
+
+typedef struct App App;
+
+typedef struct {
+    View* view;
+    App* app;
+} SelectMove3;
+
+SelectMove3* select_move3_alloc(App* app);
+
+void select_move3_free(App* app);
+
+View* select_move3_get_view(App* app);
+
+#endif /* SELECCT_MOVE3_HPP */

+ 174 - 0
views/select_move4.cpp

@@ -0,0 +1,174 @@
+#include "../pokemon_app.h"
+#include "select_move4.hpp"
+
+static void select_move4_render_callback(Canvas* canvas, void* context) {
+    canvas_clear(canvas);
+
+    SelectPokemonModel* model = (SelectPokemonModel*)context;
+    const uint8_t current_index = model->current_move;
+    char move_num[5];
+
+    snprintf(move_num, sizeof(move_num), "#%03d", current_index + 1);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(
+        canvas, 55, 54 / 2, AlignLeft, AlignTop, move_table[current_index].name);
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, move_num);
+    canvas_draw_icon(canvas, 0, 0, pokemon_table[model->current_pokemon].icon);
+    canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
+    canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Move #4");
+
+    canvas_set_font(canvas, FontPrimary);
+    elements_button_center(canvas, "OK");
+}
+
+static bool select_move4_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    SelectMove4* select_move4 = (SelectMove4*)context;
+    bool consumed = false;
+
+    if(event->type == InputTypePress && event->key == InputKeyOk) {
+        with_view_model_cpp(
+            select_move4->view,
+            SelectPokemonModel*,
+            model,
+            {
+                select_move4->app->current_move = model->current_move;
+                select_move4->app->move4_hex_code = move_table[model->current_move].hex;
+            },
+            false);
+        view_dispatcher_switch_to_view(select_move4->app->view_dispatcher, AppViewTrade);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyBack) {
+        view_dispatcher_switch_to_view(select_move4->app->view_dispatcher, AppViewSelectMove3);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyLeft) {
+        with_view_model_cpp(
+            select_move4->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 0) {
+                    model->current_move = 165;
+                } else {
+                    model->current_move--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyDown) {
+        with_view_model_cpp(
+            select_move4->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move >= 10) {
+                    model->current_move -= 10;
+                } else {
+                    model->current_move = 165;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyRight) {
+        with_view_model_cpp(
+            select_move4->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move == 165) {
+                    model->current_move = 0;
+                } else {
+                    model->current_move++;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyUp) {
+        with_view_model_cpp(
+            select_move4->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_move <= 155) {
+                    model->current_move += 10;
+                } else {
+                    model->current_move = 0;
+                    ;
+                }
+            },
+            true);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void select_move4_enter_callback(void* context) {
+    furi_assert(context);
+    SelectMove4* select_move4 = (SelectMove4*)context;
+    with_view_model_cpp(
+        select_move4->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_pokemon = select_move4->app->current_pokemon;
+            model->pokemon_hex_code = select_move4->app->pokemon_hex_code;
+            model->current_level = select_move4->app->current_level;
+            model->current_stats = select_move4->app->current_stats;
+            model->move1_hex_code = select_move4->app->move1_hex_code;
+            model->move2_hex_code = select_move4->app->move2_hex_code;
+            model->move3_hex_code = select_move4->app->move3_hex_code;
+        },
+        true);
+}
+
+bool select_move4_custom_callback(uint32_t event, void* context) {
+    UNUSED(event);
+    furi_assert(context);
+    SelectMove4* select_move4 = (SelectMove4*)context;
+    view_dispatcher_send_custom_event(select_move4->app->view_dispatcher, 0);
+    return true;
+}
+
+void select_move4_exit_callback(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+SelectMove4* select_move4_alloc(App* app) {
+    SelectMove4* select_move4 = (SelectMove4*)malloc(sizeof(SelectMove4));
+    select_move4->app = app;
+    select_move4->view = view_alloc();
+    view_set_context(select_move4->view, select_move4);
+    view_allocate_model(select_move4->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
+    with_view_model_cpp(
+        select_move4->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_move = app->current_move;
+            model->move4_hex_code = app->move4_hex_code;
+        },
+        true);
+
+    view_set_draw_callback(select_move4->view, select_move4_render_callback);
+    view_set_input_callback(select_move4->view, select_move4_input_callback);
+    view_set_enter_callback(select_move4->view, select_move4_enter_callback);
+    view_set_custom_callback(select_move4->view, select_move4_custom_callback);
+
+    view_set_exit_callback(select_move4->view, select_move4_exit_callback);
+    return select_move4;
+}
+
+void select_move4_free(App* app) {
+    furi_assert(app->select_move4);
+    view_free(app->select_move4->view);
+    free(app->select_move4);
+}
+
+View* select_move4_get_view(App* app) {
+    furi_assert(app->select_move4);
+    return app->select_move4->view;
+}

+ 25 - 0
views/select_move4.hpp

@@ -0,0 +1,25 @@
+#ifndef SELECCT_MOVE4_HPP
+#define SELECCT_MOVE4_HPP
+
+#pragma once
+#include <furi.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+
+#include <gui/elements.h>
+#include <string>
+
+typedef struct App App;
+
+typedef struct {
+    View* view;
+    App* app;
+} SelectMove4;
+
+SelectMove4* select_move4_alloc(App* app);
+
+void select_move4_free(App* app);
+
+View* select_move4_get_view(App* app);
+
+#endif /* SELECCT_MOVE4_HPP */

+ 2 - 1
views/select_pokemon.cpp

@@ -38,7 +38,8 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) {
                 select_pokemon->app->pokemon_hex_code = pokemon_table[model->current_pokemon].hex;
             },
             false);
-        view_dispatcher_switch_to_view(select_pokemon->app->view_dispatcher, AppViewTrade);
+
+        view_dispatcher_switch_to_view(select_pokemon->app->view_dispatcher, AppViewSelectLevel);
         consumed = true;
     } else if(event->type == InputTypePress && event->key == InputKeyBack) {
         view_dispatcher_switch_to_view(select_pokemon->app->view_dispatcher, VIEW_NONE);

+ 195 - 0
views/select_stats.cpp

@@ -0,0 +1,195 @@
+#include "../pokemon_app.h"
+#include "select_stats.hpp"
+
+static void select_stats_render_callback(Canvas* canvas, void* context) {
+    canvas_clear(canvas);
+
+    SelectPokemonModel* model = (SelectPokemonModel*)context;
+    const uint8_t current_index = model->current_stats;
+
+    canvas_set_font(canvas, FontPrimary);
+    if(current_index == 0) {
+        canvas_draw_str_aligned(
+            canvas, 55, 54 / 2, AlignLeft, AlignTop, "Random IV");
+        canvas_draw_str_aligned(
+            canvas, 55, 38, AlignLeft, AlignTop, "Zero EV");
+    } else if(current_index == 1) {
+        canvas_draw_str_aligned(
+            canvas, 55, 54 / 2, AlignLeft, AlignTop, "Random IV");
+        canvas_draw_str_aligned(
+            canvas, 55, 38, AlignLeft, AlignTop, "Max EV / Lvl");
+    } else if(current_index == 2) {
+        canvas_draw_str_aligned(
+            canvas, 55, 54 / 2, AlignLeft, AlignTop, "Random IV");
+        canvas_draw_str_aligned(
+            canvas, 55, 38, AlignLeft, AlignTop, "Max EV");
+    } else if(current_index == 3) {
+        canvas_draw_str_aligned(
+            canvas, 55, 54 / 2, AlignLeft, AlignTop, "Max IV");
+        canvas_draw_str_aligned(
+            canvas, 55, 38, AlignLeft, AlignTop, "Zero EV");
+    } else if(current_index == 4) {
+        canvas_draw_str_aligned(
+            canvas, 55, 54 / 2, AlignLeft, AlignTop, "Max IV");
+        canvas_draw_str_aligned(
+            canvas, 55, 38, AlignLeft, AlignTop, "Max EV / Lvl");
+    } else if(current_index == 5) {
+        canvas_draw_str_aligned(
+            canvas, 55, 54 / 2, AlignLeft, AlignTop, "Max IV");
+        canvas_draw_str_aligned(
+            canvas, 55, 38, AlignLeft, AlignTop, "Max EV");
+    }
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_icon(canvas, 0, 0, pokemon_table[model->current_pokemon].icon);
+    canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
+    canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Stats");
+
+    canvas_set_font(canvas, FontPrimary);
+    elements_button_center(canvas, "OK");
+}
+
+static bool select_stats_input_callback(InputEvent* event, void* context) {
+    furi_assert(context);
+    SelectStats* select_stats = (SelectStats*)context;
+    bool consumed = false;
+
+    if(event->type == InputTypePress && event->key == InputKeyOk) {
+        with_view_model_cpp(
+            select_stats->view,
+            SelectPokemonModel*,
+            model,
+            {
+                select_stats->app->current_stats = model->current_stats;
+            },
+            false);
+        
+        view_dispatcher_switch_to_view(select_stats->app->view_dispatcher, AppViewSelectMove1);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyBack) {
+        view_dispatcher_switch_to_view(select_stats->app->view_dispatcher, AppViewSelectLevel);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyLeft) {
+        with_view_model_cpp(
+            select_stats->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_stats == 0) {
+                    model->current_stats = 5;
+                } else {
+                    model->current_stats--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyDown) {
+        with_view_model_cpp(
+            select_stats->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_stats == 0) {
+                    model->current_stats = 5;
+                } else {
+                    model->current_stats--;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyRight) {
+        with_view_model_cpp(
+            select_stats->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_stats == 5) {
+                    model->current_stats = 0;
+                } else {
+                    model->current_stats++;
+                }
+            },
+            true);
+        consumed = true;
+    } else if(event->type == InputTypePress && event->key == InputKeyUp) {
+        with_view_model_cpp(
+            select_stats->view,
+            SelectPokemonModel*,
+            model,
+            {
+                if(model->current_stats == 5) {
+                    model->current_stats = 0;
+                } else {
+                    model->current_stats++;
+                }
+            },
+            true);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void select_stats_enter_callback(void* context) {
+    furi_assert(context);
+    SelectStats* select_stats = (SelectStats*)context;
+    with_view_model_cpp(
+        select_stats->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_pokemon = select_stats->app->current_pokemon;
+            model->pokemon_hex_code = select_stats->app->pokemon_hex_code;
+            model->current_level = select_stats->app->current_level;
+            model->current_stats = select_stats->app->current_stats;
+        },
+        true);
+}
+
+bool select_stats_custom_callback(uint32_t event, void* context) {
+    UNUSED(event);
+    furi_assert(context);
+    SelectStats* select_stats = (SelectStats*)context;
+    view_dispatcher_send_custom_event(select_stats->app->view_dispatcher, 0);
+    return true;
+}
+
+void select_stats_exit_callback(void* context) {
+    furi_assert(context);
+    UNUSED(context);
+}
+
+SelectStats* select_stats_alloc(App* app) {
+    SelectStats* select_stats = (SelectStats*)malloc(sizeof(SelectStats));
+    select_stats->app = app;
+    select_stats->view = view_alloc();
+    view_set_context(select_stats->view, select_stats);
+    view_allocate_model(select_stats->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
+    with_view_model_cpp(
+        select_stats->view,
+        SelectPokemonModel*,
+        model,
+        {
+            model->current_stats = app->current_stats;
+        },
+        true);
+
+    view_set_draw_callback(select_stats->view, select_stats_render_callback);
+    view_set_input_callback(select_stats->view, select_stats_input_callback);
+    view_set_enter_callback(select_stats->view, select_stats_enter_callback);
+    view_set_custom_callback(select_stats->view, select_stats_custom_callback);
+
+    view_set_exit_callback(select_stats->view, select_stats_exit_callback);
+    return select_stats;
+}
+
+void select_stats_free(App* app) {
+    furi_assert(app->select_stats);
+    view_free(app->select_stats->view);
+    free(app->select_stats);
+}
+
+View* select_stats_get_view(App* app) {
+    furi_assert(app->select_stats);
+    return app->select_stats->view;
+}

+ 25 - 0
views/select_stats.hpp

@@ -0,0 +1,25 @@
+#ifndef SELECCT_STATS_HPP
+#define SELECCT_LEVEL_HPP
+
+#pragma once
+#include <furi.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+
+#include <gui/elements.h>
+#include <string>
+
+typedef struct App App;
+
+typedef struct {
+    View* view;
+    App* app;
+} SelectStats;
+
+SelectStats* select_stats_alloc(App* app);
+
+void select_stats_free(App* app);
+
+View* select_stats_get_view(App* app);
+
+#endif /* SELECCT_STATS_HPP */

+ 210 - 0
views/trade.cpp

@@ -34,6 +34,7 @@ int time_in_seconds = 0;
 static void trade_draw_callback(Canvas* canvas, void* context) {
     canvas_clear(canvas);
     SelectPokemonModel* model = (SelectPokemonModel*)context;
+
     if(!model->trading) {
         if(!model->connected) {
             furi_hal_light_set(LightGreen, 0x00);
@@ -298,6 +299,69 @@ void input_clk_gameboy(void* context) {
     transferBit(context);
     time = micros();
 }
+unsigned char convertCharToTagHex(char c) {
+    switch (c) {
+        case 'A': return A_;
+        case 'B': return B_;
+        case 'C': return C_;
+        case 'D': return D_;
+        case 'E': return E_;
+        case 'F': return F_;
+        case 'G': return G_;
+        case 'H': return H_;
+        case 'I': return I_;
+        case 'J': return J_;
+        case 'K': return K_;
+        case 'L': return L_;
+        case 'M': return M_;
+        case 'N': return N_;
+        case 'O': return O_;
+        case 'P': return P_;
+        case 'Q': return Q_;
+        case 'R': return R_;
+        case 'S': return S_;
+        case 'T': return T_;
+        case 'U': return U_;
+        case 'V': return V_;
+        case 'W': return W_;
+        case 'X': return X_;
+        case 'Y': return Y_;
+        case 'Z': return Z_;
+        case 'a': return A_;
+        case 'b': return B_;
+        case 'c': return C_;
+        case 'd': return D_;
+        case 'e': return E_;
+        case 'f': return F_;
+        case 'g': return G_;
+        case 'h': return H_;
+        case 'i': return I_;
+        case 'j': return J_;
+        case 'k': return K_;
+        case 'l': return L_;
+        case 'm': return M_;
+        case 'n': return N_;
+        case 'o': return O_;
+        case 'p': return P_;
+        case 'q': return Q_;
+        case 'r': return R_;
+        case 's': return S_;
+        case 't': return T_;
+        case 'u': return U_;
+        case 'v': return V_;
+        case 'w': return W_;
+        case 'x': return X_;
+        case 'y': return Y_;
+        case 'z': return Z_;
+        case ' ': return SPACE_;
+        case '.': return PERIOD_;
+        case '\'': return S_QUOTE_;
+        case '\u2642': return MALE_;
+        case '\u2640': return FEMALE_;
+        default:  return 0x00;
+    }
+
+}
 void trade_enter_callback(void* context) {
     furi_assert(context);
     Trade* trade = (Trade*)context;
@@ -308,13 +372,159 @@ void trade_enter_callback(void* context) {
         {
             model->current_pokemon = trade->app->current_pokemon;
             model->pokemon_hex_code = trade->app->pokemon_hex_code;
+            model->current_level = trade->app->current_level;
+            model->current_stats = trade->app->current_stats;
+            model->current_move = trade->app->current_move;
+            model->move1_hex_code = trade->app->move1_hex_code;
+            model->move2_hex_code = trade->app->move2_hex_code;
+            model->move3_hex_code = trade->app->move3_hex_code;
+            model->move4_hex_code = trade->app->move4_hex_code;
             model->trading = false;
             model->connected = false;
             model->gameboy_status = GAMEBOY_INITIAL;
         },
         true);
 
+    FURI_LOG_D(TAG, "[Trade] Current Pokemon: %d", trade->app->current_pokemon);
+    
+    // Set the Pokemon name
+    
+    unsigned char nickname[11];
+    for (size_t i = 0; i < 11; ++i) {
+        nickname[i] = 0x50;
+    }
+    for (size_t i = 0; i < strlen(pokemon_table[trade->app->current_pokemon].name); ++i) {
+        nickname[i] = convertCharToTagHex(pokemon_table[trade->app->current_pokemon].name[i]);
+    }
+
+    memcpy(DATA_BLOCK2.nickname[0].str, nickname, sizeof(nickname));
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon Name: %s", pokemon_table[trade->app->current_pokemon].name);
+
+    // Set the Pokemon hex code
+
     DATA_BLOCK[12] = trade->app->pokemon_hex_code;
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon Hex Code: %x", trade->app->pokemon_hex_code);
+
+    // Set the Pokemon level
+
+    FURI_LOG_D(TAG, "[Trade] Current Level: %d", trade->app->current_level);
+
+    uint8_t level = trade->app->current_level;
+    DATA_BLOCK2.party[0].level = level & 0xFF;
+    DATA_BLOCK2.party[0].level_again = level & 0xFF;
+
+    FURI_LOG_D(TAG, "[Trade] Level Hex Code: %x", DATA_BLOCK2.party[0].level);
+
+    // Set the Pokemon experience
+
+    int32_t exp = 0;
+    if(pokemon_table[trade->app->current_pokemon].xp_group == 0) {
+        exp = 1.25 * level * level * level;
+    } else if(pokemon_table[trade->app->current_pokemon].xp_group == 1) {
+        exp = (1.2 * level * level * level) - (15 * level * level) + (100 * level) - 140;
+    } else if(pokemon_table[trade->app->current_pokemon].xp_group == 2) {
+        exp = level * level * level;
+    } else if(pokemon_table[trade->app->current_pokemon].xp_group == 3) {
+        exp = 0.8 * level * level * level;
+    }
+
+    DATA_BLOCK2.party[0].exp[0] = (exp >> 16) & 0xFF;
+    DATA_BLOCK2.party[0].exp[1] = (exp >> 8) & 0xFF;
+    DATA_BLOCK2.party[0].exp[2] = exp & 0xFF;
+
+    FURI_LOG_D(TAG, "[Trade] XP 1: %x", DATA_BLOCK2.party[0].exp[0]);
+    FURI_LOG_D(TAG, "[Trade] XP 2: %x", DATA_BLOCK2.party[0].exp[1]);
+    FURI_LOG_D(TAG, "[Trade] XP 3: %x", DATA_BLOCK2.party[0].exp[2]);
+
+    // Set the Pokemon stat experience
+
+    uint16_t statexp = 0x0000;
+    if(trade->app->current_stats == 1 || trade->app->current_stats == 4) {
+        statexp = (65535 / 100) * level;
+    } else if(trade->app->current_stats == 2 || trade->app->current_stats == 5) {
+        statexp = 65535;
+    }
+
+    DATA_BLOCK2.party[0].hp_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
+    DATA_BLOCK2.party[0].atk_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
+    DATA_BLOCK2.party[0].def_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
+    DATA_BLOCK2.party[0].spd_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
+    DATA_BLOCK2.party[0].special_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon Stat EXP: %d", statexp);
+    FURI_LOG_D(TAG, "[Trade] Pokemon HP EV: %x", DATA_BLOCK2.party[0].hp_ev);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Attack EV: %x", DATA_BLOCK2.party[0].atk_ev);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Defence EV: %x", DATA_BLOCK2.party[0].def_ev);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Speed EV: %x", DATA_BLOCK2.party[0].spd_ev);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Special EV: %x", DATA_BLOCK2.party[0].special_ev);
+
+    // Set the Pokemon stats
+
+    uint8_t atk_iv = 15;
+    uint8_t def_iv = 15;
+    uint8_t spd_iv = 15;
+    uint8_t special_iv = 15;
+    uint8_t hp_iv = 15;
+    if(trade->app->current_stats <= 2) {
+        atk_iv = rand() % 15;
+        def_iv = rand() % 15;
+        spd_iv = rand() % 15;
+        special_iv = rand() % 15;
+        DATA_BLOCK2.party[0].iv = ((atk_iv & 0b00001111) << 12) | ((def_iv & 0b00001111) << 8) | ((spd_iv & 0b00001111) << 4) | ((special_iv & 0b00001111));
+        hp_iv = (DATA_BLOCK2.party[0].iv & 0xAA) >> 4;
+    }
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon IV: %x", DATA_BLOCK2.party[0].iv);
+    FURI_LOG_D(TAG, "[Trade] Pokemon HP IV: %x", hp_iv);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Attack IV: %x", atk_iv);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Defence IV: %x", def_iv);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Speed IV: %x", spd_iv);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Special IV: %x", special_iv);
+
+    uint16_t max_hp = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_hp + hp_iv)) + floor(sqrt(statexp) / 4)) * level) / 100) + (level + 10);
+    DATA_BLOCK2.party[0].max_hp = ((max_hp >> 8) & 0x00FF) | ((max_hp << 8) & 0xFF00);
+    DATA_BLOCK2.party[0].hp = ((max_hp >> 8) & 0x00FF) | ((max_hp << 8) & 0xFF00);
+    uint16_t attack = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_atk + atk_iv)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].atk = ((attack >> 8) & 0x00FF) | ((attack << 8) & 0xFF00);
+    uint16_t defence = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_def + def_iv)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].def = ((defence >> 8) & 0x00FF) | ((defence << 8) & 0xFF00);
+    uint16_t speed = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_spd + spd_iv)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].spd = ((speed >> 8) & 0x00FF) | ((speed << 8) & 0xFF00);
+    uint16_t special = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_special + special_iv)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].special = ((special >> 8) & 0x00FF) | ((special << 8) & 0xFF00);
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon Max HP: %x", DATA_BLOCK2.party[0].max_hp);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Attack: %x", DATA_BLOCK2.party[0].atk);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Defence: %x", DATA_BLOCK2.party[0].def);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Speed: %x", DATA_BLOCK2.party[0].spd);
+    FURI_LOG_D(TAG, "[Trade] Pokemon Special: %x", DATA_BLOCK2.party[0].special);
+
+    // Set the Pokemon types
+
+    DATA_BLOCK2.party[0].type[0] = pokemon_table[trade->app->current_pokemon].type1;
+    if(pokemon_table[trade->app->current_pokemon].type2 == 0xFF) {
+        DATA_BLOCK2.party[0].type[1] = pokemon_table[trade->app->current_pokemon].type1;
+    } else {
+        DATA_BLOCK2.party[0].type[1] = pokemon_table[trade->app->current_pokemon].type2;
+    }
+
+    FURI_LOG_D(TAG, "[Trade] Type 1: %x", DATA_BLOCK2.party[0].type[0]);
+    FURI_LOG_D(TAG, "[Trade] Type 2: %x", DATA_BLOCK2.party[0].type[1]);
+
+    // Set the Pokemon moves
+    
+    DATA_BLOCK2.party[0].move[0] = trade->app->move1_hex_code;
+    DATA_BLOCK2.party[0].move[1] = trade->app->move2_hex_code;
+    DATA_BLOCK2.party[0].move[2] = trade->app->move3_hex_code;
+    DATA_BLOCK2.party[0].move[3] = trade->app->move4_hex_code;
+
+    FURI_LOG_D(TAG, "[Trade] Move 1 Hex Code: %x", trade->app->move1_hex_code);
+    FURI_LOG_D(TAG, "[Trade] Move 2 Hex Code: %x", trade->app->move2_hex_code);
+    FURI_LOG_D(TAG, "[Trade] Move 3 Hex Code: %x", trade->app->move3_hex_code);
+    FURI_LOG_D(TAG, "[Trade] Move 4 Hex Code: %x", trade->app->move4_hex_code);
+
     // B3 (Pin6) / SO (2)
     furi_hal_gpio_write(&GAME_BOY_SO, false);
     furi_hal_gpio_init(&GAME_BOY_SO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);

Неке датотеке нису приказане због велике количине промена