Przeglądaj źródła

Added pokemon name, type, level, exp, moves, stats

Darryn Cull 2 lat temu
rodzic
commit
01ddb3a3e5

+ 38 - 5
README.md

@@ -18,7 +18,7 @@
 
 This is a Pokemon exchange application from Flipper Zero to Game Boy [(Generación 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, and 4 Moves. It assumes a perfect IV and sets the EV for each stat to 0 (captured Pokemon) and calculates the Pokemon's Stats.
 
 ## 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,99 @@ 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.
+- 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.
+- The Flipper Zero should show the selection for the Pokemon's moves that you want to trade, this will happen 4 times. The default is `No Move`.
+- 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.
 - 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 />
     </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 />
     </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 />
     </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 />
     </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 />
     </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 +256,16 @@ 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>
+<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
+- [x] Set each Pokemon's characteristics, attacks, and default levels
 - [ ] Improve animations
+- [ ] Add images for the level selction screen and the move selection screens as per the original README
+- [ ] Add an option to enable EV to be set to the maximum as per level ((65535 / 100) * level), or to the utmost maximum (65535)
 
 ## Links
 

+ 370 - 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,46 @@ 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 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 +404,16 @@ 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, 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

+ 41 - 0
pokemon_app.h

@@ -11,6 +11,11 @@
 #include <pokemon_icons.h>
 
 #include "views/select_pokemon.hpp"
+#include "views/select_level.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 +24,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 +54,31 @@ struct App {
     Gui* gui;
     ViewDispatcher* view_dispatcher;
     SelectPokemon* select_pokemon;
+    SelectLevel* select_level;
+    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_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,
+    AppViewSelectMove1,
+    AppViewSelectMove2,
+    AppViewSelectMove3,
+    AppViewSelectMove4,
     AppViewTrade,
     AppViewExitConfirm,
 } AppView;
@@ -52,7 +86,13 @@ typedef enum {
 typedef void (*SelectPokemonCallback)(void* context, uint32_t index);
 typedef struct SelectPokemonModel {
     int current_pokemon = 0;
+    int current_level = 3;
+    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 +101,6 @@ typedef struct SelectPokemonModel {
 } SelectPokemonModel;
 
 extern struct pokemon_lut pokemon_table[];
+extern struct pokemon_mv move_table[];
 
 #endif /* POKEMON_APP_H */

+ 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, AppViewSelectMove1);
+        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 */

+ 171 - 0
views/select_move1.cpp

@@ -0,0 +1,171 @@
+#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, AppViewSelectLevel);
+        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->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 */

+ 172 - 0
views/select_move2.cpp

@@ -0,0 +1,172 @@
+#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->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 */

+ 173 - 0
views/select_move3.cpp

@@ -0,0 +1,173 @@
+#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->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 */

+ 173 - 0
views/select_move4.cpp

@@ -0,0 +1,173 @@
+#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->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);

+ 193 - 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 '♂': return MALE_;
+        case '♀': return FEMALE_;
+        default:  return 0x00;
+    }
+
+}
 void trade_enter_callback(void* context) {
     furi_assert(context);
     Trade* trade = (Trade*)context;
@@ -308,13 +372,142 @@ 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_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] = 0x00;
+    }
+    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]);
+    }
+    for (size_t i = 0; i < 11; ++i) {
+        if(nickname[i] == 0x00) {
+            nickname[i] = 0x50;
+        }
+        break;
+    }
+
+    memcpy(DATA_BLOCK2.nickname[0].str, nickname, sizeof(nickname));
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon Name: %s", nickname);
+
+    // 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);
+
+    int 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
+
+    int 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;
+    // uint16_t statexp = (65535 / 100) * level;
+    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 max hp
+
+    // uint16_t max_hp = (0.01 * (2 * pokemon_table[trade->app->current_pokemon].base_hp + 15 + (0.25 * statexp)) * level) + level + 10;
+    uint16_t max_hp = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_hp + 15)) + 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);
+
+    FURI_LOG_D(TAG, "[Trade] Pokemon Max HP: %x", DATA_BLOCK2.party[0].max_hp);
+
+    // Set the Pokemon stats
+
+    // uint8_t attack = (0.01 * (2 * pokemon_table[trade->app->current_pokemon].base_atk + 15 + (0.25 * statexp)) * level) + 5;
+    uint16_t attack = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_atk + 15)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].atk = ((attack >> 8) & 0x00FF) | ((attack << 8) & 0xFF00);
+    // uint8_t defence = (0.01 * (2 * pokemon_table[trade->app->current_pokemon].base_def + 15 + (0.25 * statexp)) * level) + 5;
+    uint16_t defence = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_def + 15)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].def = ((defence >> 8) & 0x00FF) | ((defence << 8) & 0xFF00);
+    // uint8_t speed = (0.01 * (2 * pokemon_table[trade->app->current_pokemon].base_spd + 15 + (0.25 * statexp)) * level) + 5;
+    uint16_t speed = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_spd + 15)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].spd = ((speed >> 8) & 0x00FF) | ((speed << 8) & 0xFF00);
+    // uint8_t special = (0.01 * (2 * pokemon_table[trade->app->current_pokemon].base_special + 15 + (0.25 * statexp)) * level) + 5;
+    uint16_t special = floor((((2 * (pokemon_table[trade->app->current_pokemon].base_special + 15)) + floor(sqrt(statexp) / 4)) * level) / 100) + 5;
+    DATA_BLOCK2.party[0].special = ((special >> 8) & 0x00FF) | ((special << 8) & 0xFF00);
+
+    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;
+    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);