Selaa lähdekoodia

Merge pokemon_trading from https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading

Willy-JL 1 vuosi sitten
vanhempi
commit
e26598b02e
100 muutettua tiedostoa jossa 1502 lisäystä ja 2358 poistoa
  1. 1 1
      pokemon_trading/.github/FUNDING.yml
  2. 1 0
      pokemon_trading/LICENSE
  3. 12 2
      pokemon_trading/README.md
  4. 2 2
      pokemon_trading/README_catalog.md
  5. 0 328
      pokemon_trading/README_es.md
  6. 4 4
      pokemon_trading/TODO.md
  7. 3 3
      pokemon_trading/application.fam
  8. 7 27
      pokemon_trading/changelog.md
  9. BIN
      pokemon_trading/docs/images/back.png
  10. 0 9
      pokemon_trading/docs/images/back.svg
  11. BIN
      pokemon_trading/docs/images/dmg_link_port_pinout.png
  12. BIN
      pokemon_trading/docs/images/flipper-zero-flat-10.png
  13. BIN
      pokemon_trading/docs/images/flipper-zero-flat-11.png
  14. BIN
      pokemon_trading/docs/images/flipper-zero-flat-12.png
  15. BIN
      pokemon_trading/docs/images/flipper-zero-flat-13.png
  16. BIN
      pokemon_trading/docs/images/flipper-zero-flat-6-2.png
  17. BIN
      pokemon_trading/docs/images/flipper-zero-flat-9.png
  18. BIN
      pokemon_trading/docs/images/game_boy_pokemon_center.png
  19. BIN
      pokemon_trading/docs/images/game_boy_save.png
  20. BIN
      pokemon_trading/docs/images/game_boy_save_trade.png
  21. BIN
      pokemon_trading/docs/images/game_boy_trade_list.png
  22. BIN
      pokemon_trading/docs/images/game_boy_trade_list_select_trade.png
  23. BIN
      pokemon_trading/docs/images/game_boy_trade_list_select_trade_confirm.png
  24. BIN
      pokemon_trading/docs/images/game_boy_trade_room.png
  25. BIN
      pokemon_trading/docs/images/game_boy_trade_room_2.png
  26. BIN
      pokemon_trading/docs/images/gblpof.gif
  27. 0 7
      pokemon_trading/docs/images/implemented.svg
  28. BIN
      pokemon_trading/docs/images/left.png
  29. 0 6
      pokemon_trading/docs/images/left.svg
  30. BIN
      pokemon_trading/docs/images/reboot.png
  31. 0 744
      pokemon_trading/docs/images/white_flat.svg
  32. BIN
      pokemon_trading/docs/images/youtube.png
  33. 0 8
      pokemon_trading/item_nl.h
  34. 0 8
      pokemon_trading/move_nl.h
  35. 0 98
      pokemon_trading/pokemon_app.c
  36. 0 15
      pokemon_trading/scenes/pokemon_exit_confirm.h
  37. 0 232
      pokemon_trading/scenes/pokemon_gen.c
  38. 0 8
      pokemon_trading/scenes/pokemon_gen.h
  39. 0 104
      pokemon_trading/scenes/pokemon_gender.c
  40. 0 22
      pokemon_trading/scenes/pokemon_gender.h
  41. 0 10
      pokemon_trading/scenes/pokemon_item.h
  42. 0 174
      pokemon_trading/scenes/pokemon_menu.c
  43. 0 38
      pokemon_trading/scenes/pokemon_menu.h
  44. 0 12
      pokemon_trading/scenes/pokemon_move.h
  45. 0 8
      pokemon_trading/scenes/pokemon_name_input.h
  46. 0 8
      pokemon_trading/scenes/pokemon_number_input.h
  47. 0 8
      pokemon_trading/scenes/pokemon_pins.h
  48. 0 11
      pokemon_trading/scenes/pokemon_pokerus.h
  49. 0 9
      pokemon_trading/scenes/pokemon_select.c
  50. 0 8
      pokemon_trading/scenes/pokemon_select.h
  51. 0 81
      pokemon_trading/scenes/pokemon_shiny.c
  52. 0 9
      pokemon_trading/scenes/pokemon_shiny.h
  53. 0 31
      pokemon_trading/scenes/pokemon_stats.c
  54. 0 8
      pokemon_trading/scenes/pokemon_stats.h
  55. 0 9
      pokemon_trading/scenes/pokemon_trade.c
  56. 0 8
      pokemon_trading/scenes/pokemon_trade.h
  57. 0 8
      pokemon_trading/scenes/pokemon_type.h
  58. 0 73
      pokemon_trading/scenes/unown_form.c
  59. 0 13
      pokemon_trading/scenes/unown_form.h
  60. 8 0
      pokemon_trading/src/include/item_nl.h
  61. 8 0
      pokemon_trading/src/include/move_nl.h
  62. 3 3
      pokemon_trading/src/include/named_list.h
  63. 3 6
      pokemon_trading/src/include/patch_list.h
  64. 5 4
      pokemon_trading/src/include/pokemon_app.h
  65. 54 0
      pokemon_trading/src/include/pokemon_attribute.h
  66. 0 0
      pokemon_trading/src/include/pokemon_char_encode.h
  67. 4 4
      pokemon_trading/src/include/pokemon_data.h
  68. 4 14
      pokemon_trading/src/include/pokemon_table.h
  69. 3 3
      pokemon_trading/src/include/stat_nl.h
  70. 3 3
      pokemon_trading/src/include/stats.h
  71. 8 0
      pokemon_trading/src/include/type_nl.h
  72. 2 2
      pokemon_trading/src/item_nl.c
  73. 0 0
      pokemon_trading/src/missingno_i.h
  74. 2 2
      pokemon_trading/src/move_nl.c
  75. 1 1
      pokemon_trading/src/named_list.c
  76. 6 2
      pokemon_trading/src/patch_list.c
  77. 124 0
      pokemon_trading/src/pokemon_app.c
  78. 265 0
      pokemon_trading/src/pokemon_attribute.c
  79. 1 1
      pokemon_trading/src/pokemon_char_encode.c
  80. 11 11
      pokemon_trading/src/pokemon_data.c
  81. 3 3
      pokemon_trading/src/pokemon_data_i.h
  82. 6 6
      pokemon_trading/src/pokemon_table.c
  83. 51 0
      pokemon_trading/src/scenes/include/pokemon_scene.h
  84. 23 0
      pokemon_trading/src/scenes/include/pokemon_scene_config.h
  85. 18 27
      pokemon_trading/src/scenes/pokemon_exit_confirm.c
  86. 252 0
      pokemon_trading/src/scenes/pokemon_gen.c
  87. 44 0
      pokemon_trading/src/scenes/pokemon_gender.c
  88. 62 13
      pokemon_trading/src/scenes/pokemon_item.c
  89. 69 0
      pokemon_trading/src/scenes/pokemon_menu.c
  90. 90 18
      pokemon_trading/src/scenes/pokemon_move.c
  91. 38 21
      pokemon_trading/src/scenes/pokemon_name_input.c
  92. 30 14
      pokemon_trading/src/scenes/pokemon_number_input.c
  93. 15 8
      pokemon_trading/src/scenes/pokemon_pins.c
  94. 18 38
      pokemon_trading/src/scenes/pokemon_pokerus.c
  95. 30 0
      pokemon_trading/src/scenes/pokemon_scene.c
  96. 28 0
      pokemon_trading/src/scenes/pokemon_select.c
  97. 43 0
      pokemon_trading/src/scenes/pokemon_shiny.c
  98. 51 0
      pokemon_trading/src/scenes/pokemon_stats.c
  99. 21 0
      pokemon_trading/src/scenes/pokemon_trade.c
  100. 65 0
      pokemon_trading/src/scenes/pokemon_trade_reset_confirm.c

+ 1 - 1
pokemon_trading/.github/FUNDING.yml

@@ -1,6 +1,6 @@
 # These are supported funding model platforms
 
-github: kbembedded # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+github: KBEmbedded # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
 patreon: #
 open_collective: # Replace with a single Open Collective username
 ko_fi: # Replace with a single Ko-fi username

+ 1 - 0
pokemon_trading/LICENSE

@@ -1,6 +1,7 @@
 MIT License
 
 Copyright (c) 2023 Esteban Fuentealba
+Copyright (c) 2023-2024 KBEmbedded
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 12 - 2
pokemon_trading/README.md

@@ -15,6 +15,7 @@ The video below trades a Bulbasaur from the Flipper to a Game Boy Color with Pok
     - [Customizing Pokemon](#customizing-pokemon)
   - [Trade](#trade-pkmn)
     - [Modifying Traded Pokemon](#modifying-traded-pokemon)
+    - [Reset Trade Connection State](#reset-trade-connection-state)
 - [How it Works / Build your own Interface](#how-does-it-work)
 
 
@@ -84,7 +85,7 @@ Details on the hardware interface, as well as how to create your own adapter boa
 
 ## Installation Directions
 
-This application can be installed through the [Flipper Application Catalog](https://lab.flipper.net/apps/pokemon), the [Flipper Mobile Application](https://docs.flipper.net/mobile-app), or a pre-compiled application binary can be found on the [Releases](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/releases) page of this repo.
+This application can be installed through the [Flipper Application Catalog](https://lab.flipper.net/apps/pokemon), the [Flipper Mobile Application](https://docs.flipper.net/mobile-app), or a pre-compiled application binary can be found on the [Releases](https://github.com/KBEmbedded/Flipper-Zero-Game-Boy-Pokemon-Trading/releases) page of this repo.
 
 The application can also be built from source using [ufbt](https://github.com/flipperdevices/flipperzero-ufbt) or compiling the application against a firmware of choice using [fbt](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppsOnSDCard.md). This will install the application to the `apps/GPIO/` folder on the Flipper's SD card.
 
@@ -376,6 +377,15 @@ The Game Boy should remain on and in the trade room. When the Flipper re-enters
 
 ---
 
+#### Reset Trade Connection State
+It is possible to reset the Flipper's connection state to having never been connected to a Game Boy. This allows the Flipper to restart communication with a Game Boy if it was accidentally turned off, for example, and the Game Boy needs to re-enter the Trade Center. Doing this keeps the current Pokemon the Flipper has in memory intact.
+
+This can also be used to leverage the Flipper to trade a pokemon between two Pokemon games with only a single Game Boy. For example, trade from Pokemon Blue to the Flipper (and then modifying the Pokemon on the Flipper if desired), resetting the trade state on the Flipper, swap the Game Boy game to Pokemon Silver, and on both the Game Boy and Flipper, start the trade process (using Time Capsule trade mode on the Pokemon Silver game).
+
+Once a connection has been established between the Flipper and a Pokemon game, the option `Reset Connection` will appear in the configuration screen under `Trade PKMN`. The Flipper will then ask for confirmation of the operation.
+
+---
+
 #### Special Note on MALVEKE PCB Rev. <= 2.5
 Version 2.0 of the Pokemon Trade tool fixes a bug on MALVEKE boards that are Rev. 2.5 or lower where after a trade is completed the `OK` button no longer functions. However, while on the trade screen the `OK` button will continue to not function. For example, if you try to press the `OK` button to turn the backlight on, the Flipper will not respond. The `OK` button functionality will be restored once the Flipper leaves the Trade screen.
 
@@ -477,7 +487,7 @@ The sprites for each Pokemon were hand-made for the monochrome screen of the Fli
 - Analogue Pocket
 
 ## Contributors
-[![Contributors](https://contrib.rocks/image?repo=EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading)](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/graphs/contributors)
+[![Contributors](https://contrib.rocks/image?repo=KBEmbedded/Flipper-Zero-Game-Boy-Pokemon-Trading)](https://github.com/KBEmbedded/Flipper-Zero-Game-Boy-Pokemon-Trading/graphs/contributors)
 
 
 ## Links

+ 2 - 2
pokemon_trading/README_catalog.md

@@ -6,11 +6,11 @@ Tool for trading Pokemon from the Flipper Zero to Generation I and II Game Boy g
 
 No longer causes the OK button to break when using the pinout for older MALVEKE (MLVK2.5) PCBs! Users of MALVEKE PCBs Rev. <= 2.5 no longer need to reset the Flipper after a trade and are able to modify the traded Pokemon!
 
-See the project's [README on GitHub](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/blob/main/README.md) for more detailed instructions on the application and all of the customization options for Pokemon.
+See the project's README on GitHub https://github.com/KBEmbedded/Flipper-Zero-Game-Boy-Pokemon-Trading/blob/main/README.md for more detailed instructions on the application and all of the customization options for Pokemon.
 
 ## Connection: Flipper Zero GPIO - Game Boy
 
-See the project's [README on GitHub](https://github.com/EstebanFuentealba/Flipper-Zero-Game-Boy-Pokemon-Trading/blob/main/README.md) for Link Cable interface adapters available on Tindie.
+See the project's README on GitHub https://github.com/kbembedded/Flipper-Zero-Game-Boy-Pokemon-Trading/blob/main/README.md#hardware-interface for Link Cable interface adapters available on Tindie.
 
 The Original pinout is as follows:
 

+ 0 - 328
pokemon_trading/README_es.md

@@ -1,328 +0,0 @@
-# GAME BOY Pokemon Trading MALVEKE
-
-<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` para correr en tu Flipper Zero.
-
-```bash
-./fbt launch 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ás comenzando desde el escritorio de Flipper Zero. De lo contrario, presiona el botón Atrás hasta que estés en el escritorio.
-
-- Presiona el botón `OK` en Flipper para abrir el menú principal.
-- Elige `Applications` en el menú.
-- Selecciona `GPIO` en el submenú.
-- Selecciona `Pokemon Trading`.
-- Flipper Zero mostrará el menú principal de la aplicación. La primera opción es seleccionar el Pokémon a intercambiar.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-pokemon-select-1.png" width="400" />
-      <br />
-  </p>
-- Presiona los botones `IZQUIERDA`/`DERECHA` para paginar la selección de Pokémon de a 1.
-- Presiona los botones `ARRIBA`/`ABAJO` para paginar la selección de Pokémon de a 10.
-- Presiona el botón `OK` para seleccionar el Pokémon a intercambiar y volver al menú principal.
-
-  <p align='center'>
-       <br />
-      <img src="./docs/images/flipper-zero-pokemon-select-2.png" width="400" /><br />
-  </p>
-- El nombre del Pokémon intercambiado se puede establecer. Cuando se selecciona un Pokémon, el nombre por defecto es el nombre de la especie en mayúsculas. Esto imita a un Pokémon sin un nombre personalizado. Para restablecer este nombre a su valor predeterminado, borra el campo de entrada de texto, presiona `OK` en el botón `Save`. Esto llenará el cuadro de texto con el nombre predeterminado. Presiona `Save` nuevamente para establecer este nombre.
-
-    - **Nota**: Los nombres de Nidoran♀ y Nidoran♂ no se renderizan correctamente. Esto se debe a que Flipper actualmente no puede imprimir caracteres Unicode en la pantalla. Siguiendo las instrucciones anteriores, se llenará el campo de entrada de texto con `NIDORAN ` con un espacio después. Este espacio es el símbolo no renderizable ♀/♂. Una vez intercambiado, se mostrará correctamente.
-
-    - **Nota**: Solo se admiten caracteres alfanuméricos en el nombre del Pokémon en este momento.
-
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-nickname.png" width="400" />
-        <br />
-    </p>
-- También se puede ajustar el nivel del Pokémon presionando `OK` en la opción de nivel. El nivel mínimo es `2` y el máximo es `100`. El nivel se ingresa a través de un cuadro de texto. (Los niveles por debajo de 2 causan una falla de desbordamiento en los juegos de Gen I que haría que el nivel saltara a 100, así que si deseas esto, simplemente establece el nivel del Pokémon en 100).
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-pokemon-level.png" width="400" />
-      <br />
-  </p>
-- El menú `Select Moves` se utiliza para elegir los movimientos del Pokémon intercambiado. Están predefinidos con el conjunto de movimientos que el Pokémon conocería al nivel 1. Seleccionar una ranura de movimiento mostrará un índice alfabético de movimientos. Además, se pueden seleccionar rápidamente `No Move` y `Default`. Ten en cuenta que cualquier movimiento después del primer `No Move` se ignora.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-move-1.png" width="400" />
-      <br />
-  </p>
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-move-2.png" width="400" />
-      <br />
-  </p>
-- El menú `Select Types` puede cambiar los tipos del Pokémon intercambiado. Los tipos están predefinidos según lo que normalmente es el Pokémon seleccionado.
-
-  - Los Pokémon con un solo tipo tendrán el mismo tipo establecido para ambos tipos.
-
-  - **Nota**: A diferencia de otros menús, cambiar cualquiera de los tipos lo guarda inmediatamente. Presionar `Back` mantendrá los cambios. Esto se abordará en una versión posterior. Si necesitas volver a los tipos predeterminados, puedes seleccionar un Pokémon diferente y luego volver a seleccionar el Pokémon deseado.
-
-  - **Nota**: Al cambiar los tipos, las estadísticas del Pokémon en el juego NO reflejarán los tipos elegidos. Además, estos pueden sobrescribirse de nuevo en el juego si el Pokémon usa un movimiento que afecta a los tipos (por ejemplo, `Transform`) o el Pokémon evoluciona.
-
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-type.png" width="400" />
-        <br />
-    </p>
-- Las estadísticas del Pokémon también se pueden influir. Las configuraciones actuales son:
-
-  - `Random IV, Zero EV`  Imita las estadísticas de un Pokémon salvaje atrapado.
-  - `Random IV, Max EV / Level` IV es aleatorio, pero EV se establece en el máximo que un Pokémon entrenado podría tener para su nivel actual.
-  - `Random IV, Max EV` IV es aleatorio, EV se establece en el máximo absoluto para un Pokémon perfectamente entrenado.
-  - `Max IV, Zero EV` Imita las estadísticas de un Pokémon salvaje atrapado, pero con el IV máximo posible.
-  - `Max IV, Max EV / Level` IV es máximo, EV se establece en el máximo que un Pokémon entrenado podría tener para su nivel actual.
-  - `Max IV, Max EV` Máximo Pokémon absolutamente perfectos y poderosos.
-
-    <p align='center'>
-        <br />
-        <img src="./docs/images/flipper-zero-stats.png" width="400" />
-        <br />
-    </p>
-
-- También se puede configurar el `OT ID#` y el `OT Name` del Pokémon. El `OT ID#` debe estar entre `0` y `65535`. Establecer el `OT ID#` y el `OT Name` igual que tu entrenador actual hace que el juego crea que fue un Pokémon capturado en estado salvaje y no uno que se intercambió. Esto significa que los Pokémon de alto nivel seguirán obedeciéndote sin medallas, pero no obtendrán el aumento de experiencia de un Pokémon intercambiado.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-ot-id.png" width="400" /><br />
-  </p>
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-ot-name.png" width="400" /><br />
-  </p>
-- Finalmente, selecciona Intercambiar PKMN para iniciar el proceso de intercambio.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-6-2.png" width="400" /><br />
-  </p>
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-9.png" width="400" /><br />
-  </p>
-- En tu Game Boy, debes conectar el **Game Link Cable** a la Game Boy y, en el juego, ve al **Pokemon Center** más cercano.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/game_boy_pokemon_center.png" width="400" /><br />
-  </p>
-- Habla con la chica en el mostrador de la derecha. La chica nos dirá que tenemos que guardar el juego antes de jugar, responderemos **YES** presionando el botón **A**.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/game_boy_save.png" width="400" /><br />
-  </p>
-- Flipper Zero mostrará que estamos conectados.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-10.png" width="400" /><br />
-  </p>
-- En la Game Boy, se nos preguntará qué opción queremos, y seleccionamos **TRADE CENTER**.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/game_boy_save_trade.png" width="400" /><br />
-  </p>
-- Ingresarás al Centro de Intercambio donde debes presionar el botón A en la Game Boy en tu lado de la mesa.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/game_boy_trade_room_2.png" width="400" /><br />
-  </p>
-- Flipper Zero permanecerá en una pantalla de espera con el Pokémon que seleccionaste.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-10.png" width="400" /><br />
-  </p>
-- Verás tu Pokémon y el Pokémon que seleccionaste en Flipper Zero, en este caso, `Mew`. Debes seleccionar el Pokémon que deseas intercambiar y presionar **TRADE**.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/game_boy_trade_list_select_trade.png" width="400" /><br />
-  </p>
-- Debes confirmar el intercambio seleccionando **TRADE**.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/game_boy_trade_list_select_trade_confirm.png" width="400" /><br />
-  </p>
-- Flipper Zero permanecerá en una pantalla de espera con el Pokémon que seleccionaste.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-11.png" width="400" /><br />
-  </p>
-- Finalmente, el intercambio de Pokémon comenzará desde **Flipper Zero** hacia la **Game Boy**.
-
-  <p align='center'>
-      <br />
-      <img src="./docs/images/flipper-zero-flat-12.png" width="400" /><br />
-  </p>
-- Si Flipper Zero se queda atascado al final del intercambio, debes reiniciarlo presionando la combinación de teclas <img src="./docs/images/left.png" /> `IZQUIERDA` + <img src="./docs/images/back.png" /> `ATRÁS`.
-
-  <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)
-
-## Contribuidores
-<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><br />
-<a href="https://github.com/kbembedded/Flipper-Zero-Game-Boy-Pokemon-Trading/">kbembedded</a>
-
-## 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>

+ 4 - 4
pokemon_trading/TODO.md

@@ -33,13 +33,13 @@
   - [x] Add images for the level selection screen, stats selection screen, and move selection screens as per the original README  
 - Codebase  
   - [x] Reimplement Logging calls  
-  - [ ] Clean up the codebase as it is now, there are a lot of optimizations in speed and code complexity that can be made, especially in added code in pokemon_app and maybe some code reduction/reuse in scenes  
-  - [ ] Consider using a single View in main app struct and only allocate a view as needed to reduce memory footprint  
+  - [x] Clean up the codebase as it is now, there are a lot of optimizations in speed and code complexity that can be made, especially in added code in pokemon_app and maybe some code reduction/reuse in scenes  
+  - [x] Consider using a single View in main app struct and only allocate a view as needed to reduce memory footprint  
 
 - Future Wants  
-  - [ ] Trading to Gen II games with both Gen I and Gen II Pokemon  
+  - [x] Trading to Gen II games with both Gen I and Gen II Pokemon  
   - [ ] Enable IR mystery gift usage in Gen II using Flipper  
-  - [ ] Be able to set up multiple Pokemon to be able to trade more than one per trip to trade center  
+  - [x] Be able to set up multiple Pokemon to be able to trade more than one per trip to trade center  
   - [x] Be able to trade back and forth for e.g. trading a Pokemon that evolves only when traded  
   - [x] Would Separating out link cable states result in a cleaner API?  
   - [ ] Implement some simple logic to be able to "battle" the Flipper?  

+ 3 - 3
pokemon_trading/application.fam

@@ -5,13 +5,13 @@ App(
     entry_point="pokemon_app",
     requires=["gui"],
     stack_size=2 * 1024,
-    fap_version=[2, 0],
+    fap_version=[2, 1],
     fap_category="GPIO",
     fap_icon="pokemon_10px.png",
     fap_icon_assets="assets",
     fap_file_assets="files",
-    fap_author="Esteban Fuentealba, Kris Bahnsen, Darryn Cull, ProteanReverie",
-    fap_weburl="https://github.com/EstebanFuentealba",
+    fap_author="Kris Bahnsen, Esteban Fuentealba, ProteanReverie, Darryn Cull",
+    fap_weburl="https://github.com/kbembedded/Flipper-Zero-Game-Boy-Pokemon-Trading",
     fap_description="Pokemon exchange from Flipper Zero to Game Boy, supports Generation I & II non-Japanese games",
     fap_private_libs=[
         Lib(

+ 7 - 27
pokemon_trading/changelog.md

@@ -1,5 +1,12 @@
 # Changelog - Patch Notes
 
+## Version 2.1
+**New Features**
+- Add ability to reset trade state without affecting current Pokemon being configured
+
+**Refactor**
+- Move files, consolidate files where appropriate, change scene management to be more in-line with Flipper paradigms
+
 ## Version 2.0
 **Bug Fixes**  
 - Older MALVEKE style pinout no longer breaks OK button, MALVEKE users now able to modify traded Pokemon
@@ -16,30 +23,3 @@
 **Refactor**
 - Sprites moved to file on SD card  
 - Create accessors for generically modifying Pokemon struct data  
-
-## Version 1.6
-- **Change Name:** All the application names for GAME BOY/MALVEKE were standardized for better readability on the screen.
-
-## Version 1.5
-- **Add Features:** Incorporate flipper-gblink library; Add support for MALVEKE board as well as custom pin selection; If MALVEKE board is detected, default to that pinout, otherwise use the original documented pinout.
-- **BUG:** The current MALVEKE pinout and interrupt use breaks the OK button after entering the trade screen.
-
-## Version 1.4
-- **Bug Fixes:** More robust trade logic fixes issues with names, remove ability to use numbers in Pokemon/Trainer names as the game itself will not allow that, fix trade animation not always being animated, make FAP icon 1bpp.
-- **Add Features:** Implement trade patch list that Game Boy expects and uses, add ability to return to main menu to modify a Pokemon traded to the Flipper and re-enter trade without the Game Boy needing to power cycle and re-connect through the Link Club, add back debug logging.
-- **Trade Refactor:** Eliminate extraneous code, improve robustness of state tracking during trades, isolate Trade's scope to the compilation unit, add notes on exchanged bytes during a trade, improve timing of animation during trade, reduce time spent in interrupt context, follow same setup/hold times for data exchange that the Game Boy uses, reduce use of magic numbers, clean up and improve code tracking real world time
-
-## Version 1.3
-- **Refactor and UI cleanup:** Convert to Flipper Zero UI modules for simpler interface, reduce binary size.
-- **Add Features:** Add ability to set custom Pokemon nickname or default, add ability to set OT name and ID, add ability to select Pokemon type(s). Note that, an evolution as well as a couple of different attacks will cause this to be overwritten with the Pokemon's default values.
-- **Bug Fixes:** Fix strange issue with exp gain causing traded Pokemon to de-level and result in incorrect stats.
-
-## Version 1.2.2
-- **Extended Functionality:** Add support to set level, select moves, set up EV/IV to a few predefined configurations, set up stats based on level and EV/IV settings, set nickname to default Pokemon name.
-
-## Version 1.2.1
-- **Add GitHub action to build**
-
-## 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
pokemon_trading/docs/images/back.png


+ 0 - 9
pokemon_trading/docs/images/back.svg

@@ -1,9 +0,0 @@
-<svg style="display:inline;fill:currentColor;stroke:currentColor;stroke-width:0.55px;"
-    xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
-    width="24" height="24" viewBox="0 0 24 24">
-    <path
-        d="M22,12C22,6.514 17.486,2 12,2C6.514,2 2,6.514 2,12C2,17.486 6.514,22 12,22C17.486,22 22,17.486 22,12M20,12C20,16.389 16.389,20 12,20C7.611,20 4,16.389 4,12C4,7.611 7.611,4 12,4C16.389,4 20,7.611 20,12"></path>
-    <path
-        d="M7.154,9.781L9.62,8L9.62,9.096L14.004,9.096C15.874,9.096 17.154,10.969 17.154,12.52C17.154,14.333 15.959,15.945 14.278,15.945L9.757,15.945L9.757,14.712L14.141,14.712C15.224,14.712 15.785,13.409 15.785,12.657C15.785,11.906 15.425,10.466 14.141,10.466L9.62,10.466L9.62,11.425L7.154,9.781Z"
-        style="stroke-width:0.55px;"></path>
-</svg>

BIN
pokemon_trading/docs/images/dmg_link_port_pinout.png


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


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


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


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


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


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


BIN
pokemon_trading/docs/images/game_boy_pokemon_center.png


BIN
pokemon_trading/docs/images/game_boy_save.png


BIN
pokemon_trading/docs/images/game_boy_save_trade.png


BIN
pokemon_trading/docs/images/game_boy_trade_list.png


BIN
pokemon_trading/docs/images/game_boy_trade_list_select_trade.png


BIN
pokemon_trading/docs/images/game_boy_trade_list_select_trade_confirm.png


BIN
pokemon_trading/docs/images/game_boy_trade_room.png


BIN
pokemon_trading/docs/images/game_boy_trade_room_2.png


BIN
pokemon_trading/docs/images/gblpof.gif


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 7
pokemon_trading/docs/images/implemented.svg


BIN
pokemon_trading/docs/images/left.png


+ 0 - 6
pokemon_trading/docs/images/left.svg

@@ -1,6 +0,0 @@
-<svg style="display:inline;fill:currentColor;stroke:currentColor;stroke-width:0.55px;"
-    xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
-    width="24" height="24" viewBox="0 0 24 24">
-    <path
-        d="M22,12A10,10 0 0,0 12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12M20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12M14,7L9,12L14,17V7Z"></path>
-</svg>

BIN
pokemon_trading/docs/images/reboot.png


+ 0 - 744
pokemon_trading/docs/images/white_flat.svg

@@ -1,744 +0,0 @@
-<svg version="1.1" id="Flipper_1" xmlns="http://www.w3.org/2000/svg"
-    xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-    viewBox="0 0 202.5 85.4" style="enable-background:new 0 0 202.5 85.4;" xml:space="preserve">
-<style type="text/css">
-	.st0{fill:#FFFFFF;}
-	.st1{fill:#231F20;}
-	.st2{fill:#fe8a2c;}
-	.st3{display:none;}
-	.st4{display:inline;fill:#FF8200;}
-	.st5{fill:#808080;}
-</style>
-<g id="white">
-	<g>
-		<g>
-			<path class="st0" d="M40.9,0.6h126.7c3.9,0.1,7.9,1,11.1,4.7C181.9,9,195.6,26,197,27.8s2.9,4.1,3.3,7.9
-				c0.4,3.8,1.5,29.3,1.5,32.8c0,3.7-1.1,5.2-1.9,6.9c-0.8,1.5-2,4-2.8,5.5s-3.5,3.8-7.8,3.9H32.2c-4.6,0-8.4-1.7-10.9-5.1
-				C18.8,76.4,5.1,57.5,4.5,56.5c-1-1.6-1.8-4.1-3.2-6.9c-0.9-1.8-1.3-4.6,1-7.8c2.4-3.2,25.8-33.6,27.9-36
-				C32.3,3.3,35.9,0.5,40.9,0.6z"/>
-			<path class="st1" d="M32.1,85.4c-4.7,0-8.6-1.8-11.2-5.3C18.6,77,4.6,57.9,4,56.8c-0.6-1-1.1-2.2-1.7-3.6c-0.4-1-0.9-2.2-1.5-3.4
-				s-1.7-4.4,1.1-8.3c2.5-3.4,26-33.8,27.9-36.1c1.7-2,5.5-5.4,11-5.4h0.1h126.7c3.2,0.1,7.9,0.7,11.6,4.9c1.9,2.3,8.1,9.9,17.9,22
-				l0.4,0.5c1.5,1.9,3,4.2,3.4,8.2c0.5,4,1.5,29.5,1.5,32.9c0,3.4-0.9,5.1-1.7,6.6c-0.1,0.2-0.2,0.4-0.3,0.6c-0.8,1.5-2,4-2.8,5.5
-				c-0.8,1.6-3.7,4.1-8.3,4.2H32.2C32.2,85.4,32.1,85.4,32.1,85.4z M40.8,1.1c-5.1,0-8.6,3.1-10.2,5c-1.9,2.3-25.4,32.6-27.8,36
-				c-2.5,3.4-1.6,6.1-1,7.2c0.6,1.2,1.1,2.4,1.6,3.5C4,54.2,4.5,55.3,5,56.2C5.5,57.1,19.3,76,21.8,79.4c2.4,3.2,6,4.9,10.4,4.9
-				h157.3c4.1-0.1,6.6-2.2,7.3-3.6c0.8-1.6,2-4,2.8-5.5c0.1-0.2,0.2-0.4,0.3-0.6c0.8-1.4,1.5-2.9,1.6-6.1c0-3.9-1.1-29.1-1.5-32.8
-				s-1.8-5.9-3.2-7.6l-0.4-0.5c-12.3-15.3-16.5-20.4-17.9-22c-2.6-3-6-4.4-10.7-4.5H41.1C40.9,1.1,40.8,1.1,40.8,1.1z"/>
-		</g>
-		<g>
-			<path class="st1" d="M27.3,78.5c-4.6,0-7-1.8-12.6-9.5c-5.4-7.3-12.9-17.8-13-17.9l0.5-0.3c0.1,0.1,7.5,10.6,12.9,17.9
-				c5.5,7.5,7.8,9.2,12.2,9.2h165.4c3.3-0.2,6.7-1.8,7.6-3.6l0.5,0.3c-1,2-4.6,3.8-8.1,3.9H27.3z"/>
-		</g>
-		<g>
-			<path class="st0" d="M164.8,2.9c4,0,6.6,0.5,9.2,3.6s18,22.2,19.3,23.8c1.3,1.6,2.4,4,2.4,6.6s0.6,14.8,0.4,18
-				c-0.2,3.3-2.9,5.7-6.4,5.8H42c-4.7-0.1-6.7-1.3-8.9-3.6c-2.2-2.4-7.9-8.5-9.6-10.7c-1.9-2.4-1-4.2,0.1-5.9
-				C24.9,38.9,43.4,11,45.2,8.1c1.7-2.8,4.9-5.2,8.8-5.2L164.8,2.9z"/>
-			<path class="st1" d="M42.1,61.1c-4.8-0.1-6.8-1.3-9.1-3.7s-7.9-8.6-9.6-10.8c-2-2.5-1.1-4.5,0.1-6.2C24.8,38.6,43.3,10.7,44.9,8
-				c2.1-3.3,5.4-5.3,9-5.3l0,0h110.8c4.2,0,6.8,0.6,9.4,3.7c2.6,3.1,18.2,22.4,19.3,23.8c1.5,2,2.4,4.5,2.4,6.8
-				c0,0.9,0.1,2.9,0.2,5.2c0.2,4.8,0.4,10.7,0.3,12.8c-0.2,3.4-3,6-6.6,6.1H42.1z M54,3.2c-3.4,0-6.6,1.9-8.5,5.1
-				C43.8,11,25.2,38.9,24,40.7c-1,1.5-2,3.2-0.1,5.5c1.7,2.2,7.3,8.3,9.6,10.7c2.2,2.3,4.1,3.5,8.7,3.5h147.7
-				c3.3-0.1,5.9-2.5,6.1-5.6c0.1-2.1-0.1-8.3-0.3-12.8c-0.1-2.3-0.2-4.3-0.2-5.2c0-3.2-1.6-5.6-2.3-6.4C192,29,176.5,9.7,173.8,6.7
-				c-2.5-2.9-5-3.4-9-3.5L54,3.2L54,3.2z"/>
-		</g>
-		<g>
-			<path class="st0" d="M191.3,39.6c2.5,3.2,0.8,11-4.7,11.9h-32.8c-11.3-0.1-22.8-9.4-22.7-22.7S142.7,7,154.1,7
-				c10.4,0.1,16.8,7.3,17.4,8.2C173.4,17.7,189.1,36.8,191.3,39.6z"/>
-			<path class="st1" d="M153.8,51.8c-5.7,0-11.5-2.4-15.8-6.5c-4.7-4.4-7.2-10.3-7.2-16.6C130.9,15,142.9,6.6,154,6.6h0.1
-				c11.1,0.1,17.6,8.2,17.6,8.3c0.9,1.2,5,6.1,9.2,11.4c4.6,5.7,9.4,11.6,10.6,13.1l0,0c1.4,1.7,1.6,4.9,0.5,7.6
-				c-1,2.6-3,4.3-5.4,4.7L153.8,51.8z M154,7.2c-10.8,0-22.5,8.2-22.6,21.5c0,6.1,2.5,11.9,7,16.1c4.3,4,9.9,6.3,15.4,6.3h32.8
-				c2.1-0.4,3.9-1.9,4.9-4.4s0.8-5.4-0.4-7l0,0c-1.2-1.5-5.9-7.4-10.6-13.1c-4.3-5.2-8.3-10.2-9.2-11.4
-				C171.2,15.1,164.9,7.2,154,7.2L154,7.2z"/>
-		</g>
-		<g>
-			<path class="st0" d="M147.8,80.3h23.9c0.9,0,1.8,1.1,0.1,1.2h-24.3C146.8,81.5,146.2,80.6,147.8,80.3z"/>
-			<path class="st1" d="M147.5,81.8c-0.5,0-0.9-0.4-0.9-0.8c0-0.3,0.1-0.8,1.2-1l0,0h23.9c0.7,0,1.3,0.5,1.3,1
-				c0,0.3-0.2,0.7-1.2,0.8H147.5z M147.8,80.6c-0.6,0.1-0.7,0.3-0.7,0.4s0.2,0.3,0.4,0.3h24.3c0.5,0,0.7-0.2,0.7-0.2
-				c0-0.1-0.3-0.4-0.8-0.4L147.8,80.6z"/>
-		</g>
-		<g>
-			<path class="st0" d="M195.4,80.4c0.3,0.1,0.3,1.7-2.4,2.3c-4.1,1-6,0.3-5.4-0.7s1.3-0.4,4.2-0.9S194.7,80,195.4,80.4z"/>
-			<path class="st1" d="M189.6,83.5c-1.1,0-1.9-0.2-2.2-0.6c-0.2-0.3-0.2-0.6,0-0.9c0.4-0.7,1-0.8,1.9-0.8c0.6,0,1.4-0.1,2.5-0.2
-				c1.4-0.2,2.1-0.5,2.5-0.7c0.5-0.2,0.8-0.3,1.2,0c0.2,0.1,0.3,0.3,0.3,0.6c0,0.3-0.2,1.7-2.7,2.2
-				C191.8,83.3,190.5,83.5,189.6,83.5z M195,80.6c-0.1,0-0.2,0-0.5,0.1c-0.5,0.2-1.2,0.5-2.6,0.7c-1.1,0.2-1.9,0.2-2.5,0.3
-				c-1,0-1.2,0.1-1.5,0.5c-0.1,0.2,0,0.3,0,0.3c0.3,0.4,1.9,0.7,5.2-0.1c1.5-0.3,2-0.9,2.2-1.3c0.1-0.2,0.1-0.4,0.1-0.5
-				C195.2,80.6,195.1,80.6,195,80.6z"/>
-		</g>
-		<g>
-			<path class="st2" d="M154,8.6c12.2,0.2,21.3,10.3,21.3,20.4c-0.1,10.6-8.5,20.6-20.7,20.6c-12.2-0.1-22-9.2-21.9-21.1
-				C132.8,17.1,142.7,8.4,154,8.6z"/>
-			<path class="st1" d="M154.8,49.9h-0.1c-12.6-0.1-22.4-9.5-22.3-21.5c0-5.3,2.2-10.3,6-14.1c4.1-4,9.8-6.2,15.7-6.2l0,0
-				c12.9,0.2,21.8,11.1,21.7,20.8C175.7,39.1,167.7,49.9,154.8,49.9z M153.6,9c-5.5,0-10.8,2.1-14.7,5.9c-3.7,3.6-5.8,8.4-5.8,13.5
-				c-0.1,11.5,9.4,20.6,21.5,20.7h0.1c12.4,0,20.1-10.4,20.1-20.1c0-9.2-8.5-19.7-20.9-19.9C153.9,9,153.8,9,153.6,9z"/>
-		</g>
-		<g>
-			<path class="st2" d="M183.4,36.5c4.3,0,6.9,3.5,6.9,6.7c0,3.1-2.2,6.4-6.6,6.4c-4.2-0.1-6.9-3.5-6.9-6.7
-				C176.9,39.7,179.6,36.6,183.4,36.5z"/>
-			<path class="st1" d="M183.8,50.1h-0.1c-2,0-3.9-0.8-5.3-2.2c-1.3-1.4-2-3.2-2-4.9c0.1-3.2,2.8-6.7,7.1-6.8l0,0
-				c2.1,0,4,0.8,5.4,2.3c1.2,1.3,1.9,3.1,1.9,4.9c0,1.8-0.7,3.6-2,4.9C187.5,49.4,185.8,50.1,183.8,50.1z M183.5,37L183.5,37
-				c-3.8,0-6.2,3.1-6.3,5.9c0,1.6,0.6,3.1,1.8,4.3c1.2,1.3,2.9,2,4.7,2s3.4-0.5,4.5-1.7c1.1-1.1,1.7-2.7,1.7-4.3s-0.6-3.1-1.7-4.3
-				C187.4,38.1,185.9,37,183.5,37z"/>
-		</g>
-		<g>
-			<path class="st1" d="M154.5,46c-0.3,0-0.5-0.1-0.7-0.4c-0.2-0.2-1.3-2-2.3-3.7L151,41c-0.2-0.4-0.3-0.8-0.1-1
-				c0.1-0.1,0.3-0.3,0.7-0.3s1.8,0,3.1,0c1.1,0,2.2,0,2.5,0c0.5,0,0.7,0.3,0.8,0.4c0.1,0.2,0.1,0.6-0.1,0.8
-				c-0.1,0.1-0.3,0.6-0.7,1.2c-0.9,1.6-1.8,3.2-2,3.5S154.7,46,154.5,46L154.5,46z M151.5,40.2c-0.1,0-0.1,0-0.1,0.1s0,0.3,0.1,0.5
-				l0.5,0.8c0.7,1.2,2.1,3.5,2.3,3.7c0.1,0.1,0.2,0.2,0.3,0.2l0,0c0.1,0,0.2-0.1,0.2-0.2c0.2-0.3,1.3-2.2,2-3.4
-				c0.3-0.6,0.6-1,0.7-1.2c0.1-0.1,0.1-0.2,0-0.3c0-0.1-0.2-0.1-0.3-0.1c-0.3,0-1.3,0-2.5,0C153.3,40.2,152,40.2,151.5,40.2
-				L151.5,40.2L151.5,40.2z"/>
-		</g>
-		<g>
-			<path class="st1" d="M142,32c-0.2,0-0.3,0-0.6-0.1s-2.5-1.3-4.5-2.5l-0.5-0.3c-0.4-0.2-0.5-0.5-0.5-0.7c0-0.3,0.2-0.6,0.6-0.8
-				c0.3-0.2,2.2-1.2,3.4-1.9l1.1-0.6c0.3-0.2,0.8-0.4,1.1-0.2c0.4,0.2,0.3,0.7,0.3,0.8c0,0.6,0,3.8,0.1,5v0.4c0,0.3-0.1,0.6-0.3,0.7
-				C142.3,32,142.1,32,142,32z M141.9,25.5c-0.1,0-0.2,0-0.5,0.2l-1.1,0.6c-1.3,0.7-3.1,1.7-3.4,1.9c-0.2,0.1-0.3,0.2-0.3,0.3
-				c0,0.1,0.1,0.1,0.2,0.2l0.5,0.3c1.1,0.6,4.1,2.3,4.4,2.5c0.3,0.1,0.4,0.1,0.4,0.1s0-0.1,0-0.2V31c0-1.2-0.1-4.4-0.1-5h0.3H142
-				C142,25.6,142,25.5,141.9,25.5L141.9,25.5z"/>
-		</g>
-		<g>
-			<path class="st1" d="M166.6,32c-0.1,0-0.3,0-0.4-0.1c-0.2-0.1-0.4-0.3-0.4-0.8c0-0.3,0-1,0-1.8c0-1.3-0.1-2.9,0-3.4l0,0
-				c0-0.4,0.1-0.7,0.4-0.9c0.3-0.2,0.7-0.1,1.3,0.2c0.5,0.3,3.4,2,4.2,2.5l0.2,0.1c0.3,0.2,0.5,0.4,0.5,0.7c0,0.2-0.1,0.5-0.6,0.8
-				c-0.6,0.4-4.1,2.4-4.5,2.6C167,32,166.8,32,166.6,32z M166.3,25.9c0,0.6,0,2.1,0,3.4c0,0.8,0,1.5,0,1.8c0,0.1,0,0.3,0.1,0.3
-				c0.1,0.1,0.2,0,0.4-0.1c0.4-0.2,3.9-2.2,4.5-2.6c0.2-0.1,0.3-0.3,0.3-0.3c0-0.1-0.1-0.1-0.2-0.2l-0.2-0.1
-				c-0.8-0.5-3.7-2.1-4.2-2.4c-0.4-0.2-0.7-0.3-0.7-0.2C166.3,25.5,166.3,25.7,166.3,25.9L166.3,25.9z"/>
-		</g>
-		<g>
-			<path class="st1" d="M156.8,17.5L156.8,17.5c-0.3,0-4,0-5.2,0h-0.5c-0.4,0-0.7-0.1-0.8-0.4c-0.1-0.1-0.2-0.4,0-0.9
-				c0.1-0.3,0.7-1.2,1.3-2.2c0.6-0.9,1.1-1.8,1.3-2.2c0.3-0.4,0.5-0.7,0.8-0.7s0.5,0.1,0.7,0.5c0.1,0.2,0.7,1.1,1.3,2.1
-				c0.7,1.1,1.4,2.3,1.6,2.5c0.2,0.3,0.2,0.6,0.1,0.9C157.4,17.3,157.1,17.5,156.8,17.5z M151.1,16.9h0.5c2.3,0,5,0,5.2,0
-				c0.1,0,0.2,0,0.2-0.1c0.1-0.1,0-0.2-0.1-0.3c-0.2-0.3-0.9-1.4-1.6-2.6c-0.6-1-1.2-1.9-1.3-2.1c-0.1-0.2-0.2-0.2-0.2-0.2l0,0
-				c0,0-0.2,0.1-0.4,0.4c-0.2,0.4-0.8,1.3-1.3,2.2c-0.6,1-1.2,1.9-1.3,2.2c-0.1,0.1-0.1,0.2-0.1,0.3C150.9,16.9,151,16.9,151.1,16.9
-				L151.1,16.9z"/>
-		</g>
-		<g>
-			<path class="st1" d="M185.4,46.2L185.4,46.2h-3.8v-1.5h3.6l0,0c0.6,0,1-0.8,1-1.3c0-0.2-0.1-0.6-0.2-0.9
-				c-0.2-0.3-0.4-0.5-0.7-0.5h-3.2v1l-2.7-1.8l2.7-1.9v1.1h3.1c0.7,0,1.4,0.4,2,1c0.5,0.6,0.7,1.3,0.7,1.9c0,0.8-0.2,1.5-0.7,2
-				C186.7,45.9,186.1,46.2,185.4,46.2z M182.2,45.6h3.2l0,0c0.5,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1,0.6-1.7c0-0.5-0.2-1.1-0.6-1.6
-				c-0.4-0.5-0.9-0.8-1.5-0.8h-3.6v-0.6l-1.1,0.8l1.1,0.7v-0.5h3.7c0.5,0,1,0.3,1.2,0.8c0.3,0.5,0.3,1,0.3,1.2
-				c0,0.8-0.6,1.8-1.5,1.8l0,0h-3.1L182.2,45.6z"/>
-		</g>
-		<g>
-			<path class="st0" d="M133.3,47.9c0.7,0,1.3,0.7,1.3,1.3c0,0.5-0.4,1.2-1.2,1.1s-1.4-0.5-1.4-1.2C132,48.5,132.5,47.9,133.3,47.9z
-				"/>
-			<path class="st1" d="M133.4,50.6L133.4,50.6c-0.9,0-1.7-0.6-1.6-1.4c0-0.8,0.7-1.5,1.5-1.5l0,0l0,0c0.9,0,1.5,0.8,1.5,1.6
-				C134.8,49.9,134.3,50.6,133.4,50.6z M133.3,48.2c-0.5,0-1,0.4-1,1c0,0.5,0.5,0.9,1.1,0.9l0,0c0.6,0,0.9-0.5,0.9-0.9
-				C134.2,48.8,133.8,48.2,133.3,48.2L133.3,48.2z"/>
-		</g>
-		<g>
-			<path class="st1" d="M154.4,35.9L154.4,35.9c-2.2,0-4.3-0.9-5.7-2.3c-1.3-1.3-2-3.1-1.9-5.1c0.1-4.8,4.4-7,7.4-7l0,0l0,0
-				c1.9,0,3.7,0.8,5.1,2.2c1.4,1.4,2.2,3.2,2.1,5.1c0,1.9-0.7,3.7-2,5C158.2,35.1,156.4,35.9,154.4,35.9z M154.2,22.3L154.2,22.3
-				c-2.7,0-6.5,1.9-6.5,6.2c0,1.7,0.6,3.3,1.7,4.4c1.3,1.3,3.2,2.1,5.1,2.1l0,0c1.7,0,3.3-0.6,4.4-1.8c1.1-1.2,1.8-2.7,1.8-4.4
-				c0-1.7-0.7-3.3-1.9-4.5C157.5,23,155.8,22.4,154.2,22.3z"/>
-		</g>
-		<g>
-			<path class="st0" d="M121.6,51.5H54.1c-2.7,0-5-2.2-5-5V11.7c0-2.7,2.2-5,5-5h67.5c2.7,0,5,2.2,5,5v34.8
-				C126.6,49.3,124.4,51.5,121.6,51.5z"/>
-			<path class="st1" d="M121.6,52H54.1c-3,0-5.5-2.4-5.5-5.5V11.7c0-3,2.4-5.5,5.5-5.5h67.5c3,0,5.5,2.5,5.5,5.5v34.8
-				C127.1,49.6,124.6,52,121.6,52z M54.1,7.3c-2.5,0-4.5,2-4.5,4.5v34.8c0,2.5,2,4.5,4.5,4.5h67.5c2.5,0,4.5-2,4.5-4.5V11.7
-				c0-2.5-2-4.5-4.5-4.5H54.1V7.3z"/>
-		</g>
-		<g>
-			<path class="st2" d="M121.4,49.1H54.5c-1.6,0-2.9-1.3-2.9-2.9V11.9c0-1.6,1.3-2.9,2.9-2.9h66.8c1.6,0,2.9,1.3,2.9,2.9v34.3
-				C124.3,47.8,123,49.1,121.4,49.1z"/>
-			<path class="st1" d="M121.4,49.4H54.5c-1.8,0-3.2-1.4-3.2-3.2V11.9c0-1.8,1.4-3.2,3.2-3.2h66.8c1.8,0,3.2,1.4,3.2,3.2v34.3
-				C124.5,48,123.1,49.4,121.4,49.4z M54.5,9.3c-1.4,0-2.6,1.2-2.6,2.6v34.3c0,1.4,1.2,2.6,2.6,2.6h66.8c1.4,0,2.6-1.2,2.6-2.6V11.9
-				c0-1.4-1.2-2.6-2.6-2.6C121.3,9.3,54.5,9.3,54.5,9.3z"/>
-		</g>
-	</g>
-	<g id="dolphin_1_">
-		<g>
-			<polygon points="86.7,35.8 86.1,35.8 85.6,35.8 85,35.8 85,36.4 85.6,36.4 86.1,36.4 86.7,36.4 87.2,36.4 87.8,36.4 87.8,35.8 
-				87.2,35.8 			"/>
-		</g>
-		<g>
-			<polygon points="70,35.8 69.5,35.8 69.5,36.3 70,36.3 70.6,36.3 70.6,35.8 			"/>
-		</g>
-		<g>
-			<rect x="58.97" y="35.47" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.1959 94.8637)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.79" y="35.63" transform="matrix(5.134305e-03 -1 1 5.134305e-03 21.8589 93.8361)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.7" y="35.69" transform="matrix(5.134305e-03 -1 1 5.134305e-03 20.7184 92.8058)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="88.9,35.3 88.3,35.3 88.3,34.7 87.8,34.7 87.2,34.7 87.2,35.3 87.8,35.3 87.8,35.8 88.3,35.8 88.9,35.9 
-				89.5,35.9 90,35.9 90,35.3 89.5,35.3 			"/>
-		</g>
-		<g>
-			<rect x="68.93" y="35.25" transform="matrix(5.134305e-03 -1 1 5.134305e-03 33.3228 104.5986)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="59.44" y="35.05" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.0809 94.909)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="58.35" y="35.01" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.0409 93.7807)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.27" y="35.07" transform="matrix(5.134305e-03 -1 1 5.134305e-03 21.9013 92.7517)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.18" y="34.93" transform="matrix(5.134305e-03 -1 1 5.134305e-03 20.9613 91.5241)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="90.6,34.8 90,34.7 90,35.3 90.6,35.3 91.1,35.3 91.7,35.3 91.7,34.8 91.1,34.8 			"/>
-		</g>
-		<g>
-			<rect x="60" y="34.43" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.2657 94.8522)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="58.92" y="34.39" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.2264 93.7232)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.93" y="34.45" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.1847 92.7943)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.74" y="34.5" transform="matrix(5.134305e-03 -1 1 5.134305e-03 21.9479 91.6674)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.66" y="34.46" transform="matrix(5.134305e-03 -1 1 5.134305e-03 20.9082 90.5384)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="91.7,34.2 91.7,34.8 92.2,34.8 92.8,34.8 92.8,34.2 92.2,34.2 			"/>
-		</g>
-		<g>
-			<polygon points="86.7,34.7 87.2,34.7 87.2,34.2 86.7,34.2 86.1,34.2 86.1,34.7 			"/>
-		</g>
-		<g>
-			<rect x="59.48" y="33.96" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.2096 93.8691)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="58.49" y="33.92" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.2686 92.8401)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.31" y="33.98" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.0293 91.7103)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.12" y="33.94" transform="matrix(5.134305e-03 -1 1 5.134305e-03 21.8907 90.4827)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.03" y="33.9" transform="matrix(5.134305e-03 -1 1 5.134305e-03 20.8514 89.3535)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="59.06" y="33.4" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.3532 92.8826)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.97" y="33.36" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.3134 91.753)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.88" y="33.42" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.1746 90.7263)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.7" y="33.47" transform="matrix(5.134305e-03 -1 1 5.134305e-03 21.9363 89.5974)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="93.9,33.1 93.3,33.1 92.8,33.1 92.2,33.1 91.7,33.1 91.1,33.1 90.6,33.1 90,33.1 89.5,33.1 88.9,33.1 88.4,33.1 
-				87.8,33.1 87.2,33.1 86.7,33.1 86.1,33.1 85.6,33.1 85,33.1 84.5,33.1 84.5,32.5 85,32.5 85,31.9 85.6,32 85.6,31.4 86.1,31.4 
-				86.2,30.8 86.7,30.8 86.7,30.3 87.3,30.3 87.3,29.7 87.8,29.7 87.8,29.2 88.4,29.2 88.4,28.6 88.9,28.6 88.9,28.1 89.5,28.1 
-				89.5,27.5 90.1,27.5 90.1,27 90.6,27 90.6,26.4 91.2,26.4 91.2,25.9 91.7,25.9 91.7,25.3 92.3,25.3 92.3,24.8 92.8,24.8 
-				92.8,24.2 93.4,24.2 93.4,23.7 93.4,23.1 93.4,22.6 93.4,22 92.9,22 92.9,21.5 92.3,21.5 91.7,21.4 91.2,21.4 91.2,20.9 
-				90.6,20.9 90.1,20.9 89.5,20.9 89,20.9 88.4,20.9 87.9,20.9 87.3,20.9 86.8,20.9 86.2,20.9 86.2,21.4 85.6,21.4 85.1,21.4 
-				85.1,22 84.5,22 84,22 84,22.5 83.4,22.5 82.9,22.5 82.9,22 82.3,22 82.3,21.4 82.3,20.8 81.8,20.8 81.8,20.3 81.8,19.7 
-				81.2,19.7 81.2,19.2 80.7,19.2 80.7,18.6 80.1,18.6 80.1,18.1 79.6,18.1 79.6,17.5 79,17.5 78.5,17.5 78.5,16.9 77.9,16.9 
-				77.4,16.9 77.4,16.4 76.8,16.4 76.2,16.4 75.7,16.4 75.7,15.8 75.1,15.8 74.6,15.8 74,15.8 73.5,15.8 72.9,15.8 72.9,15.3 
-				72.4,15.2 71.8,15.2 71.3,15.2 70.7,15.2 70.2,15.2 69.6,15.2 69,15.2 68.5,15.2 67.9,15.2 67.4,15.2 66.8,15.2 66.3,15.2 
-				65.7,15.2 65.2,15.2 64.6,15.2 64.6,15.8 64,15.8 63.5,15.8 62.9,15.8 62.4,15.8 62.4,16.3 61.8,16.3 61.3,16.3 60.7,16.3 
-				60.7,16.9 60.2,16.9 60.2,17.4 59.6,17.4 59.1,17.4 59,18 58.5,18 57.9,17.9 57.9,18.5 57.4,18.5 57.4,19.1 56.8,19.1 56.8,19.6 
-				56.3,19.6 56.3,20.2 55.7,20.2 55.7,20.7 55.2,20.7 55.1,21.3 55.1,21.8 54.6,21.8 54.6,22.4 54.6,22.9 54,22.9 54,23.5 54,24 
-				53.5,24 53.5,24.6 53.5,25.1 53.5,25.7 54,25.7 54,25.1 54,24.6 54.6,24.6 54.6,24 54.6,23.5 55.1,23.5 55.1,22.9 55.1,22.4 
-				55.7,22.4 55.7,21.8 55.7,21.3 56.3,21.3 56.3,20.7 56.8,20.7 56.8,20.2 57.4,20.2 57.4,19.6 57.9,19.6 57.9,19.1 58.5,19.1 
-				58.5,18.5 59,18.5 59.6,18.5 59.6,18 60.2,18 60.7,18 60.7,17.4 61.3,17.4 61.8,17.4 62.4,17.4 62.9,17.4 63.5,17.4 64,17.4 
-				64.6,17.4 65.1,17.4 65.7,17.4 66.3,17.4 66.8,17.4 67.4,17.4 67.4,16.9 66.8,16.9 66.3,16.9 65.7,16.9 65.2,16.9 64.6,16.9 
-				64,16.9 63.5,16.9 62.9,16.9 62.9,16.3 63.5,16.3 64,16.3 64.6,16.3 65.2,16.3 65.2,15.8 65.7,15.8 66.3,15.8 66.8,15.8 
-				67.4,15.8 67.9,15.8 68.5,15.8 69,15.8 69.6,15.8 70.1,15.8 70.7,15.8 71.3,15.8 71.8,15.8 72.4,15.8 72.4,16.4 72.9,16.4 
-				72.9,16.9 73.5,16.9 73.5,16.4 74,16.4 74,16.9 74.6,16.9 75.1,16.9 75.7,16.9 76.2,16.9 76.8,16.9 76.8,17.5 76.8,18 77.3,18 
-				77.9,18.1 78.5,18.1 79,18.1 79,18.6 79.6,18.6 79.6,19.2 80.1,19.2 80.1,19.7 80.7,19.7 80.7,20.3 81.2,20.3 81.2,20.8 
-				81.2,21.4 81.2,21.9 80.7,21.9 80.6,22.5 81.2,22.5 81.8,22.5 82.3,22.5 82.3,23.1 82.3,23.6 82.9,23.6 83.4,23.6 83.4,23.1 
-				84,23.1 84.5,23.1 84.5,22.5 85.1,22.5 85.6,22.5 85.6,22 86.2,22 86.8,22 86.8,21.4 87.3,21.4 87.9,21.4 88.4,21.4 89,21.4 
-				89.5,21.4 90.1,21.4 90.6,21.4 90.6,22 91.2,22 91.7,22 92.3,22 92.3,22.6 92.8,22.6 92.8,23.1 92.3,23.1 91.7,23.1 91.2,23.1 
-				90.6,23.1 90.6,23.7 90.1,23.7 89.5,23.7 89,23.7 89,24.2 88.4,24.2 87.8,24.2 87.8,24.8 87.3,24.8 86.7,24.7 86.7,25.3 
-				86.2,25.3 86.2,25.9 85.6,25.9 85.6,26.4 85.1,26.4 85.1,27 84.5,27 84.5,27.5 84,27.5 83.9,28.1 83.4,28.1 83.4,28.6 82.8,28.6 
-				82.8,29.2 82.3,29.2 82.3,29.7 81.7,29.7 81.7,30.3 81.2,30.3 81.2,30.8 80.6,30.8 80.6,31.4 80,31.4 80,31.9 79.5,31.9 
-				79.5,32.5 78.9,32.5 78.9,33 78.4,33 78.4,33.6 77.8,33.6 77.8,34.1 77.3,34.1 77.3,34.7 76.7,34.7 76.2,34.7 76.1,35.2 
-				75.6,35.2 75,35.2 75,35.8 74.5,35.8 73.9,35.8 73.4,35.8 73.4,36.3 72.8,36.3 72.3,36.3 71.7,36.3 71.2,36.3 70.6,36.3 
-				70.6,36.9 71.1,36.9 71.7,36.9 72.3,36.9 72.8,36.9 73.4,36.9 73.9,36.9 74.5,36.9 75,36.9 75.6,36.9 76.1,36.9 76.7,36.9 
-				77.2,36.9 77.8,36.9 78.4,36.9 78.9,36.9 79.5,36.9 80,36.9 80.6,36.9 81.1,36.9 81.7,36.9 82.2,36.9 82.8,36.9 83.3,36.9 
-				83.9,36.9 84.5,36.9 85,36.9 85,36.4 84.5,36.4 83.9,36.4 83.4,36.4 82.8,36.4 82.2,36.4 81.7,36.4 81.1,36.4 80.6,36.4 80,36.4 
-				79.5,36.4 78.9,36.4 78.4,36.4 78.4,35.8 78.4,35.2 78.9,35.2 78.9,34.7 79.5,34.7 79.5,34.1 80,34.1 80,33.6 80.6,33.6 
-				81.1,33.6 81.7,33.6 82.3,33.6 82.8,33.6 83.4,33.6 83.9,33.6 83.9,34.2 84.5,34.2 85,34.2 85.6,34.2 86.1,34.2 86.1,33.6 
-				86.7,33.6 87.2,33.6 87.8,33.6 88.4,33.6 88.9,33.6 89.5,33.6 90,33.6 90.6,33.6 91.1,33.6 91.7,33.6 92.2,33.6 92.8,33.7 
-				92.8,34.2 93.3,34.2 93.9,34.2 93.9,34.8 93.9,35.3 93.9,35.9 93.3,35.9 93.3,36.4 92.8,36.4 92.8,37 92.2,37 92.2,37.5 
-				91.7,37.5 91.7,38.1 91.1,38.1 90.6,38.1 90.5,38.6 90,38.6 89.4,38.6 88.9,38.6 88.9,39.2 88.3,39.2 87.8,39.2 87.2,39.2 
-				87.2,39.7 86.7,39.7 86.1,39.7 85.6,39.7 85.5,40.3 85,40.3 84.4,40.3 83.9,40.3 83.3,40.3 83.3,40.8 82.8,40.8 82.2,40.8 
-				81.7,40.8 81.1,40.8 81.1,41.4 80.6,41.4 80,41.4 79.4,41.3 79.4,41.9 78.9,41.9 78.9,42.5 79.4,42.5 80,42.5 80.5,42.5 
-				81.1,42.5 81.7,42.5 82.2,42.5 82.8,42.5 82.8,41.9 83.3,41.9 83.9,41.9 83.9,41.4 83.9,40.8 84.4,40.8 85,40.8 85.5,40.8 
-				86.1,40.8 86.1,40.3 86.7,40.3 87.2,40.3 87.8,40.3 87.8,39.7 88.3,39.7 88.9,39.7 89.4,39.7 89.4,39.2 90,39.2 90.5,39.2 
-				91.1,39.2 91.1,38.6 91.7,38.6 92.2,38.6 92.2,38.1 92.8,38.1 92.8,37.5 93.3,37.5 93.3,37 93.9,37 93.9,36.4 94.4,36.4 
-				94.4,35.9 94.4,35.3 94.4,34.8 94.5,34.2 94.5,33.7 93.9,33.7 			"/>
-		</g>
-		<g>
-			<rect x="58.43" y="32.94" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.1982 91.7988)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.35" y="32.89" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.1586 90.6696)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.16" y="32.85" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.02 89.442)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.07" y="32.91" transform="matrix(5.134305e-03 -1 1 5.134305e-03 21.8786 88.4149)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.91" y="32.37" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.2429 90.7118)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.92" y="32.23" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.4021 89.5849)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.74" y="32.39" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.0652 88.5576)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="60.55" y="31.83" transform="matrix(5.134305e-03 -1 1 5.134305e-03 28.4088 92.8184)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="58.4,31.8 58.4,32.4 59,32.4 59,32.9 59.5,32.9 59.5,33.5 60.1,33.5 60.1,34 60.6,34 60.6,34.6 61.2,34.6 
-				61.2,35.2 61.7,35.2 61.7,34.6 61.7,34 61.7,33.5 62.3,33.5 62.3,32.9 62.3,32.4 61.7,32.4 61.2,32.4 61.2,32.9 61.2,33.5 
-				60.6,33.5 60.6,32.9 60.1,32.9 60.1,32.4 59.5,32.4 59.5,31.8 59.5,31.3 59,31.3 59,31.8 			"/>
-		</g>
-		<g>
-			<rect x="57.39" y="31.81" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.2872 89.6305)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.3" y="31.76" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.2473 88.5013)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.02" y="31.72" transform="matrix(5.134305e-03 -1 1 5.134305e-03 23.0083 87.1761)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="57.95" y="31.28" transform="matrix(5.134305e-03 -1 1 5.134305e-03 26.3722 89.6722)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.87" y="31.14" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.4326 88.4445)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="55.68" y="31.1" transform="matrix(5.134305e-03 -1 1 5.134305e-03 24.2895 87.218)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="60.6,30.7 60.1,30.7 60.1,31.3 60.1,31.8 60.6,31.8 60.6,31.3 			"/>
-		</g>
-		<g>
-			<rect x="57.33" y="30.72" transform="matrix(5.134305e-03 -1 1 5.134305e-03 26.3174 88.4904)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="56.24" y="30.58" transform="matrix(5.134305e-03 -1 1 5.134305e-03 25.3767 87.2628)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<path d="M68.4,30.2v-0.6V29v-0.6v-0.6v-0.6h-0.6v-0.6V26h-0.6v-0.6h-0.6H66v-0.6h-0.6h-0.6h-0.6h-0.6H63v0.6h-0.6h-0.6V26h-0.6
-				v0.6v0.6h-0.6v0.6v0.6V29v0.6v0.6h0.6v0.6v0.6h0.6V32v0.6h0.6V32H63h0.6v-0.6h0.6h0.6h0.6v-0.6H66h0.6h0.6h0.6h0.6H69v-0.6
-				L68.4,30.2z M63.4,28v-0.6H64h0.6V28v0.6H64h-0.6V28z"/>
-		</g>
-		<g>
-			<rect x="56.71" y="30.06" transform="matrix(5.134305e-03 -1 1 5.134305e-03 26.3595 87.2071)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="71.2,29.7 71.2,29.1 71.2,28.6 71.2,28 71.2,27.4 71.2,26.9 71.2,26.3 70.6,26.3 70.6,26.9 70.6,27.4 70.6,28 
-				70.6,28.5 70.6,29.1 70.6,29.7 70.6,30.2 71.2,30.2 71.7,30.2 72.3,30.2 72.3,29.7 71.7,29.7 			"/>
-		</g>
-		<g>
-			<polygon points="60.1,29.6 60.1,29 60.1,28.5 60.1,27.9 60.1,27.4 60.1,26.8 59.6,26.8 59.6,27.4 59.6,27.9 59.5,28.5 59.5,29 
-				59.5,29.6 59.5,30.2 59.5,30.7 60.1,30.7 60.1,30.2 			"/>
-		</g>
-		<g>
-			<polygon points="72.3,29.1 72.3,29.7 72.8,29.7 73.4,29.7 73.4,29.1 72.9,29.1 			"/>
-		</g>
-		<g>
-			<polygon points="73.4,28.6 73.4,29.1 74,29.1 74.5,29.1 74.5,28.6 74,28.6 			"/>
-		</g>
-		<g>
-			<polygon points="74.5,28 74.5,28.6 75.1,28.6 75.6,28.6 75.6,28 75.1,28 			"/>
-		</g>
-		<g>
-			<polygon points="75.6,27.5 75.6,28 76.2,28 76.7,28 76.7,27.5 76.2,27.5 			"/>
-		</g>
-		<g>
-			<polygon points="69.5,28 69.5,28.5 69.5,29.1 69.5,29.7 69.5,30.2 69.5,30.8 69,30.8 69,31.3 69.5,31.3 70.1,31.3 70.1,30.8 
-				70.1,30.2 70.1,29.7 70.1,29.1 70.1,28.5 70.1,28 70.1,27.4 70.1,26.9 69.5,26.9 69.5,27.4 			"/>
-		</g>
-		<g>
-			<rect x="76.7" y="26.94" transform="matrix(5.134305e-03 -1 1 5.134305e-03 49.3644 104.0994)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="77.3,26.4 77.3,26.9 77.9,26.9 78.4,26.9 78.4,26.4 77.9,26.4 			"/>
-		</g>
-		<g>
-			<polygon points="69,26.9 69.5,26.9 69.5,26.3 69.5,25.8 69,25.8 69,26.3 			"/>
-		</g>
-		<g>
-			<polygon points="60.7,26.3 60.7,25.7 60.1,25.7 60.1,26.3 60.1,26.8 60.7,26.8 			"/>
-		</g>
-		<g>
-			<polygon points="58.4,26.8 58.4,27.4 58.4,27.9 58.4,28.5 58.4,29 58.4,29.6 58.4,30.1 57.9,30.1 57.9,30.7 58.4,30.7 58.4,31.3 
-				59,31.3 59,30.7 59,30.2 59,29.6 59,29 59,28.5 59,27.9 59,27.4 59,26.8 59,26.3 58.5,26.3 			"/>
-		</g>
-		<g>
-			<rect x="78.42" y="25.87" transform="matrix(5.134305e-03 -1 1 5.134305e-03 52.1503 104.7495)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="79,25.3 79,25.8 79.5,25.8 80.1,25.8 80.1,25.3 79.5,25.3 			"/>
-		</g>
-		<g>
-			<polygon points="75.1,25.2 74.5,25.2 74,25.2 74,25.8 74.5,25.8 75.1,25.8 75.6,25.8 76.2,25.8 76.2,25.3 75.6,25.2 			"/>
-		</g>
-		<g>
-			<polygon points="70.7,25.2 70.1,25.2 70.1,25.8 70.1,26.3 70.6,26.3 70.7,25.8 			"/>
-		</g>
-		<g>
-			<rect x="68.31" y="25.2" transform="matrix(5.134305e-03 -1 1 5.134305e-03 42.7596 93.9763)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="60.7" y="25.11" transform="matrix(5.134305e-03 -1 1 5.134305e-03 35.2776 86.2758)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="59,25.7 59,26.3 59.6,26.3 59.6,25.7 59.6,25.2 59,25.2 			"/>
-		</g>
-		<g>
-			<rect x="80.04" y="24.59" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.0393 105.1025)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="76.2,24.7 76.2,25.3 76.8,25.3 77.3,25.3 77.3,24.7 76.8,24.7 			"/>
-		</g>
-		<g>
-			<rect x="73.52" y="24.64" transform="matrix(5.134305e-03 -1 1 5.134305e-03 48.5014 98.6335)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="69.57" y="24.65" transform="matrix(5.134305e-03 -1 1 5.134305e-03 44.5623 94.6831)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="67.99" y="24.63" transform="matrix(5.134305e-03 -1 1 5.134305e-03 43.0018 93.0898)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="61.16" y="24.59" transform="matrix(5.134305e-03 -1 1 5.134305e-03 36.2632 86.2221)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="59.48" y="24.57" transform="matrix(5.134305e-03 -1 1 5.134305e-03 34.6008 84.5275)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="80.6,24.2 80.6,24.7 81.2,24.7 81.7,24.7 81.8,24.2 81.2,24.2 			"/>
-		</g>
-		<g>
-			<polygon points="77.3,24.1 77.3,24.7 77.9,24.7 78.4,24.7 78.4,24.2 77.9,24.1 			"/>
-		</g>
-		<g>
-			<rect x="72.9" y="23.98" transform="matrix(5.134305e-03 -1 1 5.134305e-03 48.5423 97.3489)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="69.04" y="24.08" transform="matrix(5.134305e-03 -1 1 5.134305e-03 44.6043 93.5989)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="67.3,24.7 67.9,24.7 67.9,24.1 67.3,24.1 66.8,24.1 66.8,24.6 			"/>
-		</g>
-		<g>
-			<polygon points="62.9,24.6 62.9,24.1 62.3,24.1 61.8,24.1 61.8,24.6 62.3,24.6 			"/>
-		</g>
-		<g>
-			<rect x="60.15" y="24.05" transform="matrix(5.134305e-03 -1 1 5.134305e-03 35.7867 84.6725)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="81.76" y="23.52" transform="matrix(5.134305e-03 -1 1 5.134305e-03 57.8264 105.7553)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="78.4" y="23.69" transform="matrix(5.134305e-03 -1 1 5.134305e-03 54.3101 102.5693)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="64,24.1 64.6,24.1 65.1,24.1 65.7,24.1 66.2,24.1 66.8,24.1 66.8,23.5 66.2,23.5 65.7,23.5 65.1,23.5 64.6,23.5 
-				64,23.5 63.5,23.5 62.9,23.5 62.9,24.1 63.5,24.1 			"/>
-		</g>
-		<g>
-			<rect x="60.61" y="23.43" transform="matrix(5.134305e-03 -1 1 5.134305e-03 36.8701 84.518)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="79,23 79,23.6 79.5,23.6 80.1,23.6 80.1,23.1 79.5,23 			"/>
-		</g>
-		<g>
-			<rect x="76.3" y="22.92" transform="matrix(5.134305e-03 -1 1 5.134305e-03 52.9897 99.6957)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="72.9,23 72.9,22.5 72.3,22.5 72.3,23 72.3,23.6 72.3,24.1 72.9,24.1 72.9,23.6 			"/>
-		</g>
-		<g>
-			<polygon points="69.6,23.6 69.6,23 69.6,22.4 69,22.4 69,23 68.4,23 68.5,22.4 67.9,22.4 67.9,21.9 67.3,21.9 67.3,22.4 
-				66.8,22.4 66.2,22.4 65.7,22.4 65.1,22.4 64.6,22.4 64,22.4 63.5,22.4 62.9,22.4 62.4,22.4 62.3,23 62.9,23 63.5,23 64,23 
-				64.6,23 65.1,23 65.7,23 66.2,23 66.8,23 67.3,23 67.3,23.5 67.9,23.5 68.4,23.5 68.4,24.1 69,24.1 69,23.5 			"/>
-		</g>
-		<g>
-			<polygon points="61.2,23 61.2,23.5 61.8,23.5 62.3,23.5 62.3,23 61.8,23 			"/>
-		</g>
-		<g>
-			<rect x="80.03" y="22.52" transform="matrix(5.134305e-03 -1 1 5.134305e-03 57.0965 103.0237)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="75.78" y="22.35" transform="matrix(5.134305e-03 -1 1 5.134305e-03 53.0348 98.6083)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="77.92" y="21.84" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.6797 100.2473)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="75.15" y="21.89" transform="matrix(5.134305e-03 -1 1 5.134305e-03 52.8798 97.5249)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="73.4,21.9 73.4,21.4 72.9,21.4 72.9,21.9 72.9,22.5 73.4,22.5 			"/>
-		</g>
-		<g>
-			<rect x="68.53" y="21.74" transform="matrix(5.134305e-03 -1 1 5.134305e-03 46.4396 90.7545)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="77.4" y="21.28" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.7244 99.1622)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="67.91" y="21.27" transform="matrix(5.134305e-03 -1 1 5.134305e-03 46.2849 89.6707)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="79.45" y="20.87" transform="matrix(5.134305e-03 -1 1 5.134305e-03 58.1702 100.8023)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="76.68" y="20.71" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.5681 97.8796)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="73.42" y="20.89" transform="matrix(5.134305e-03 -1 1 5.134305e-03 52.1523 94.7938)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="68.57" y="20.65" transform="matrix(5.134305e-03 -1 1 5.134305e-03 47.5681 89.7142)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="78.92" y="20.2" transform="matrix(5.134305e-03 -1 1 5.134305e-03 58.3146 99.6165)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="76.15" y="20.25" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.5148 96.894)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="73.98" y="20.17" transform="matrix(5.134305e-03 -1 1 5.134305e-03 53.4324 94.6384)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="70.1,20.8 69.6,20.8 69.6,21.3 69,21.3 69,21.9 69.6,21.9 69.6,22.4 70.1,22.4 70.1,21.9 70.1,21.3 70.7,21.3 
-				70.7,20.8 70.7,20.2 70.1,20.2 			"/>
-		</g>
-		<g>
-			<rect x="69.04" y="20.23" transform="matrix(5.134305e-03 -1 1 5.134305e-03 48.4527 89.7598)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="67.95" y="20.19" transform="matrix(5.134305e-03 -1 1 5.134305e-03 47.413 88.6307)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="78.4" y="19.74" transform="matrix(5.134305e-03 -1 1 5.134305e-03 58.2585 98.6329)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="74.54" y="19.54" transform="matrix(5.134305e-03 -1 1 5.134305e-03 54.6153 94.5821)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="70.69" y="19.55" transform="matrix(5.134305e-03 -1 1 5.134305e-03 50.7784 90.7335)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="69.6" y="19.61" transform="matrix(5.134305e-03 -1 1 5.134305e-03 49.6376 89.7032)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="68.51" y="19.66" transform="matrix(5.134305e-03 -1 1 5.134305e-03 48.4975 88.6725)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="77.88" y="19.17" transform="matrix(5.134305e-03 -1 1 5.134305e-03 58.3033 97.5454)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="75.01" y="19.02" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.6008 94.5286)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="70.07" y="19.08" transform="matrix(5.134305e-03 -1 1 5.134305e-03 50.6235 89.6503)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="68.98" y="19.14" transform="matrix(5.134305e-03 -1 1 5.134305e-03 49.4831 88.6196)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="75.67" y="18.5" transform="matrix(5.134305e-03 -1 1 5.134305e-03 56.7848 94.6709)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="70.1,18.6 70.7,18.6 70.7,18 70.1,18 69.6,18 69,18 69,18.6 69.6,18.6 69.6,19.1 70.1,19.1 			"/>
-		</g>
-		<g>
-			<rect x="76.14" y="17.98" transform="matrix(5.134305e-03 -1 1 5.134305e-03 57.77 94.6179)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="72.38" y="17.98" transform="matrix(5.134305e-03 -1 1 5.134305e-03 54.0291 90.8649)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="71.8,18 71.2,18 71.2,18.6 70.7,18.6 70.7,19.1 71.2,19.1 71.2,19.7 71.8,19.7 71.8,19.1 72.3,19.1 72.4,18.6 
-				71.8,18.6 			"/>
-		</g>
-		<g>
-			<rect x="72.95" y="17.45" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.1161 90.9096)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="71.86" y="17.41" transform="matrix(5.134305e-03 -1 1 5.134305e-03 54.0754 89.7809)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="68.5,17.4 67.9,17.4 67.4,17.4 67.4,18 67.9,18 68.5,18 69,18 69,17.5 			"/>
-		</g>
-		<g>
-			<rect x="73.41" y="16.93" transform="matrix(5.134305e-03 -1 1 5.134305e-03 56.0985 90.8536)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="72.32" y="16.89" transform="matrix(5.134305e-03 -1 1 5.134305e-03 55.0591 89.7247)" width="0.6" height="0.6"/>
-		</g>
-	</g>
-	<g id="furippa_1_">
-		<g>
-			<polygon points="107.3,30.9 107.3,31.5 107.8,31.5 108.4,31.5 108.4,30.9 107.8,30.9 			"/>
-		</g>
-		<g>
-			<rect x="108.43" y="30.34" transform="matrix(5.134305e-03 -1 1 5.134305e-03 77.5309 139.205)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="116.8,29.3 116.8,28.7 116.3,28.7 116.3,28.2 116.3,27.6 115.7,27.6 115.7,27 115.7,26.5 115.2,26.5 114.6,26.5 
-				114.6,27 114.6,27.6 114.6,28.2 115.1,28.2 115.1,28.7 115.1,29.3 115.7,29.3 115.7,29.9 115.7,30.4 116.3,30.4 116.3,31 
-				116.3,31.5 116.8,31.5 117.4,31.5 117.4,31 117.4,30.4 117.4,29.9 116.8,29.9 			"/>
-		</g>
-		<g>
-			<polygon points="108.4,29.3 108.4,28.7 107.8,28.7 107.8,29.3 107.8,29.8 108.4,29.8 			"/>
-		</g>
-		<g>
-			<polygon points="107.3,29.3 107.3,28.7 106.7,28.7 106.7,29.2 106.7,29.8 107.3,29.8 			"/>
-		</g>
-		<g>
-			<polygon points="109,29.3 109,29.8 109,30.4 109.5,30.4 109.5,29.8 109.5,29.3 109.5,28.7 109,28.7 			"/>
-		</g>
-		<g>
-			<polygon points="121.9,28.2 121.3,28.2 120.8,28.2 120.2,28.2 119.6,28.2 119.1,28.2 119.1,28.7 119.1,29.3 119.6,29.3 
-				120.2,29.3 120.8,29.3 121.3,29.3 121.9,29.3 122.4,29.3 122.4,28.8 122.4,28.2 			"/>
-		</g>
-		<g>
-			<polygon points="103.4,28.7 103.4,28.1 103.4,27.5 103.4,27 103.4,26.4 102.8,26.4 102.2,26.4 102.2,27 102.2,27.5 102.2,28.1 
-				102.2,28.7 102.8,28.7 			"/>
-		</g>
-		<g>
-			<polygon points="112.4,26.5 112.3,27 112.3,27.6 111.8,27.6 111.8,28.2 111.8,28.7 111.2,28.7 111.2,29.3 111.2,29.8 110.7,29.8 
-				110.6,30.4 110.6,31 110.6,31.5 111.2,31.5 111.8,31.5 111.8,31 111.8,30.4 112.3,30.4 112.3,29.8 112.3,29.3 112.9,29.3 
-				112.9,28.7 112.9,28.2 113.5,28.2 113.5,27.6 113.5,27 113.5,26.5 112.9,26.5 			"/>
-		</g>
-		<g>
-			<polygon points="104.5,26.4 104.5,27 104.5,27.6 104.5,28.1 104.5,28.7 104.5,29.2 103.9,29.2 103.9,29.8 103.4,29.8 103.3,30.4 
-				102.8,30.4 102.2,30.3 102.2,30.9 102.2,31.5 102.8,31.5 103.3,31.5 103.9,31.5 103.9,30.9 104.5,30.9 104.5,30.4 105,30.4 
-				105,29.8 105.6,29.8 105.6,29.2 105.6,28.7 105.6,28.1 105.6,27.6 105.6,27 105.6,26.4 105.1,26.4 			"/>
-		</g>
-		<g>
-			<polygon points="100,26.4 99.4,26.4 98.9,26.4 98.3,26.4 97.8,26.4 97.2,26.4 96.6,26.4 96.1,26.4 95.5,26.4 95.5,26.9 
-				95.5,27.5 96.1,27.5 96.6,27.5 97.2,27.5 97.8,27.5 98.3,27.5 98.9,27.5 99.4,27.5 100,27.5 100,28.1 100,28.7 99.4,28.6 
-				99.4,29.2 98.9,29.2 98.9,29.8 98.3,29.8 97.7,29.8 97.7,30.3 97.2,30.3 96.6,30.3 96.1,30.3 95.5,30.3 95.5,30.9 95.5,31.4 
-				96,31.4 96.6,31.4 97.2,31.4 97.7,31.4 98.3,31.5 98.3,30.9 98.9,30.9 99.4,30.9 99.4,30.3 100,30.3 100,29.8 100.5,29.8 
-				100.5,29.2 101.1,29.2 101.1,28.7 101.1,28.1 101.1,27.5 101.1,27 101.1,26.4 100.6,26.4 			"/>
-		</g>
-		<g>
-			<path d="M117.4,25.9h-0.6v0.6v0.6v0.6h0.6h0.6h0.6v-0.6v-0.6v-0.6H118H117.4z M118,27.1h-0.6v-0.6h0.6V27.1z"/>
-		</g>
-	</g>
-	<g id="waves_1_">
-		<g>
-			<polygon points="96.2,19.7 96.2,20.3 96.8,20.3 96.8,19.7 96.8,19.1 96.2,19.1 			"/>
-		</g>
-		<g>
-			<polygon points="94,19.7 94,20.3 94.5,20.3 94.5,19.7 94.5,19.1 94,19.1 			"/>
-		</g>
-		<g>
-			<polygon points="98.5,18 98.5,18.6 98.5,19.2 98.5,19.7 98.5,20.3 99,20.3 99,19.7 99,19.2 99,18.6 99,18 			"/>
-		</g>
-		<g>
-			<polygon points="96.2,18 95.7,18 95.7,18.6 95.7,19.1 96.2,19.1 96.2,18.6 			"/>
-		</g>
-		<g>
-			<rect x="93.43" y="18.64" transform="matrix(5.134305e-03 -1 1 5.134305e-03 74.3037 112.5742)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="92.9,18 92.3,18 92.3,18.6 92.9,18.6 93.4,18.6 93.4,18 			"/>
-		</g>
-		<g>
-			<polygon points="98.5,16.9 97.9,16.9 97.9,17.5 97.9,18 98.5,18 98.5,17.5 			"/>
-		</g>
-		<g>
-			<rect x="95.21" y="17.44" transform="matrix(5.134305e-03 -1 1 5.134305e-03 77.2823 113.1613)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<rect x="94.49" y="16.83" transform="matrix(5.134305e-03 -1 1 5.134305e-03 77.1711 111.8337)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="97.9,15.8 97.4,15.8 97.4,16.3 97.4,16.9 97.9,16.9 97.9,16.3 			"/>
-		</g>
-		<g>
-			<polygon points="94,16.3 93.4,16.3 93.4,16.9 94,16.9 94.5,16.9 94.5,16.3 			"/>
-		</g>
-		<g>
-			<polygon points="92.9,15.8 92.3,15.8 92.3,16.3 92.9,16.3 93.4,16.3 93.4,15.8 			"/>
-		</g>
-		<g>
-			<rect x="96.88" y="15.11" transform="matrix(5.134305e-03 -1 1 5.134305e-03 81.2768 112.5089)" width="0.6" height="0.6"/>
-		</g>
-		<g>
-			<polygon points="96.2,14.7 95.7,14.6 95.7,15.2 96.2,15.2 96.8,15.2 96.8,14.7 			"/>
-		</g>
-		<g>
-			<polygon points="95.1,14.1 94.6,14.1 94.6,14.6 95.1,14.6 95.7,14.6 95.7,14.1 			"/>
-		</g>
-		<g>
-			<polygon points="94,13.5 93.4,13.5 92.9,13.5 92.3,13.5 92.3,14.1 92.9,14.1 93.4,14.1 94,14.1 94.6,14.1 94.6,13.5 			"/>
-		</g>
-	</g>
-	<g class="st3">
-		<path class="st4" d="M93.5,71.9c-2.2,0-4.5,0-6.7,0v-0.8h0.8c0-0.4,0-1.3,0-1.7h0.8c0-0.4,0-1.3,0-1.7h0.8c0-0.7,0-1.8,0-2.5
-			c-0.4,0-1.3,0-1.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7c3.3,0,6.7,0,10.1,0v-0.8h0.8v-0.8C94.7,71.9,93.9,71.9,93.5,71.9z"/>
-		<path class="st4" d="M101,68.6v-0.8h0.8c0-0.7,0-1.8,0-2.5c-0.4,0-1.3,0-1.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0V73h0.8c0-0.4,0-1.3,0-1.7h0.8
-			c0-0.4,0-1.3,0-1.7h0.8V68.6z"/>
-		<path class="st4" d="M127.8,67.7h0.8v-0.8h0.8c0-0.4,0-1.3,0-1.7c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7
-			h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0v-0.8h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8
-			c2.8,0,5.6,0,8.4,0v-0.8h0.8v-0.8h0.8C127.8,68.8,127.8,67.7,127.8,67.7z M126.1,67.7h-0.8v0.8c-2.2,0-4.5,0-6.7,0v-0.8h0.8v-0.8
-			c2.2,0,4.5,0,6.7,0V67.7z"/>
-		<path class="st4" d="M114.4,67.7h0.8v-0.8h0.8c0-0.4,0-1.3,0-1.7c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7
-			h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H101c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0v-0.8h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8
-			c2.8,0,5.6,0,8.4,0v-0.8h0.8v-0.8h0.8L114.4,67.7L114.4,67.7z M112.7,67.7h-0.8v0.8c-2.2,0-4.5,0-6.7,0v-0.8h0.8v-0.8
-			c2.2,0,4.5,0,6.7,0V67.7z"/>
-		<path class="st4" d="M142.1,66.9v-0.8h0.8v-0.8c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H128c0,0.4,0,1.3,0,1.7c3.6,0,7.3,0,10.9,0V73h0.8v-0.8c-3.1,0-6.2,0-9.2,0v-0.8h0.8
-			v-0.8c2.5,0,5.1,0,7.5,0v-0.8h0.8V69c-2.5,0-5.1,0-7.5,0v-0.8h0.8v-0.8C135.9,66.9,139,66.9,142.1,66.9z"/>
-		<path class="st4" d="M85.1,66.9v-0.8h0.8v-0.8c-4.2,0-8.4,0-12.6,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H70c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0v-0.8h0.8
-			c0-0.4,0-1.3,0-1.7h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8c2.5,0,5.1,0,7.5,0v-0.8h0.8v-0.8c-2.5,0-5.1,0-7.5,0v-0.8H75v-0.8
-			C78.3,66.9,81.7,66.9,85.1,66.9z"/>
-		<path class="st4" d="M156.3,65.2c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H143c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0v-0.8h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8c1.9,0,3.9,0,5.9,0v0.8h0.8V72
-			h0.8v0.8h0.8v0.8h0.8v0.8h0.8v0.8c0.4,0,1.3,0,1.7,0c0-0.4,0-1.3,0-1.7h-0.8v-0.8h-0.8v-0.8h-0.8v-0.8H153c0-0.4,0-1.3,0-1.7h0.8
-			v-0.8h0.8v-0.8h0.8V67h0.8v-0.8h0.8v-0.8h-0.7L156.3,65.2L156.3,65.2z M153,67.7h-0.8v0.8c-2.2,0-4.5,0-6.7,0v-0.8h0.8v-0.8
-			c2.2,0,4.5,0,6.7,0V67.7z"/>
-	</g>
-	<g>
-		<path class="st5" d="M93.2,72c-2.2,0-4.5,0-6.7,0v-0.8h0.8c0-0.4,0-1.3,0-1.7h0.8c0-0.4,0-1.3,0-1.7h0.8c0-0.7,0-1.8,0-2.5
-			c-0.4,0-1.3,0-1.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H84
-			c0,0.4,0,1.3,0,1.7c3.3,0,6.7,0,10,0V73h0.8v-1C94.5,72,93.7,72,93.2,72z"/>
-		<path class="st5" d="M100.8,68.7v-0.8h0.8c0-0.7,0-1.8,0-2.5c-0.4,0-1.3,0-1.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0v-0.8h0.8c0-0.4,0-1.3,0-1.7h0.8
-			c0-0.4,0-1.3,0-1.7h0.8V68.7z"/>
-		<path class="st5" d="M127.6,67.8h0.8V67h0.8c0-0.4,0-1.3,0-1.7c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7
-			h-0.8c0,0.4,0,1.3,0,1.7H115c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0V73h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8
-			c2.8,0,5.6,0,8.4,0v-0.8h0.8v-0.8h0.8v-1.1H127.6z M125.9,67.8h-0.8v0.8c-2.2,0-4.5,0-6.7,0v-0.8h0.8V67c2.2,0,4.5,0,6.7,0V67.8z"
-			/>
-		<path class="st5" d="M114.2,67.8h0.8V67h0.8c0-0.4,0-1.3,0-1.7c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7
-			h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0V73h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8
-			c2.8,0,5.6,0,8.4,0v-0.8h0.8v-0.8h0.8C114.2,68.9,114.2,67.8,114.2,67.8z M112.5,67.8h-0.8v0.8c-2.2,0-4.5,0-6.7,0v-0.8h0.8V67
-			c2.2,0,4.5,0,6.7,0V67.8z"/>
-		<path class="st5" d="M141.8,67v-0.8h0.8v-0.8c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7c3.6,0,7.3,0,10.9,0v-0.8h0.8V72c-3,0-6.2,0-9.2,0v-0.8h0.8
-			v-0.8c2.5,0,5,0,7.5,0v-0.8h0.8v-0.8c-2.5,0-5,0-7.5,0V68h0.8v-1C135.7,67,138.8,67,141.8,67z"/>
-		<path class="st5" d="M84.9,67v-0.8h0.8v-0.8c-4.2,0-8.4,0-12.6,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8
-			c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H69c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0v-0.8h0.8
-			c0-0.4,0-1.3,0-1.7h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8c2.5,0,5,0,7.5,0v-0.8h0.8V69c-2.5,0-5,0-7.5,0v-0.8h0.8V67
-			C78.2,67,81.6,67,84.9,67z"/>
-		<path class="st5" d="M156.1,65.3c-3.9,0-7.8,0-11.7,0c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7h-0.8c0,0.4,0,1.3,0,1.7H142
-			c0,0.4,0,1.3,0,1.7h-1c0,0.4,0,1.3,0,1.7c0.4,0,1.3,0,1.7,0V73h0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8c1.9,0,3.9,0,5.9,0v0.8h0.8V72h0.8
-			v0.8h0.8v0.8h0.8v0.8h0.8v0.8c0.4,0,1.3,0,1.7,0c0-0.4,0-1.3,0-1.7h-0.8v-0.8h-0.8V72h-0.8v-0.8h-0.8c0-0.4,0-1.3,0-1.7h0.8v-0.8
-			h0.8v-0.8h0.8V67h0.8v-0.8h0.8v-0.8h-0.6V65.3z M152.7,67.8h-0.8v0.8c-2.2,0-4.5,0-6.7,0v-0.8h0.8V67c2.2,0,4.5,0,6.7,0V67.8z"/>
-	</g>
-</g>
-</svg>

BIN
pokemon_trading/docs/images/youtube.png


+ 0 - 8
pokemon_trading/item_nl.h

@@ -1,8 +0,0 @@
-#ifndef __ITEM_NL_H__
-#define __ITEM_NL_H__
-
-#pragma once
-
-extern const NamedList item_list[];
-
-#endif // __ITEM_NL_H__

+ 0 - 8
pokemon_trading/move_nl.h

@@ -1,8 +0,0 @@
-#ifndef __MOVE_NL_H__
-#define __MOVE_NL_H__
-
-#pragma once
-
-extern const NamedList move_list[];
-
-#endif // __MOVE_NL_H__

+ 0 - 98
pokemon_trading/pokemon_app.c

@@ -1,98 +0,0 @@
-#include <furi_hal_light.h>
-#include <pokemon_icons.h>
-
-#include "pokemon_app.h"
-#include "pokemon_data.h"
-#include "scenes/pokemon_menu.h"
-#include "views/trade.h"
-#include "views/select_pokemon.h"
-#include "pokemon_char_encode.h"
-
-#include <expansion/expansion.h>
-
-PokemonFap* pokemon_alloc() {
-    PokemonFap* pokemon_fap = (PokemonFap*)malloc(sizeof(PokemonFap));
-
-    // View dispatcher
-    pokemon_fap->view_dispatcher = view_dispatcher_alloc();
-
-    view_dispatcher_set_event_callback_context(pokemon_fap->view_dispatcher, pokemon_fap);
-    view_dispatcher_attach_to_gui(
-        pokemon_fap->view_dispatcher,
-        (Gui*)furi_record_open(RECORD_GUI),
-        ViewDispatcherTypeFullscreen);
-
-    // Set up defaults
-    memcpy(&pokemon_fap->pins, &common_pinouts[PINOUT_ORIGINAL], sizeof(struct gblink_pins));
-
-    /* Set up gui modules used. It would be nice if these could be allocated and
-     * freed as needed, however, the scene manager still requires pointers that
-     * get set up as a part of the scene. Therefore, individual scene's exit
-     * callbacks cannot free the buffer.
-     *
-     * In order to do this properly, I think each scene, or maybe common to all
-     * scenes, would end up needing to set a delayed callback of some kind. But
-     * I'm not sure how to guarantee this gets called in a reasonable amount of
-     * time.
-     */
-    pokemon_fap->text_input = text_input_alloc();
-    pokemon_fap->submenu = submenu_alloc();
-    pokemon_fap->variable_item_list = variable_item_list_alloc();
-    pokemon_fap->dialog_ex = dialog_ex_alloc();
-
-    // Set up menu scene
-    pokemon_fap->scene_manager = scene_manager_alloc(&pokemon_scene_manager_handlers, pokemon_fap);
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewMainMenu, submenu_get_view(pokemon_fap->submenu));
-    scene_manager_next_scene(pokemon_fap->scene_manager, MainMenuScene);
-
-    return pokemon_fap;
-}
-
-void free_app(PokemonFap* pokemon_fap) {
-    furi_assert(pokemon_fap);
-
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-
-    view_dispatcher_free(pokemon_fap->view_dispatcher);
-
-    // Free scenes
-    scene_manager_free(pokemon_fap->scene_manager);
-
-    // Free gui modules
-    submenu_free(pokemon_fap->submenu);
-    text_input_free(pokemon_fap->text_input);
-    variable_item_list_free(pokemon_fap->variable_item_list);
-    dialog_ex_free(pokemon_fap->dialog_ex);
-
-    // Close records
-    furi_record_close(RECORD_GUI);
-
-    // Free rest
-    free(pokemon_fap);
-    pokemon_fap = NULL;
-}
-
-int32_t pokemon_app(void* p) {
-    UNUSED(p);
-
-    Expansion* expansion = furi_record_open(RECORD_EXPANSION);
-    expansion_disable(expansion);
-
-    PokemonFap* pokemon_fap = pokemon_alloc();
-
-    furi_hal_light_set(LightRed, 0x00);
-    furi_hal_light_set(LightGreen, 0x00);
-    furi_hal_light_set(LightBlue, 0x00);
-
-    //switch view and run dispatcher
-    view_dispatcher_run(pokemon_fap->view_dispatcher);
-
-    // Free resources
-    free_app(pokemon_fap);
-
-    expansion_enable(expansion);
-    furi_record_close(RECORD_EXPANSION);
-
-    return 0;
-}

+ 0 - 15
pokemon_trading/scenes/pokemon_exit_confirm.h

@@ -1,15 +0,0 @@
-#ifndef __POKEMON_EXIT_CONFIRM_H__
-#define __POKEMON_EXIT_CONFIRM_H__
-
-#pragma once
-
-#include <gui/modules/dialog_ex.h>
-#include <gui/scene_manager.h>
-
-void pokemon_exit_confirm_dialog_callback(DialogExResult result, void* context);
-
-void pokemon_exit_confirm_on_enter(void* context);
-
-bool pokemon_exit_confirm_on_event(void* context, SceneManagerEvent event);
-
-#endif // __POKEMON_EXIT_CONFIRM_H__

+ 0 - 232
pokemon_trading/scenes/pokemon_gen.c

@@ -1,232 +0,0 @@
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "../pokemon_char_encode.h"
-
-#include <named_list.h>
-
-#include "../views/trade.h"
-#include "../views/select_pokemon.h"
-
-#include "pokemon_menu.h"
-#include "pokemon_stats.h"
-#include "pokemon_shiny.h"
-#include "pokemon_gender.h"
-#include "pokemon_pokerus.h"
-#include "unown_form.h"
-
-static void scene_change_from_main_cb(void* context, uint32_t index) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    /* Reuse of scenes to allow for using the same functions to set names */
-    switch(index) {
-    case SelectNicknameScene:
-    case SelectOTNameScene:
-    case SelectUnownFormScene:
-        scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectNicknameScene, index);
-        break;
-    case SelectLevelScene:
-    case SelectOTIDScene:
-        scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectLevelScene, index);
-        break;
-    case SelectGenderScene:
-        if(select_gender_is_static(
-               pokemon_fap->pdata,
-               table_stat_base_get(
-                   pokemon_fap->pdata->pokemon_table,
-                   pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE),
-                   STAT_BASE_GENDER_RATIO,
-                   NONE)))
-            return;
-        break;
-    }
-
-    /* Set the navigation handler back to the basic one in the main menu. We only
-     * want gen_back_event_callback from this menu as going back from the gen menu
-     * means we need to free pdata.
-     */
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, main_menu_back_event_callback);
-
-    /* Set scene state to the current index so we can have that element highlighted when
-     * we return.
-     */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, GenITradeScene, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, index);
-}
-
-bool gen_back_event_callback(void* context) {
-    furi_assert(context);
-    PokemonFap* pokemon_fap = context;
-
-    scene_manager_next_scene(pokemon_fap->scene_manager, ConfirmExitScene);
-    return true;
-}
-
-void gen_scene_on_enter(void* context) {
-    char buf[32];
-    char name_buf[11]; // All name buffers are 11 bytes at most, including term
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-    int pkmn_num;
-    uint32_t state;
-
-    // Set up trade party struct
-    if(!pokemon_fap->pdata) {
-        state = scene_manager_get_scene_state(pokemon_fap->scene_manager, GenITradeScene);
-        switch(state) {
-        case GenITradeScene:
-            state = GEN_I;
-            break;
-        case GenIITradeScene:
-            state = GEN_II;
-            break;
-        default:
-            state = 0;
-            break;
-        }
-        pokemon_fap->pdata = pokemon_data_alloc(state);
-
-        /* Clear the scene state as this is the first entry in to this scene
-	 * we definitely want to be completely reset.
-	 */
-        scene_manager_set_scene_state(pokemon_fap->scene_manager, GenITradeScene, 0);
-
-        /* Allocate select and trade views */
-        /* Allocates its own view and adds it to the main view_dispatcher */
-        pokemon_fap->select = select_pokemon_alloc(
-            pokemon_fap->pdata,
-            pokemon_fap->view_dispatcher,
-            pokemon_fap->scene_manager,
-            AppViewSelectPokemon);
-
-        // Trade View
-        /* Allocates its own view and adds it to the main view_dispatcher */
-        pokemon_fap->trade = trade_alloc(
-            pokemon_fap->pdata, &pokemon_fap->pins, pokemon_fap->view_dispatcher, AppViewTrade);
-    }
-
-    pkmn_num = pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE);
-
-    /* Clear the scene state of the Move scene since that is used to set the
-     * highlighted menu item.
-     * This could be done in move, but move would need its own custom exit handler
-     * which is fine but would just waste a few more bytes compared to us handling
-     * it here.
-     */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectMoveScene, 0);
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectItemSetScene, 0);
-
-    submenu_reset(pokemon_fap->submenu);
-
-    snprintf(
-        buf,
-        sizeof(buf),
-        "Pokemon:   %s",
-        table_stat_name_get(pokemon_fap->pdata->pokemon_table, pkmn_num));
-    submenu_add_item(
-        pokemon_fap->submenu, buf, SelectPokemonScene, scene_change_from_main_cb, pokemon_fap);
-
-    pokemon_name_get(pokemon_fap->pdata, STAT_NICKNAME, name_buf, sizeof(name_buf));
-    snprintf(buf, sizeof(buf), "Nickname:  %s", name_buf);
-    submenu_add_item(
-        pokemon_fap->submenu, buf, SelectNicknameScene, scene_change_from_main_cb, pokemon_fap);
-
-    snprintf(
-        buf,
-        sizeof(buf),
-        "Level:           %d",
-        pokemon_stat_get(pokemon_fap->pdata, STAT_LEVEL, NONE));
-    submenu_add_item(
-        pokemon_fap->submenu, buf, SelectLevelScene, scene_change_from_main_cb, pokemon_fap);
-
-    if(pokemon_fap->pdata->gen == GEN_II) {
-        snprintf(
-            buf,
-            sizeof(buf),
-            "Held Item:   %s",
-            namedlist_name_get_index(
-                pokemon_fap->pdata->item_list,
-                pokemon_stat_get(pokemon_fap->pdata, STAT_HELD_ITEM, NONE)));
-        submenu_add_item(
-            pokemon_fap->submenu, buf, SelectItemScene, scene_change_from_main_cb, pokemon_fap);
-    }
-
-    submenu_add_item(
-        pokemon_fap->submenu,
-        "Select Moves",
-        SelectMoveScene,
-        scene_change_from_main_cb,
-        pokemon_fap);
-
-    if(pokemon_fap->pdata->gen == GEN_I) {
-        submenu_add_item(
-            pokemon_fap->submenu,
-            "Select Types",
-            SelectTypeScene,
-            scene_change_from_main_cb,
-            pokemon_fap);
-    }
-
-    submenu_add_item(
-        pokemon_fap->submenu,
-        namedlist_name_get_index(
-            pokemon_fap->pdata->stat_list, pokemon_stat_get(pokemon_fap->pdata, STAT_SEL, NONE)),
-        SelectStatsScene,
-        scene_change_from_main_cb,
-        pokemon_fap);
-
-    if(pokemon_fap->pdata->gen == GEN_II) {
-        snprintf(
-            buf,
-            sizeof(buf),
-            "Shiny:             %s",
-            select_shiny_is_shiny(pokemon_fap->pdata) ? "Yes" : "No");
-        submenu_add_item(
-            pokemon_fap->submenu, buf, SelectShinyScene, scene_change_from_main_cb, pokemon_fap);
-
-        snprintf(buf, sizeof(buf), "Gender:         %s", select_gender_get(pokemon_fap->pdata));
-        submenu_add_item(
-            pokemon_fap->submenu, buf, SelectGenderScene, scene_change_from_main_cb, pokemon_fap);
-
-        snprintf(buf, sizeof(buf), "Pokerus:       %s", select_pokerus_status(pokemon_fap));
-        submenu_add_item(
-            pokemon_fap->submenu, buf, SelectPokerusScene, scene_change_from_main_cb, pokemon_fap);
-
-        if(pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE) == 0xC8) { // Unown
-            snprintf(buf, sizeof(buf), "Unown Form: %c", unown_form_get(pokemon_fap->pdata));
-            submenu_add_item(
-                pokemon_fap->submenu,
-                buf,
-                SelectUnownFormScene,
-                scene_change_from_main_cb,
-                pokemon_fap);
-        }
-    }
-
-    snprintf(
-        buf,
-        sizeof(buf),
-        "OT ID#:          %05d",
-        pokemon_stat_get(pokemon_fap->pdata, STAT_OT_ID, NONE));
-    submenu_add_item(
-        pokemon_fap->submenu, buf, SelectOTIDScene, scene_change_from_main_cb, pokemon_fap);
-
-    pokemon_name_get(pokemon_fap->pdata, STAT_OT_NAME, name_buf, sizeof(name_buf));
-    snprintf(buf, sizeof(buf), "OT Name:      %s", name_buf);
-    submenu_add_item(
-        pokemon_fap->submenu, buf, SelectOTNameScene, scene_change_from_main_cb, pokemon_fap);
-
-    submenu_add_item(
-        pokemon_fap->submenu, "Trade PKMN", TradeScene, scene_change_from_main_cb, pokemon_fap);
-
-    /* TODO: Add Save pokemon option here */
-
-    /* HACK: No matter what gen were in, we just store the scene state in GenITradeScene */
-    submenu_set_selected_item(
-        pokemon_fap->submenu,
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, GenITradeScene));
-
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, gen_back_event_callback);
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-}

+ 0 - 8
pokemon_trading/scenes/pokemon_gen.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_GEN_H
-#define POKEMON_GEN_H
-
-#pragma once
-
-void gen_scene_on_enter(void* context);
-
-#endif // POKEMON_GEN_H

+ 0 - 104
pokemon_trading/scenes/pokemon_gender.c

@@ -1,104 +0,0 @@
-#include <gui/modules/submenu.h>
-
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "pokemon_menu.h"
-
-static const char* gender_str[] = {
-    "Unknown",
-    "Female",
-    "Male",
-};
-
-/* This returns a string pointer if the gender is static, NULL if it is not and
- * the gender needs to be calculated.
- */
-const char* select_gender_is_static(PokemonData* pdata, uint8_t ratio) {
-    switch(ratio) {
-    case 0xFF:
-        return gender_str[0];
-    case 0xFE:
-        return gender_str[1];
-    case 0x00:
-        if(pokemon_stat_get(pdata, STAT_NUM, NONE) != 0xEB) { // Tyrogue can be either gender
-            return gender_str[2];
-        }
-        break;
-    default:
-        break;
-    }
-
-    return NULL;
-}
-
-const char* select_gender_get(PokemonData* pdata) {
-    uint8_t ratio = table_stat_base_get(
-        pdata->pokemon_table,
-        pokemon_stat_get(pdata, STAT_NUM, NONE),
-        STAT_BASE_GENDER_RATIO,
-        NONE);
-    uint8_t atk_iv;
-    const char* rc;
-
-    rc = select_gender_is_static(pdata, ratio);
-    if(rc) return rc;
-
-    /* Falling through here means now we need to calculate the gender from
-     * its ratio and ATK_IV.
-     */
-    atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
-    if(atk_iv * 17 <= ratio)
-        return gender_str[1];
-    else
-        return gender_str[2];
-}
-
-static void select_gender_selected_callback(void* context, uint32_t index) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-    PokemonData* pdata = pokemon_fap->pdata;
-    uint8_t ratio = table_stat_base_get(
-        pdata->pokemon_table,
-        pokemon_stat_get(pdata, STAT_NUM, NONE),
-        STAT_BASE_GENDER_RATIO,
-        NONE);
-    uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
-
-    /* If we need to make the pokemon a male, increase atk IV until it exceeds
-     * the gender ratio.
-     *
-     * Note that, there is no checking here for impossible situations as the
-     * scene enter function will immediately quit if its not possible to change
-     * the gender (the extremes of gender_ratio value).
-     *
-     * The check for gender is a percentage, if ATK_IV*(255/15) <= the ratio,
-     * then the pokemon is a female. The gender ratio values end up being:
-     * DEF GENDER_F0      EQU   0 percent
-     * DEF GENDER_F12_5   EQU  12 percent + 1
-     * DEF GENDER_F25     EQU  25 percent
-     * DEF GENDER_F50     EQU  50 percent
-     * DEF GENDER_F75     EQU  75 percent
-     * DEF GENDER_F100    EQU 100 percent - 1
-     * Where percent is (255/100)
-     */
-    if(index) {
-        while((atk_iv * 17) <= ratio) atk_iv++;
-    } else {
-        while((atk_iv * 17) > ratio) atk_iv--;
-    }
-
-    pokemon_stat_set(pdata, STAT_ATK_IV, NONE, atk_iv);
-
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
-}
-
-void select_gender_scene_on_enter(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    submenu_reset(pokemon_fap->submenu);
-
-    submenu_add_item(
-        pokemon_fap->submenu, "Female", 0, select_gender_selected_callback, pokemon_fap);
-
-    submenu_add_item(
-        pokemon_fap->submenu, "Male", 1, select_gender_selected_callback, pokemon_fap);
-}

+ 0 - 22
pokemon_trading/scenes/pokemon_gender.h

@@ -1,22 +0,0 @@
-#ifndef POKEMON_GENDER_H
-#define POKEMON_GENDER_H
-
-#pragma once
-
-/* The gender ratio is a bit value, and if the ATK_IV is less than or equal to
- * the gender ratio, the gender is female.
- *
- * A ratio of 0xff means gender is unknown.
- * A ratio of 0x00 is annoyingly special. It either means that pokemon can be
- *   male only -OR- there is a very small chance the pokemon is female. The
- *   male only pokemon need to be specifically checked for.
- */
-
-const char* select_gender_is_static(PokemonData* pdata, uint8_t ratio);
-
-/* This will return a pointer to a string of the pokemon's current gender */
-char* select_gender_get(PokemonData* pdata);
-
-void select_gender_scene_on_enter(void* context);
-
-#endif // POKEMON_GENDER_H

+ 0 - 10
pokemon_trading/scenes/pokemon_item.h

@@ -1,10 +0,0 @@
-#ifndef POKEMON_ITEM_H
-#define POKEMON_ITEM_H
-
-#pragma once
-
-void select_item_scene_on_enter(void* context);
-
-void select_item_set_scene_on_enter(void* context);
-
-#endif // POKEMON_ITEM_H

+ 0 - 174
pokemon_trading/scenes/pokemon_menu.c

@@ -1,174 +0,0 @@
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "../pokemon_char_encode.h"
-
-#include "pokemon_menu.h"
-#include "pokemon_gen.h"
-#include "pokemon_select.h"
-#include "pokemon_name_input.h"
-#include "pokemon_number_input.h"
-#include "pokemon_move.h"
-#include "pokemon_item.h"
-#include "pokemon_type.h"
-#include "pokemon_stats.h"
-#include "pokemon_shiny.h"
-#include "pokemon_gender.h"
-#include "pokemon_pokerus.h"
-#include "pokemon_trade.h"
-#include "pokemon_pins.h"
-#include "pokemon_exit_confirm.h"
-
-static void scene_change_from_main_cb(void* context, uint32_t index) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    /* The same trade scene is used for both gen i and ii. Set the real index to
-     * scene's state.
-     */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, GenITradeScene, index);
-
-    /* Set scene state to the current index so we can have that element highlighted when
-     * we return.
-     */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, MainMenuScene, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, index);
-}
-
-bool main_menu_back_event_callback(void* context) {
-    furi_assert(context);
-    PokemonFap* pokemon_fap = context;
-    return scene_manager_handle_back_event(pokemon_fap->scene_manager);
-}
-
-void main_menu_scene_on_enter(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    submenu_reset(pokemon_fap->submenu);
-    submenu_set_header(pokemon_fap->submenu, "Pokemon Trade Tool");
-
-    submenu_add_item(
-        pokemon_fap->submenu,
-        "Gen I    (R/B/Y non-JPN)",
-        GenITradeScene,
-        scene_change_from_main_cb,
-        pokemon_fap);
-    submenu_add_item(
-        pokemon_fap->submenu,
-        "Gen II   (G/S/C non-JPN)",
-        GenIITradeScene,
-        scene_change_from_main_cb,
-        pokemon_fap);
-    submenu_add_item(
-        pokemon_fap->submenu,
-        "Select EXT Pinout",
-        SelectPinsScene,
-        scene_change_from_main_cb,
-        pokemon_fap);
-
-    submenu_set_selected_item(
-        pokemon_fap->submenu,
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, MainMenuScene));
-
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, main_menu_back_event_callback);
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-}
-
-bool null_scene_on_event(void* context, SceneManagerEvent event) {
-    UNUSED(context);
-    UNUSED(event);
-    return false;
-}
-
-void null_scene_on_exit(void* context) {
-    UNUSED(context);
-}
-
-void generic_scene_on_exit(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewMainMenu);
-    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewOpts);
-}
-
-void (*const pokemon_scene_on_enter_handlers[])(void*) = {
-    main_menu_scene_on_enter, //MainMenuScene,
-    gen_scene_on_enter, //GenITradeScene,
-    gen_scene_on_enter, //GenIITradeScene,
-    select_pokemon_scene_on_enter, //SelectPokemonScene,
-    select_name_scene_on_enter, //SelectNicknameScene,
-    select_number_scene_on_enter, //SelectLevelScene,
-    select_move_scene_on_enter, //SelectMoveScene,
-    select_move_index_scene_on_enter, //SelectMoveIndexScene,
-    select_move_set_scene_on_enter, //SelectMoveSetScene,
-    select_item_scene_on_enter, //SelectItemScene,
-    select_item_set_scene_on_enter, //SelectItemSetScene,
-    select_type_scene_on_enter, //SelectTypeScene,
-    select_stats_scene_on_enter, //SelectStatsScene,
-    select_shiny_scene_on_enter, //SelectShinyScene,
-    select_gender_scene_on_enter, //SelectGenderScene,
-    select_pokerus_scene_on_enter, //SelectPokerusScene,
-    select_name_scene_on_enter, //SelectUnownFormScene,
-    select_number_scene_on_enter, //SelectOTIDScene,
-    select_name_scene_on_enter, //SelectOTNameScene,
-    trade_scene_on_enter, //TradeScene,
-    select_pins_scene_on_enter, //SelectPinsScene,
-    pokemon_exit_confirm_on_enter, //ConfirmExitScene,
-};
-
-void (*const pokemon_scene_on_exit_handlers[])(void*) = {
-    null_scene_on_exit, //MainMenuScene,
-    null_scene_on_exit, //GenITradeScene,
-    null_scene_on_exit, //GenIITradeScene,
-    null_scene_on_exit, //SelectPokemonScene,
-    generic_scene_on_exit, //SelectNicknameScene,
-    generic_scene_on_exit, //SelectLevelScene,
-    null_scene_on_exit, //SelectMoveScene,
-    null_scene_on_exit, //SelectMoveIndexScene,
-    null_scene_on_exit, //SelectMoveSetScene,
-    null_scene_on_exit, //SelectItemScene,
-    null_scene_on_exit, //SelectItemSetScene,
-    generic_scene_on_exit, //SelectTypeScene,
-    null_scene_on_exit, //SelectStatsScene,
-    null_scene_on_exit, //SelectShinyScene,
-    null_scene_on_exit, //SelectGenderScene,
-    generic_scene_on_exit, //SelectPokerusScene,
-    generic_scene_on_exit, //SelectUnownFormScene,
-    generic_scene_on_exit, //SelectOTIDScene,
-    generic_scene_on_exit, //SelectOTNameScene,
-    null_scene_on_exit, //TradeScene,
-    generic_scene_on_exit, //SelectPinsScene,
-    generic_scene_on_exit, //ConfirmExitScene,
-};
-
-bool (*const pokemon_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
-    null_scene_on_event, //MainMenuScene,
-    null_scene_on_event, //GenITradeScene,
-    null_scene_on_event, //GenIITradeScene,
-    null_scene_on_event, //SelectPokemonScene,
-    null_scene_on_event, //SelectNicknameScene,
-    null_scene_on_event, //SelectLevelScene,
-    null_scene_on_event, //SelectMoveScene,
-    null_scene_on_event, //SelectMoveIndexScene,
-    null_scene_on_event, //SelectMoveSetScene,
-    null_scene_on_event, //SelectItemScene,
-    null_scene_on_event, //SelectItemSetScene,
-    null_scene_on_event, //SelectTypeScene,
-    null_scene_on_event, //SelectStatsScene,
-    null_scene_on_event, //SelectShinyScene,
-    null_scene_on_event, //SelectGenderScene,
-    null_scene_on_event, //SelectPokerusScene,
-    null_scene_on_event, //SelectUnownFormScene,
-    null_scene_on_event, //SelectOTIDScene,
-    null_scene_on_event, //SelectOTNameScene,
-    null_scene_on_event, //TradeScene,
-    null_scene_on_event, //SelectPinsScene,
-    pokemon_exit_confirm_on_event, //ConfirmExitScene,
-};
-
-const SceneManagerHandlers pokemon_scene_manager_handlers = {
-    .on_enter_handlers = pokemon_scene_on_enter_handlers,
-    .on_exit_handlers = pokemon_scene_on_exit_handlers,
-    .on_event_handlers = pokemon_scene_on_event_handlers,
-    .scene_num = SceneCount,
-};

+ 0 - 38
pokemon_trading/scenes/pokemon_menu.h

@@ -1,38 +0,0 @@
-#ifndef POKEMON_MENU_H
-#define POKEMON_MENU_H
-
-#pragma once
-
-#include <gui/scene_manager.h>
-
-typedef enum {
-    MainMenuScene,
-    GenITradeScene, // Formerly main menu scene
-    GenIITradeScene,
-    SelectPokemonScene,
-    SelectNicknameScene,
-    SelectLevelScene,
-    SelectMoveScene,
-    SelectMoveIndexScene,
-    SelectMoveSetScene,
-    SelectItemScene,
-    SelectItemSetScene,
-    SelectTypeScene,
-    SelectStatsScene,
-    SelectShinyScene,
-    SelectGenderScene,
-    SelectPokerusScene,
-    SelectUnownFormScene,
-    SelectOTIDScene,
-    SelectOTNameScene,
-    TradeScene,
-    SelectPinsScene,
-    ConfirmExitScene,
-    SceneCount,
-} AppScene;
-
-extern const SceneManagerHandlers pokemon_scene_manager_handlers;
-
-bool main_menu_back_event_callback(void* context);
-
-#endif // POKEMON_MENU_H

+ 0 - 12
pokemon_trading/scenes/pokemon_move.h

@@ -1,12 +0,0 @@
-#ifndef POKEMON_MOVE_H
-#define POKEMON_MOVE_H
-
-#pragma once
-
-void select_move_scene_on_enter(void* context);
-
-void select_move_index_scene_on_enter(void* context);
-
-void select_move_set_scene_on_enter(void* context);
-
-#endif // POKEMON_MOVE_H

+ 0 - 8
pokemon_trading/scenes/pokemon_name_input.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_NAME_H
-#define POKEMON_NAME_H
-
-#pragma once
-
-void select_name_scene_on_enter(void* context);
-
-#endif // POKEMON_NAME_H

+ 0 - 8
pokemon_trading/scenes/pokemon_number_input.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_NUMBER_INPUT_H
-#define POKEMON_NUMBER_INPUT_H
-
-#pragma once
-
-void select_number_scene_on_enter(void* context);
-
-#endif // POKEMON_NUMBER_INPUT_H

+ 0 - 8
pokemon_trading/scenes/pokemon_pins.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_PINS_H
-#define POKEMON_PINS_H
-
-#pragma once
-
-void select_pins_scene_on_enter(void* context);
-
-#endif // POKEMON_PINS_H

+ 0 - 11
pokemon_trading/scenes/pokemon_pokerus.h

@@ -1,11 +0,0 @@
-#ifndef __POKEMON_POKERUS_H__
-#define __POKEMON_POKERUS_H__
-
-#include "../pokemon_app.h"
-
-#pragma once
-
-void select_pokerus_scene_on_enter(void* context);
-const char* select_pokerus_status(PokemonFap* pokemon_fap);
-
-#endif // __POKEMON_POKERUS_H__

+ 0 - 9
pokemon_trading/scenes/pokemon_select.c

@@ -1,9 +0,0 @@
-#include "../pokemon_app.h"
-
-void select_pokemon_scene_on_enter(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-    // switch to select pokemon scene
-    // Note for the future, this might make sense to setup and teardown each view
-    // at runtime rather than at the start of the whole application
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSelectPokemon);
-}

+ 0 - 8
pokemon_trading/scenes/pokemon_select.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_SELECT_H
-#define POKEMON_SELECT_H
-
-#pragma once
-
-void select_pokemon_scene_on_enter(void* context);
-
-#endif // POKEMON_SELECT_H

+ 0 - 81
pokemon_trading/scenes/pokemon_shiny.c

@@ -1,81 +0,0 @@
-#include <gui/modules/submenu.h>
-
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-
-#include "pokemon_menu.h"
-
-/* This just assumes gen ii for now */
-/* For a Gen II pokemon to be shiny, the following must be met:
- * Spd, Def, and Spc must all be 10
- * Atk must be 2, 3, 6, 7, 10, 11, 14, or 15
- */
-bool select_shiny_is_shiny(PokemonData* pdata) {
-    uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
-    uint8_t def_iv = pokemon_stat_get(pdata, STAT_DEF_IV, NONE);
-    uint8_t spd_iv = pokemon_stat_get(pdata, STAT_SPD_IV, NONE);
-    uint8_t spc_iv = pokemon_stat_get(pdata, STAT_SPC_IV, NONE);
-    bool rc = 1;
-
-    if(spd_iv != 10) rc = 0;
-    if(def_iv != 10) rc = 0;
-    if(spc_iv != 10) rc = 0;
-    switch(atk_iv) {
-    case 0:
-    case 1:
-    case 4:
-    case 5:
-    case 8:
-    case 9:
-    case 12:
-    case 13:
-        rc = 0;
-        break;
-    default:
-        break;
-    }
-
-    return rc;
-}
-
-static void select_shiny_selected_callback(void* context, uint32_t index) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-    PokemonData* pdata = pokemon_fap->pdata;
-
-    if(!index) {
-        do {
-            /* First, reset the IV to the selected stat */
-            pokemon_stat_set(pdata, STAT_SEL, NONE, pokemon_stat_get(pdata, STAT_SEL, NONE));
-
-            /* Next, ensure the current IVs wouldn't make the pokemon shiny */
-        } while(select_shiny_is_shiny(pdata));
-    } else {
-        /* Set Def, Spd, Spc to 10 */
-        pokemon_stat_set(pdata, STAT_DEF_IV, NONE, 10);
-        pokemon_stat_set(pdata, STAT_SPD_IV, NONE, 10);
-        pokemon_stat_set(pdata, STAT_SPC_IV, NONE, 10);
-
-        /* Increase ATK IV until we hit a shiny number. Note that, this only
-         * affects IVs that are randomly generated, max IV will already be set
-         * at 15 which will make it shiny.
-         */
-        while(!select_shiny_is_shiny(pdata)) {
-            pokemon_stat_set(
-                pdata, STAT_ATK_IV, NONE, pokemon_stat_get(pdata, STAT_ATK_IV, NONE) + 1);
-        }
-    }
-
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
-}
-
-void select_shiny_scene_on_enter(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    submenu_reset(pokemon_fap->submenu);
-
-    submenu_add_item(
-        pokemon_fap->submenu, "Shiny", 1, select_shiny_selected_callback, pokemon_fap);
-
-    submenu_add_item(
-        pokemon_fap->submenu, "Not Shiny", 0, select_shiny_selected_callback, pokemon_fap);
-}

+ 0 - 9
pokemon_trading/scenes/pokemon_shiny.h

@@ -1,9 +0,0 @@
-#ifndef POKEMON_SHINY_H
-#define POKEMON_SHINY_H
-
-#pragma once
-
-void select_shiny_scene_on_enter(void* context);
-bool select_shiny_is_shiny(PokemonData* pdata);
-
-#endif // POKEMON_SHINY_H

+ 0 - 31
pokemon_trading/scenes/pokemon_stats.c

@@ -1,31 +0,0 @@
-#include <gui/modules/submenu.h>
-
-#include <named_list.h>
-
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "pokemon_menu.h"
-
-static void select_stats_selected_callback(void* context, uint32_t index) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-
-    pokemon_stat_set(pokemon_fap->pdata, STAT_SEL, NONE, index);
-
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
-}
-
-void select_stats_scene_on_enter(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-    int i;
-
-    submenu_reset(pokemon_fap->submenu);
-    /* TODO: This is a magic number that this scene shouldn't need to know about */
-    for(i = 0; i < 6; i++) {
-        submenu_add_item(
-            pokemon_fap->submenu,
-            namedlist_name_get_index(pokemon_fap->pdata->stat_list, i),
-            i,
-            select_stats_selected_callback,
-            pokemon_fap);
-    }
-}

+ 0 - 8
pokemon_trading/scenes/pokemon_stats.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_STATS_H
-#define POKEMON_STATS_H
-
-#pragma once
-
-void select_stats_scene_on_enter(void* context);
-
-#endif // POKEMON_STATS_H

+ 0 - 9
pokemon_trading/scenes/pokemon_trade.c

@@ -1,9 +0,0 @@
-#include "../pokemon_app.h"
-
-void trade_scene_on_enter(void* context) {
-    PokemonFap* pokemon_fap = (PokemonFap*)context;
-    // switch to select pokemon scene
-    // Note for the future, this might make sense to setup and teardown each view
-    // at runtime rather than at the start?
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewTrade);
-}

+ 0 - 8
pokemon_trading/scenes/pokemon_trade.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_TRADE_H
-#define POKEMON_TRADE_H
-
-#pragma once
-
-void trade_scene_on_enter(void* context);
-
-#endif // POKEMON_TRADE_H

+ 0 - 8
pokemon_trading/scenes/pokemon_type.h

@@ -1,8 +0,0 @@
-#ifndef POKEMON_TYPE_H
-#define POKEMON_TYPE_H
-
-#pragma once
-
-void select_type_scene_on_enter(void* context);
-
-#endif // POKEMON_TYPE_H

+ 0 - 73
pokemon_trading/scenes/unown_form.c

@@ -1,73 +0,0 @@
-#include <stdint.h>
-#include "../pokemon_data.h"
-
-#include "unown_form.h"
-
-/* This is used to get the current IVs from the trade struct.
- * Unown form is calculated by taking the middle bytes of each nibble of IV,
- * pressing them in order to a single byte, and dividing that by 10 (rounded
- * down/floor). This will create a value from 0 to 25 that is a 1:1 mapping
- * of the English alphabet and is how Unown forms are represented.
- *
- * C integer division truncates to 0 rather than does any proper rounding.
- *
- * https://bulbapedia.bulbagarden.net/wiki/Individual_values#Unown's_letter
- */
-static uint8_t unown_ivs_get(PokemonData* pdata) {
-    furi_assert(pdata);
-    uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE);
-    uint8_t ivs_mid;
-
-    ivs_mid =
-        (((ivs & 0x6000) >> 7) | ((ivs & 0x0600) >> 5) | ((ivs & 0x0060) >> 3) |
-         ((ivs & 0x0006) >> 1));
-
-    return ivs_mid;
-}
-
-static void unown_ivs_set(PokemonData* pdata, uint8_t ivs_mid) {
-    furi_assert(pdata);
-    uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE);
-
-    /* Clear the middle bits of each nibble */
-    ivs &= ~(0x6666);
-
-    /* Set the updated ivs_mid in to those cleared bits */
-    ivs |=
-        (((ivs_mid & 0xC0) << 7) | ((ivs_mid & 0x30) << 5) | ((ivs_mid & 0x0C) << 3) |
-         ((ivs_mid & 0x03) << 1));
-    pokemon_stat_set(pdata, STAT_IV, NONE, ivs);
-}
-
-char unown_form_get(PokemonData* pdata) {
-    uint8_t form = unown_ivs_get(pdata);
-
-    /* The forumula is specifically the center two bits of each IV slapped
-     * together and floor(/10)
-     */
-    form /= 10;
-    form += 'A';
-
-    return form;
-}
-
-/* Try and get to the desired form by adding/subtracting the current IVs */
-void unown_form_set(PokemonData* pdata, char letter) {
-    uint8_t ivs = unown_ivs_get(pdata);
-    uint8_t form;
-
-    letter = toupper(letter);
-    furi_check(isalpha(letter));
-
-    while(1) {
-        form = ((ivs / 10) + 'A');
-        if(form == letter) break;
-        if(form > letter)
-            ivs--;
-        else
-            ivs++;
-    }
-
-    /* form is now the target letter, set IVs back up */
-    unown_ivs_set(pdata, ivs);
-}

+ 0 - 13
pokemon_trading/scenes/unown_form.h

@@ -1,13 +0,0 @@
-#ifndef __UNOWN_FORM_H__
-#define __UNOWN_FORM_H__
-
-#pragma once
-
-#include "../pokemon_data.h"
-
-/* Returns ascii char, or 0 if unown is not the current pokemon */
-char unown_form_get(PokemonData* pdata);
-
-void unown_form_set(PokemonData* pdata, char letter);
-
-#endif // __UNOWN_FORM_H__

+ 8 - 0
pokemon_trading/src/include/item_nl.h

@@ -0,0 +1,8 @@
+#ifndef ITEM_NL_H
+#define ITEM_NL_H
+
+#pragma once
+
+extern const NamedList item_list[];
+
+#endif // ITEM_NL_H

+ 8 - 0
pokemon_trading/src/include/move_nl.h

@@ -0,0 +1,8 @@
+#ifndef MOVE_NL_H
+#define MOVE_NL_H
+
+#pragma once
+
+extern const NamedList move_list[];
+
+#endif // MOVE_NL_H

+ 3 - 3
pokemon_trading/named_list.h → pokemon_trading/src/include/named_list.h

@@ -1,5 +1,5 @@
-#ifndef __NAMED_LIST_H__
-#define __NAMED_LIST_H__
+#ifndef NAMED_LIST_H
+#define NAMED_LIST_H
 
 #pragma once
 
@@ -43,4 +43,4 @@ const char* namedlist_name_get_index(const NamedList* list, uint32_t index);
 /* Get a pointer to the item's name from a position */
 const char* namedlist_name_get_pos(const NamedList* list, uint32_t pos);
 
-#endif //__NAMED_LIST_H__
+#endif //NAMED_LIST_H

+ 3 - 6
pokemon_trading/views/trade_patch_list.h → pokemon_trading/src/include/patch_list.h

@@ -4,13 +4,10 @@
 #pragma once
 
 #include <gui/view.h>
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
 
-struct patch_list {
-    uint8_t index;
-    struct patch_list* next;
-};
+struct patch_list;
 
 struct patch_list* plist_alloc(void);
 

+ 5 - 4
pokemon_trading/pokemon_app.h → pokemon_trading/src/include/pokemon_app.h

@@ -13,7 +13,7 @@
 #include <gui/modules/variable_item_list.h>
 #include <gblink.h>
 
-#include "pokemon_data.h"
+#include <src/include/pokemon_data.h>
 
 #define TAG "Pokemon"
 
@@ -42,11 +42,12 @@ struct pokemon_fap {
 typedef struct pokemon_fap PokemonFap;
 
 typedef enum {
-    AppViewMainMenu,
-    AppViewOpts, // Generic view ID meant for module re-use
+    AppViewSubmenu,
+    AppViewTextInput,
+    AppViewVariableItem,
+    AppViewDialogEx,
     AppViewSelectPokemon,
     AppViewTrade,
-    AppViewExitConfirm,
 } AppView;
 
 #endif /* POKEMON_APP_H */

+ 54 - 0
pokemon_trading/src/include/pokemon_attribute.h

@@ -0,0 +1,54 @@
+#ifndef POKEMON_ATTRIBUTE_H
+#define POKEMON_ATTRIBUTE_H
+
+#pragma once
+
+#include <src/include/pokemon_data.h>
+
+typedef enum {
+    GENDER_MALE,
+    GENDER_FEMALE,
+} Gender;
+
+typedef enum {
+    GENDER_F0 = 0x00,
+    GENDER_F12_5 = 0x1F,
+    GENDER_F25 = 0x3F,
+    GENDER_F50 = 0x7F,
+    GENDER_F75 = 0xBF,
+    GENDER_F100 = 0xFE,
+    GENDER_UNKNOWN = 0xFF,
+} GenderRatio;
+
+/* The gender ratio is a bit value, and if the ATK_IV is less than or equal to
+ * the gender ratio, the gender is female.
+ *
+ * A ratio of 0xff means gender is unknown.
+ * A ratio of 0x00 is annoyingly special. It either means that pokemon can be
+ *   male only -OR- there is a very small chance the pokemon is female. The
+ *   male only pokemon need to be specifically checked for.
+ */
+
+const char* pokemon_gender_is_static(PokemonData* pdata, uint8_t ratio);
+
+/* This will return a pointer to a string of the pokemon's current gender */
+const char* pokemon_gender_get(PokemonData* pdata);
+
+void pokemon_gender_set(PokemonData* pdata, Gender gender);
+
+const char* pokerus_get_status_str(PokemonData* pdata);
+
+void pokerus_set_strain(PokemonData* pdata, uint8_t strain);
+
+void pokerus_set_days(PokemonData *pdata, uint8_t days);
+
+bool pokemon_is_shiny(PokemonData* pdata);
+
+void pokemon_set_shiny(PokemonData *pdata, bool shiny);
+
+/* Returns ascii char, or 0 if unown is not the current pokemon */
+char unown_form_get(PokemonData* pdata);
+
+void unown_form_set(PokemonData* pdata, char letter);
+
+#endif // POKEMON_ATTRIBUTE_H

+ 0 - 0
pokemon_trading/pokemon_char_encode.h → pokemon_trading/src/include/pokemon_char_encode.h


+ 4 - 4
pokemon_trading/pokemon_data.h → pokemon_trading/src/include/pokemon_data.h

@@ -12,10 +12,10 @@
 #include <math.h>
 #include <stdint.h>
 
-#include <named_list.h>
-#include <stat_nl.h>
-#include <pokemon_table.h>
-#include "stats.h"
+#include <src/include/named_list.h>
+#include <src/include/stat_nl.h>
+#include <src/include/pokemon_table.h>
+#include <src/include/stats.h>
 
 /* Generation defines */
 #define GEN_I 0x01

+ 4 - 14
pokemon_trading/pokemon_table.h → pokemon_trading/src/include/pokemon_table.h

@@ -1,9 +1,9 @@
-#ifndef __POKEMON_TABLE_H__
-#define __POKEMON_TABLE_H__
+#ifndef POKEMON_TABLE_H
+#define POKEMON_TABLE_H
 
 #include <stdint.h>
 
-#include "stats.h"
+#include <src/include/stats.h>
 
 typedef enum {
     GROWTH_MEDIUM_FAST = 0,
@@ -12,16 +12,6 @@ typedef enum {
     GROWTH_SLOW = 5,
 } Growth;
 
-typedef enum {
-    GENDER_F0 = 0x00,
-    GENDER_F12_5 = 0x1F,
-    GENDER_F25 = 0x3F,
-    GENDER_F50 = 0x7F,
-    GENDER_F75 = 0xBF,
-    GENDER_F100 = 0xFE,
-    GENDER_UNKNOWN = 0xFF,
-} Gender;
-
 typedef struct pokemon_data_table PokemonTable;
 
 int table_pokemon_pos_get(const PokemonTable* table, uint8_t index);
@@ -30,4 +20,4 @@ uint8_t
 const char* table_stat_name_get(const PokemonTable* table, int num);
 const PokemonTable* table_pointer_get();
 
-#endif // __POKEMON_TABLE_H__
+#endif // POKEMON_TABLE_H

+ 3 - 3
pokemon_trading/stat_nl.h → pokemon_trading/src/include/stat_nl.h

@@ -1,5 +1,5 @@
-#ifndef __STAT_NL_H__
-#define __STAT_NL_H__
+#ifndef STAT_NL_H
+#define STAT_NL_H
 
 #pragma once
 
@@ -14,4 +14,4 @@ typedef enum {
     MAXIV_MAXEV,
 } EvIv;
 
-#endif // __STAT_NL_H__
+#endif // STAT_NL_H

+ 3 - 3
pokemon_trading/stats.h → pokemon_trading/src/include/stats.h

@@ -1,5 +1,5 @@
-#ifndef __STATS_H__
-#define __STATS_H__
+#ifndef STATS_H
+#define STATS_H
 
 #pragma once
 
@@ -101,4 +101,4 @@ typedef enum {
     NONE = 0, // Just a filler value
 } DataStatSub;
 
-#endif // __STATS_H__
+#endif // STATS_H

+ 8 - 0
pokemon_trading/src/include/type_nl.h

@@ -0,0 +1,8 @@
+#ifndef TYPE_NL_H
+#define TYPE_NL_H
+
+#pragma once
+
+extern const NamedList type_list[];
+
+#endif // TYPE_NL_H

+ 2 - 2
pokemon_trading/item_nl.c → pokemon_trading/src/item_nl.c

@@ -1,5 +1,5 @@
-#include <named_list.h>
-#include <pokemon_data.h>
+#include <src/include/named_list.h>
+#include <src/include/pokemon_data.h>
 
 const NamedList item_list[] = {
     {"No Item", 0x00, GEN_II},

+ 0 - 0
pokemon_trading/missingno_i.h → pokemon_trading/src/missingno_i.h


+ 2 - 2
pokemon_trading/move_nl.c → pokemon_trading/src/move_nl.c

@@ -1,5 +1,5 @@
-#include <named_list.h>
-#include <pokemon_data.h>
+#include <src/include/named_list.h>
+#include <src/include/pokemon_data.h>
 
 const NamedList move_list[] = {
     {"No Move", 0x00, (GEN_I | GEN_II)},

+ 1 - 1
pokemon_trading/named_list.c → pokemon_trading/src/named_list.c

@@ -1,7 +1,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <named_list.h>
+#include <src/include/named_list.h>
 
 /* Get number of elements in a list
  * This is not very efficient as-is since it has to walk the whole list.

+ 6 - 2
pokemon_trading/views/trade_patch_list.c → pokemon_trading/src/patch_list.c

@@ -1,5 +1,9 @@
-#include "../pokemon_app.h"
-#include "trade_patch_list.h"
+#include <src/include/pokemon_app.h>
+
+struct patch_list {
+    uint8_t index;
+    struct patch_list* next;
+};
 
 struct patch_list* plist_alloc(void) {
     struct patch_list* plist = NULL;

+ 124 - 0
pokemon_trading/src/pokemon_app.c

@@ -0,0 +1,124 @@
+#include <furi_hal_light.h>
+#include <pokemon_icons.h>
+#include <expansion/expansion.h>
+
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+#include <src/views/trade.h>
+#include <src/views/select_pokemon.h>
+#include <src/include/pokemon_char_encode.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+bool pokemon_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+
+    return scene_manager_handle_custom_event(pokemon_fap->scene_manager, event);
+}
+
+bool pokemon_back_event_callback(void* context) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    return scene_manager_handle_back_event(pokemon_fap->scene_manager);
+}
+
+
+PokemonFap* pokemon_alloc() {
+    PokemonFap* pokemon_fap = (PokemonFap*)malloc(sizeof(PokemonFap));
+    ViewDispatcher* view_dispatcher = NULL;
+
+    // View dispatcher
+    view_dispatcher = view_dispatcher_alloc();
+    pokemon_fap->view_dispatcher = view_dispatcher;
+
+    view_dispatcher_set_event_callback_context(view_dispatcher, pokemon_fap);
+    view_dispatcher_set_custom_event_callback(view_dispatcher, pokemon_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(view_dispatcher, pokemon_back_event_callback);
+    view_dispatcher_attach_to_gui(
+        view_dispatcher,
+        (Gui*)furi_record_open(RECORD_GUI),
+        ViewDispatcherTypeFullscreen);
+
+    // Set up pinout defaults
+    memcpy(&pokemon_fap->pins, &common_pinouts[PINOUT_ORIGINAL], sizeof(struct gblink_pins));
+
+    // Text input
+    pokemon_fap->text_input = text_input_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewTextInput, text_input_get_view(pokemon_fap->text_input));
+
+    // Submenu
+    pokemon_fap->submenu = submenu_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewSubmenu, submenu_get_view(pokemon_fap->submenu));
+
+    // Variable Item List
+    pokemon_fap->variable_item_list = variable_item_list_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewVariableItem, variable_item_list_get_view(pokemon_fap->variable_item_list));
+
+    // DialogEx
+    pokemon_fap->dialog_ex = dialog_ex_alloc();
+    view_dispatcher_add_view(
+        view_dispatcher, AppViewDialogEx, dialog_ex_get_view(pokemon_fap->dialog_ex));
+
+    // Scene manager
+    pokemon_fap->scene_manager = scene_manager_alloc(&pokemon_scene_handlers, pokemon_fap);
+    scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneMainMenu);
+
+    return pokemon_fap;
+}
+
+void free_app(PokemonFap* pokemon_fap) {
+    furi_assert(pokemon_fap);
+
+    // Submenu
+    submenu_free(pokemon_fap->submenu);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+
+    text_input_free(pokemon_fap->text_input);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewTextInput);
+
+    variable_item_list_free(pokemon_fap->variable_item_list);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
+
+    dialog_ex_free(pokemon_fap->dialog_ex);
+    view_dispatcher_remove_view(pokemon_fap->view_dispatcher, AppViewDialogEx);
+
+    view_dispatcher_free(pokemon_fap->view_dispatcher);
+
+    // Free scenes
+    scene_manager_free(pokemon_fap->scene_manager);
+
+    // Close records
+    furi_record_close(RECORD_GUI);
+
+    // Free rest
+    free(pokemon_fap);
+    pokemon_fap = NULL;
+}
+
+int32_t pokemon_app(void* p) {
+    UNUSED(p);
+
+    Expansion* expansion = furi_record_open(RECORD_EXPANSION);
+    expansion_disable(expansion);
+
+    PokemonFap* pokemon_fap = pokemon_alloc();
+
+    furi_hal_light_set(LightRed, 0x00);
+    furi_hal_light_set(LightGreen, 0x00);
+    furi_hal_light_set(LightBlue, 0x00);
+
+    //switch view and run dispatcher
+    view_dispatcher_run(pokemon_fap->view_dispatcher);
+
+    // Free resources
+    free_app(pokemon_fap);
+
+    expansion_enable(expansion);
+    furi_record_close(RECORD_EXPANSION);
+
+    return 0;
+}

+ 265 - 0
pokemon_trading/src/pokemon_attribute.c

@@ -0,0 +1,265 @@
+#include <stdint.h>
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+#include <src/include/pokemon_attribute.h>
+
+
+static const char* gender_str[] = {
+    "Unknown",
+    "Female",
+    "Male",
+};
+
+/* This returns a string pointer if the gender is static, NULL if it is not and
+ * the gender needs to be calculated.
+ */
+const char* pokemon_gender_is_static(PokemonData* pdata, uint8_t ratio) {
+    switch(ratio) {
+    case 0xFF:
+        return gender_str[0];
+    case 0xFE:
+        return gender_str[1];
+    case 0x00:
+        if(pokemon_stat_get(pdata, STAT_NUM, NONE) != 0xEB) { // Tyrogue can be either gender
+            return gender_str[2];
+        }
+        break;
+    default:
+        break;
+    }
+
+    return NULL;
+}
+
+const char* pokemon_gender_get(PokemonData* pdata) {
+    uint8_t ratio = table_stat_base_get(
+        pdata->pokemon_table,
+        pokemon_stat_get(pdata, STAT_NUM, NONE),
+        STAT_BASE_GENDER_RATIO,
+        NONE);
+    uint8_t atk_iv;
+    const char* rc;
+
+    rc = pokemon_gender_is_static(pdata, ratio);
+    if(rc) return rc;
+
+    /* Falling through here means now we need to calculate the gender from
+     * its ratio and ATK_IV.
+     */
+    atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
+    if(atk_iv * 17 <= ratio)
+        return gender_str[1];
+    else
+        return gender_str[2];
+}
+
+void pokemon_gender_set(PokemonData* pdata, Gender gender) {
+
+    uint8_t ratio = table_stat_base_get(
+        pdata->pokemon_table,
+        pokemon_stat_get(pdata, STAT_NUM, NONE),
+        STAT_BASE_GENDER_RATIO,
+        NONE);
+    uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
+
+    /* If we need to make the pokemon a male, increase atk IV until it exceeds
+     * the gender ratio.
+     *
+     * Note that, there is no checking here for impossible situations as the
+     * scene enter function will immediately quit if its not possible to change
+     * the gender (the extremes of gender_ratio value).
+     *
+     * The check for gender is a percentage, if ATK_IV*(255/15) <= the ratio,
+     * then the pokemon is a female. The gender ratio values end up being:
+     * DEF GENDER_F0      EQU   0 percent
+     * DEF GENDER_F12_5   EQU  12 percent + 1
+     * DEF GENDER_F25     EQU  25 percent
+     * DEF GENDER_F50     EQU  50 percent
+     * DEF GENDER_F75     EQU  75 percent
+     * DEF GENDER_F100    EQU 100 percent - 1
+     * Where percent is (255/100)
+     */
+    if(gender == GENDER_MALE) {
+        while((atk_iv * 17) <= ratio) atk_iv++;
+    } else {
+        while((atk_iv * 17) > ratio) atk_iv--;
+    }
+
+    pokemon_stat_set(pdata, STAT_ATK_IV, NONE, atk_iv);
+}
+
+static const char* pokerus_states[] = {
+    "Clean",
+    "Infected",
+    "Cured",
+    "",
+};
+
+const char* pokerus_get_status_str(PokemonData* pdata) {
+    uint8_t pokerus;
+
+    pokerus = pokemon_stat_get(pdata, STAT_POKERUS, NONE);
+
+    if(pokerus == 0x00)
+        return pokerus_states[0];
+
+    if((pokerus & 0x0f) != 0x00)
+        return pokerus_states[1];
+
+    return pokerus_states[2];
+}
+
+void pokerus_set_strain(PokemonData* pdata, uint8_t strain) {
+    uint8_t pokerus;
+
+    /* Need to read/modify/write the existing stat */
+    pokerus = pokemon_stat_get(pdata, STAT_POKERUS, NONE);
+    pokerus &= 0x0f;
+    pokerus |= (strain << 4);
+
+    if((pokerus & 0xf0) == 0x00)
+        pokerus = 0;
+
+    pokemon_stat_set(pdata, STAT_POKERUS, NONE, pokerus);
+}
+
+void pokerus_set_days(PokemonData *pdata, uint8_t days) {
+    uint8_t pokerus;
+
+    days &= 0x0f;
+
+    /* Need to read/modify/write the existing stat */
+    pokerus = pokemon_stat_get(pdata, STAT_POKERUS, NONE);
+    pokerus &= 0xf0;
+    pokerus |= days;
+    pokemon_stat_set(pdata, STAT_POKERUS, NONE, pokerus);
+}
+
+/* This just assumes gen ii for now */
+/* For a Gen II pokemon to be shiny, the following must be met:
+ * Spd, Def, and Spc must all be 10
+ * Atk must be 2, 3, 6, 7, 10, 11, 14, or 15
+ */
+bool pokemon_is_shiny(PokemonData* pdata) {
+    uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
+    uint8_t def_iv = pokemon_stat_get(pdata, STAT_DEF_IV, NONE);
+    uint8_t spd_iv = pokemon_stat_get(pdata, STAT_SPD_IV, NONE);
+    uint8_t spc_iv = pokemon_stat_get(pdata, STAT_SPC_IV, NONE);
+    bool rc = 1;
+
+    if(spd_iv != 10) rc = 0;
+    if(def_iv != 10) rc = 0;
+    if(spc_iv != 10) rc = 0;
+    switch(atk_iv) {
+    case 0:
+    case 1:
+    case 4:
+    case 5:
+    case 8:
+    case 9:
+    case 12:
+    case 13:
+        rc = 0;
+        break;
+    default:
+        break;
+    }
+
+    return rc;
+}
+
+void pokemon_set_shiny(PokemonData* pdata, bool shiny) {
+
+    if(!shiny) {
+        do {
+            /* First, reset the IV to the selected stat */
+            pokemon_stat_set(pdata, STAT_SEL, NONE, pokemon_stat_get(pdata, STAT_SEL, NONE));
+
+	    /* XXX: This may not be right? */
+            /* Next, ensure the current IVs wouldn't make the pokemon shiny */
+        } while(pokemon_is_shiny(pdata));
+    } else {
+        /* Set Def, Spd, Spc to 10 */
+        pokemon_stat_set(pdata, STAT_DEF_IV, NONE, 10);
+        pokemon_stat_set(pdata, STAT_SPD_IV, NONE, 10);
+        pokemon_stat_set(pdata, STAT_SPC_IV, NONE, 10);
+
+        /* Increase ATK IV until we hit a shiny number. Note that, this only
+         * affects IVs that are randomly generated, max IV will already be set
+         * at 15 which will make it shiny.
+         */
+        while(!pokemon_is_shiny(pdata)) {
+            pokemon_stat_set(
+                pdata, STAT_ATK_IV, NONE, pokemon_stat_get(pdata, STAT_ATK_IV, NONE) + 1);
+        }
+    }
+}
+
+/* This is used to get the current IVs from the trade struct.
+ * Unown form is calculated by taking the middle bytes of each nibble of IV,
+ * pressing them in order to a single byte, and dividing that by 10 (rounded
+ * down/floor). This will create a value from 0 to 25 that is a 1:1 mapping
+ * of the English alphabet and is how Unown forms are represented.
+ *
+ * C integer division truncates to 0 rather than does any proper rounding.
+ *
+ * https://bulbapedia.bulbagarden.net/wiki/Individual_values#Unown's_letter
+ */
+static uint8_t unown_ivs_get(PokemonData* pdata) {
+    furi_assert(pdata);
+    uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE);
+    uint8_t ivs_mid;
+
+    ivs_mid =
+        (((ivs & 0x6000) >> 7) | ((ivs & 0x0600) >> 5) | ((ivs & 0x0060) >> 3) |
+         ((ivs & 0x0006) >> 1));
+
+    return ivs_mid;
+}
+
+static void unown_ivs_set(PokemonData* pdata, uint8_t ivs_mid) {
+    furi_assert(pdata);
+    uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE);
+
+    /* Clear the middle bits of each nibble */
+    ivs &= ~(0x6666);
+
+    /* Set the updated ivs_mid in to those cleared bits */
+    ivs |=
+        (((ivs_mid & 0xC0) << 7) | ((ivs_mid & 0x30) << 5) | ((ivs_mid & 0x0C) << 3) |
+         ((ivs_mid & 0x03) << 1));
+    pokemon_stat_set(pdata, STAT_IV, NONE, ivs);
+}
+
+char unown_form_get(PokemonData* pdata) {
+    uint8_t form = unown_ivs_get(pdata);
+
+    /* The forumula is specifically the center two bits of each IV slapped
+     * together and floor(/10)
+     */
+    form /= 10;
+    form += 'A';
+
+    return form;
+}
+
+/* Try and get to the desired form by adding/subtracting the current IVs */
+void unown_form_set(PokemonData* pdata, char letter) {
+    uint8_t ivs = unown_ivs_get(pdata);
+    uint8_t form;
+
+    letter = toupper(letter);
+    furi_check(isalpha(letter));
+
+    while(1) {
+        form = ((ivs / 10) + 'A');
+        if(form == letter) break;
+        if(form > letter)
+            ivs--;
+        else
+            ivs++;
+    }
+
+    /* form is now the target letter, set IVs back up */
+    unown_ivs_set(pdata, ivs);
+}

+ 1 - 1
pokemon_trading/pokemon_char_encode.c → pokemon_trading/src/pokemon_char_encode.c

@@ -1,7 +1,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
-#include "pokemon_char_encode.h"
+#include <src/include/pokemon_char_encode.h>
 
 char pokemon_char_to_encoded(int byte) {
     switch(byte) {

+ 11 - 11
pokemon_trading/pokemon_data.c → pokemon_trading/src/pokemon_data.c

@@ -1,21 +1,21 @@
 #include <pokemon_icons.h>
+#include "pokemon_data_i.h"
 
 #include <storage/storage.h>
 
-#include "pokemon_data.h"
-#include "pokemon_data_i.h"
-#include "pokemon_app.h"
-#include "pokemon_char_encode.h"
+#include <src/include/pokemon_data.h>
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_char_encode.h>
 
-#include "pokemon_table.h"
+#include <src/include/pokemon_table.h>
 
-#include <named_list.h>
-#include <item_nl.h>
-#include <stat_nl.h>
-#include <type_nl.h>
-#include <move_nl.h>
+#include <src/include/named_list.h>
+#include <src/include/item_nl.h>
+#include <src/include/stat_nl.h>
+#include <src/include/type_nl.h>
+#include <src/include/move_nl.h>
 
-#include <missingno_i.h>
+#include <src/missingno_i.h>
 
 #define RECALC_NONE 0x00
 #define RECALC_EXP 0x01

+ 3 - 3
pokemon_trading/pokemon_data_i.h → pokemon_trading/src/pokemon_data_i.h

@@ -1,10 +1,10 @@
 #ifndef __POKEMON_DATA_I_H__
 #define __POKEMON_DATA_I_H__
 
-#include "pokemon_data.h"
+#include <src/include/pokemon_data.h>
 
-//#include "pokemon_app.h"
-//#include "pokemon_char_encode.h"
+//#include <src/pokemon_app.h>
+//#include <src/include/pokemon_char_encode.h>
 
 static void pokemon_stat_ev_calc(PokemonData* pdata, EvIv val);
 static void pokemon_stat_iv_calc(PokemonData* pdata, EvIv val);

+ 6 - 6
pokemon_trading/pokemon_table.c → pokemon_trading/src/pokemon_table.c

@@ -1,13 +1,13 @@
 #include <stdint.h>
 
-#include <pokemon_table.h>
-#include "stats.h"
-
 #include <gui/icon.h>
-#include <pokemon_icons.h>
-
 #include <furi.h>
 
+#include <pokemon_icons.h>
+#include <src/include/pokemon_attribute.h>
+#include <src/include/pokemon_table.h>
+#include <src/include/stats.h>
+
 /* NOTE: It seems like gen ii index is national pokedex order? */
 /* Gen i and Gen ii are _almost_ the same with all stats. The big difference
  * is that while most gen i pokemon's spc matches the same gen ii spc_atk,
@@ -27,7 +27,7 @@ struct __attribute__((__packed__)) pokemon_data_table {
     const uint8_t type[2];
     const uint8_t move[4];
     const Growth growth;
-    const Gender gender_ratio;
+    const GenderRatio gender_ratio;
 };
 
 int table_pokemon_pos_get(const PokemonTable* table, uint8_t index) {

+ 51 - 0
pokemon_trading/src/scenes/include/pokemon_scene.h

@@ -0,0 +1,51 @@
+#ifndef POKEMON_SCENE_H
+#define POKEMON_SCENE_H
+
+#pragma once
+
+#include <gui/scene_manager.h>
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) PokemonScene##id,
+typedef enum {
+#include "pokemon_scene_config.h"
+    PokemonSceneNum,
+    /* Magic number to send on an event to search through scene history and
+     * change to a previous scene.
+     */
+    PokemonSceneSearch = (1 << 30),
+    /* Magic number to send on an event to trigger going back a scene */
+    PokemonSceneBack = (1 << 31),
+} PokemonScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers pokemon_scene_handlers;
+
+/* Disable redundant declarations for this.
+ * Normally not something we would want, however, this codebase does reuse
+ * functions (using different scene IDs) to handle what would otherwise be
+ * the same (or very similar) code. e.g. OT Name, nickname, and unown form use
+ * the same name select scene with a different ID. Similar for OT ID and level.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "pokemon_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_event handlers declaration
+#define ADD_SCENE(prefix, name, id) \
+    bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
+#include "pokemon_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
+#include "pokemon_scene_config.h"
+#undef ADD_SCENE
+
+#pragma GCC diagnostic pop
+
+#endif // POKEMON_SCENE_H

+ 23 - 0
pokemon_trading/src/scenes/include/pokemon_scene_config.h

@@ -0,0 +1,23 @@
+ADD_SCENE(pokemon,	main_menu,		MainMenu)
+ADD_SCENE(pokemon,	gen,			GenITrade)
+ADD_SCENE(pokemon,	gen,			GenIITrade)
+ADD_SCENE(pokemon,	select_pokemon,		Select)
+ADD_SCENE(pokemon,	select_name,		Nickname)
+ADD_SCENE(pokemon,	select_number,		Level)
+ADD_SCENE(pokemon,	select_move,		Move)
+ADD_SCENE(pokemon,	select_move_index,	MoveIndex)
+ADD_SCENE(pokemon,	select_move_set,	MoveSet)
+ADD_SCENE(pokemon,	select_item,		Item)
+ADD_SCENE(pokemon,	select_item_set,	ItemSet)
+ADD_SCENE(pokemon,	select_type,		Type)
+ADD_SCENE(pokemon,	select_stats,		Stats)
+ADD_SCENE(pokemon,	select_shiny,		Shiny)
+ADD_SCENE(pokemon,	select_gender,		Gender)
+ADD_SCENE(pokemon,	select_pokerus,		Pokerus)
+ADD_SCENE(pokemon,	select_name,		UnownForm)
+ADD_SCENE(pokemon,	select_number,		OTID)
+ADD_SCENE(pokemon,	select_name,		OTName)
+ADD_SCENE(pokemon,	trade,			Trade)
+ADD_SCENE(pokemon,	select_pins,		Pins)
+ADD_SCENE(pokemon,	exit_confirm,		ExitConfirm)
+ADD_SCENE(pokemon,	reset_confirm,		ResetConfirm)

+ 18 - 27
pokemon_trading/scenes/pokemon_exit_confirm.c → pokemon_trading/src/scenes/pokemon_exit_confirm.c

@@ -1,26 +1,21 @@
 #include <gui/modules/dialog_ex.h>
 
 #include <pokemon_icons.h>
-#include "pokemon_menu.h"
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
 
-#include "../views/select_pokemon.h"
-#include "../views/trade.h"
+#include <src/scenes/include/pokemon_scene.h>
 
-static bool pokemon_exit_confirm_back_event_callback(void* context) {
-    UNUSED(context);
-
-    return true;
-}
+#include <src/views/select_pokemon.h>
+#include <src/views/trade.h>
 
-void pokemon_exit_confirm_dialog_callback(DialogExResult result, void* context) {
+static void pokemon_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) {
     PokemonFap* pokemon_fap = context;
 
-    scene_manager_handle_custom_event(pokemon_fap->scene_manager, result);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, result);
 }
 
-void pokemon_exit_confirm_on_enter(void* context) {
+void pokemon_scene_exit_confirm_on_enter(void* context) {
     PokemonFap* pokemon_fap = context;
     DialogEx* dialog_ex = pokemon_fap->dialog_ex;
 
@@ -39,21 +34,12 @@ void pokemon_exit_confirm_on_enter(void* context) {
         AlignTop);
     dialog_ex_set_icon(dialog_ex, 44, 32, &I_surprised_pika);
     dialog_ex_set_context(dialog_ex, pokemon_fap);
-    dialog_ex_set_result_callback(dialog_ex, pokemon_exit_confirm_dialog_callback);
-
-    /* Disable the existing navigation event handler to prevent handling further
-     * back events. Going back to the main menu as well as going back to the
-     * gen menu will re-enable the proper navigation handler.
-     */
-    view_dispatcher_set_navigation_event_callback(
-        pokemon_fap->view_dispatcher, pokemon_exit_confirm_back_event_callback);
-
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewOpts, dialog_ex_get_view(pokemon_fap->dialog_ex));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    dialog_ex_set_result_callback(dialog_ex, pokemon_scene_exit_confirm_dialog_callback);
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewDialogEx);
 }
 
-bool pokemon_exit_confirm_on_event(void* context, SceneManagerEvent event) {
+bool pokemon_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
     PokemonFap* pokemon_fap = context;
     bool consumed = false;
 
@@ -62,7 +48,7 @@ bool pokemon_exit_confirm_on_event(void* context, SceneManagerEvent event) {
             consumed = scene_manager_previous_scene(pokemon_fap->scene_manager);
         } else if(event.event == DialogExResultLeft) {
             consumed = scene_manager_search_and_switch_to_previous_scene(
-                pokemon_fap->scene_manager, MainMenuScene);
+                pokemon_fap->scene_manager, PokemonSceneMainMenu);
             /* NOTE: The above should never fail */
             furi_check(consumed);
 
@@ -88,3 +74,8 @@ bool pokemon_exit_confirm_on_event(void* context, SceneManagerEvent event) {
 
     return consumed;
 }
+
+void pokemon_scene_exit_confirm_on_exit(void* context) {
+    UNUSED(context);
+}
+

+ 252 - 0
pokemon_trading/src/scenes/pokemon_gen.c

@@ -0,0 +1,252 @@
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+#include <src/include/pokemon_char_encode.h>
+
+#include <src/include/named_list.h>
+
+#include <src/views/trade.h>
+#include <src/views/select_pokemon.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+#include <src/include/pokemon_attribute.h>
+
+static void scene_change_from_main_cb(void* context, uint32_t index) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    /* Set scene state to the current index so we can have that element highlighted when
+     * we return. Note that GenI scene is always used as a reference for this in this
+     * scene, whether its GenI or GenII.
+     */
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade, index);
+
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, index);
+}
+
+void pokemon_scene_gen_on_enter(void* context) {
+    char buf[32];
+    char name_buf[11]; // All name buffers are 11 bytes at most, including term
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+    PokemonData* pdata = pokemon_fap->pdata;
+    int pkmn_num;
+    uint32_t state;
+
+    // Set up trade party struct
+    if(!pdata) {
+        state = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade);
+        switch(state) {
+        case PokemonSceneGenITrade:
+            state = GEN_I;
+            break;
+        case PokemonSceneGenIITrade:
+            state = GEN_II;
+            break;
+        default:
+            state = 0;
+            break;
+        }
+        pokemon_fap->pdata = pokemon_data_alloc(state);
+	pdata = pokemon_fap->pdata;
+
+        /* Clear the scene state as this is the first entry in to this scene
+	 * we definitely want to be completely reset.
+	 */
+        scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade, 0);
+
+        /* Allocate select and trade views */
+        /* Allocates its own view and adds it to the main view_dispatcher */
+        pokemon_fap->select = select_pokemon_alloc(
+            pdata,
+            pokemon_fap->view_dispatcher,
+            AppViewSelectPokemon);
+
+        // Trade View
+        /* Allocates its own view and adds it to the main view_dispatcher */
+        pokemon_fap->trade = trade_alloc(
+            pdata, &pokemon_fap->pins, pokemon_fap->view_dispatcher, AppViewTrade);
+    }
+
+    pkmn_num = pokemon_stat_get(pdata, STAT_NUM, NONE);
+
+    /* Clear the scene state of the Move scene since that is used to set the
+     * highlighted menu item.
+     * This could be done in move, but move would need its own custom exit handler
+     * which is fine but would just waste a few more bytes compared to us handling
+     * it here.
+     */
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMove, 0);
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet, 0);
+
+    submenu_reset(pokemon_fap->submenu);
+
+    snprintf(
+        buf,
+        sizeof(buf),
+        "Pokemon:   %s",
+        table_stat_name_get(pdata->pokemon_table, pkmn_num));
+    submenu_add_item(
+        pokemon_fap->submenu, buf, PokemonSceneSelect, scene_change_from_main_cb, pokemon_fap);
+
+    pokemon_name_get(pdata, STAT_NICKNAME, name_buf, sizeof(name_buf));
+    snprintf(buf, sizeof(buf), "Nickname:  %s", name_buf);
+    submenu_add_item(
+        pokemon_fap->submenu, buf, PokemonSceneNickname, scene_change_from_main_cb, pokemon_fap);
+
+    snprintf(
+        buf,
+        sizeof(buf),
+        "Level:           %d",
+        pokemon_stat_get(pdata, STAT_LEVEL, NONE));
+    submenu_add_item(
+        pokemon_fap->submenu, buf, PokemonSceneLevel, scene_change_from_main_cb, pokemon_fap);
+
+    if(pdata->gen == GEN_II) {
+        snprintf(
+            buf,
+            sizeof(buf),
+            "Held Item:   %s",
+            namedlist_name_get_index(
+                pdata->item_list,
+                pokemon_stat_get(pdata, STAT_HELD_ITEM, NONE)));
+        submenu_add_item(
+            pokemon_fap->submenu, buf, PokemonSceneItem, scene_change_from_main_cb, pokemon_fap);
+    }
+
+    submenu_add_item(
+        pokemon_fap->submenu,
+        "Select Moves",
+        PokemonSceneMove,
+        scene_change_from_main_cb,
+        pokemon_fap);
+
+    if(pdata->gen == GEN_I) {
+        submenu_add_item(
+            pokemon_fap->submenu,
+            "Select Types",
+            PokemonSceneType,
+            scene_change_from_main_cb,
+            pokemon_fap);
+    }
+
+    submenu_add_item(
+        pokemon_fap->submenu,
+        namedlist_name_get_index(
+            pdata->stat_list, pokemon_stat_get(pdata, STAT_SEL, NONE)),
+        PokemonSceneStats,
+        scene_change_from_main_cb,
+        pokemon_fap);
+
+    if(pdata->gen == GEN_II) {
+        snprintf(
+            buf,
+            sizeof(buf),
+            "Shiny:             %s",
+            pokemon_is_shiny(pdata) ? "Yes" : "No");
+        submenu_add_item(
+            pokemon_fap->submenu, buf, PokemonSceneShiny, scene_change_from_main_cb, pokemon_fap);
+
+        snprintf(buf, sizeof(buf), "Gender:         %s", pokemon_gender_get(pdata));
+        submenu_add_item(
+            pokemon_fap->submenu, buf, PokemonSceneGender, scene_change_from_main_cb, pokemon_fap);
+
+        snprintf(buf, sizeof(buf), "Pokerus:       %s", pokerus_get_status_str(pdata));
+        submenu_add_item(
+            pokemon_fap->submenu, buf, PokemonScenePokerus, scene_change_from_main_cb, pokemon_fap);
+
+        if(pokemon_stat_get(pdata, STAT_NUM, NONE) == 0xC8) { // Unown
+            snprintf(buf, sizeof(buf), "Unown Form: %c", unown_form_get(pdata));
+            submenu_add_item(
+                pokemon_fap->submenu,
+                buf,
+                PokemonSceneUnownForm,
+                scene_change_from_main_cb,
+                pokemon_fap);
+        }
+    }
+
+    snprintf(
+        buf,
+        sizeof(buf),
+        "OT ID#:          %05d",
+        pokemon_stat_get(pdata, STAT_OT_ID, NONE));
+    submenu_add_item(
+        pokemon_fap->submenu, buf, PokemonSceneOTID, scene_change_from_main_cb, pokemon_fap);
+
+    pokemon_name_get(pdata, STAT_OT_NAME, name_buf, sizeof(name_buf));
+    snprintf(buf, sizeof(buf), "OT Name:      %s", name_buf);
+    submenu_add_item(
+        pokemon_fap->submenu, buf, PokemonSceneOTName, scene_change_from_main_cb, pokemon_fap);
+
+    submenu_add_item(
+        pokemon_fap->submenu, "Trade PKMN", PokemonSceneTrade, scene_change_from_main_cb, pokemon_fap);
+
+    if (trade_connected(pokemon_fap->trade)) {
+        submenu_add_item(pokemon_fap->submenu,
+                         "Reset Connection",
+                         PokemonSceneResetConfirm,
+                         scene_change_from_main_cb,
+                         pokemon_fap);
+    }
+
+    /* TODO: Add Save pokemon option here */
+
+    /* HACK: No matter what gen were in, we just store the scene state in PokemonSceneGenITrade */
+    submenu_set_selected_item(
+        pokemon_fap->submenu,
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade));
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+}
+
+bool pokemon_scene_gen_on_event(void* context, SceneManagerEvent event) {
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+    PokemonData* pdata = pokemon_fap->pdata;
+    uint8_t pokemon_num;
+    uint8_t gender_ratio;
+
+
+    /* If the user tries to go back from this scene to main menu, instead
+     * shift to the exit confirmation scene. That scene will handle freeing
+     * data as well as going back to the main menu.
+     */
+    if (event.type == SceneManagerEventTypeBack) {
+        scene_manager_next_scene(pokemon_fap->scene_manager, PokemonSceneExitConfirm);
+        consumed = true;
+    }
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+
+        /* Reuse of scenes to allow for using the same functions to set names */
+        switch(event.event) {
+        case PokemonSceneNickname:
+        case PokemonSceneOTName:
+        case PokemonSceneUnownForm:
+            scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneNickname, event.event);
+            break;
+        case PokemonSceneLevel:
+        case PokemonSceneOTID:
+            scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneLevel, event.event);
+            break;
+        case PokemonSceneGender:
+            pokemon_num = pokemon_stat_get(pdata, STAT_NUM, NONE);
+            gender_ratio = table_stat_base_get(pdata->pokemon_table, pokemon_num, STAT_BASE_GENDER_RATIO, NONE);
+            /* If the pokemon's gender is static (always male, always female,
+             * or unknown), then don't transition to the gender selection scene.
+             */
+            if(pokemon_gender_is_static(pdata, gender_ratio))
+                goto out;
+            break;
+        }
+
+        scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+    }
+
+out:
+    return consumed;
+}
+
+void pokemon_scene_gen_on_exit(void* context) {
+    UNUSED(context);
+}

+ 44 - 0
pokemon_trading/src/scenes/pokemon_gender.c

@@ -0,0 +1,44 @@
+#include <gui/modules/submenu.h>
+
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+#include <src/include/pokemon_attribute.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+static void select_gender_selected_callback(void* context, uint32_t index) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    pokemon_gender_set(pokemon_fap->pdata, index);
+
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
+}
+
+void pokemon_scene_select_gender_on_enter(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    submenu_reset(pokemon_fap->submenu);
+
+    submenu_add_item(
+        pokemon_fap->submenu, "Female", GENDER_FEMALE, select_gender_selected_callback, pokemon_fap);
+
+    submenu_add_item(
+        pokemon_fap->submenu, "Male", GENDER_MALE, select_gender_selected_callback, pokemon_fap);
+}
+
+bool pokemon_scene_select_gender_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_gender_on_exit(void* context) {
+    UNUSED(context);
+}

+ 62 - 13
pokemon_trading/scenes/pokemon_item.c → pokemon_trading/src/scenes/pokemon_item.c

@@ -2,15 +2,16 @@
 #include <gui/scene_manager.h>
 #include <stdio.h>
 
-#include <named_list.h>
+#include <src/include/named_list.h>
 
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "pokemon_menu.h"
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+
+#include <src/scenes/include/pokemon_scene.h>
 
 static void select_item_selected_callback(void* context, uint32_t index) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
-    uint32_t item = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectItemSetScene);
+    uint32_t item = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet);
 
     pokemon_stat_set(pokemon_fap->pdata, STAT_HELD_ITEM, item, index);
 
@@ -22,18 +23,18 @@ static void select_item_selected_callback(void* context, uint32_t index) {
             pokemon_stat_get(pokemon_fap->pdata, STAT_HELD_ITEM, item)));
 
     /* Move back to Gen menu. This assumes this submenu is only ever used in Gen II */
-    scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, GenIITradeScene);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, (PokemonSceneSearch | PokemonSceneGenIITrade));
 }
 
 static void select_item_index_callback(void* context, uint32_t index) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
     /* Move to next scene */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectItemSetScene, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, SelectItemSetScene);
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet, index);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneItemSet);
 }
 
-void select_item_scene_on_enter(void* context) {
+void pokemon_scene_select_item_on_enter(void* context) {
     furi_assert(context);
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     int i;
@@ -64,16 +65,41 @@ void select_item_scene_on_enter(void* context) {
 
     submenu_set_selected_item(
         pokemon_fap->submenu,
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectItemSetScene));
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectItemSetScene, 0);
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet));
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet, 0);
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+}
+
+bool pokemon_scene_select_item_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_item_on_exit(void* context) {
+    UNUSED(context);
 }
 
-void select_item_set_scene_on_enter(void* context) {
+void pokemon_scene_select_item_set_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     int i;
     const char* name;
     char letter =
-        (char)scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectItemSetScene);
+        (char)scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneItemSet);
 
     /* Populate submenu with all items that start with `letter` */
     /* NOTE! Start with pos of 1 in the item list since 0 should always be no item! */
@@ -92,3 +118,26 @@ void select_item_set_scene_on_enter(void* context) {
         }
     }
 }
+
+bool pokemon_scene_select_item_set_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_item_set_on_exit(void* context) {
+    UNUSED(context);
+}

+ 69 - 0
pokemon_trading/src/scenes/pokemon_menu.c

@@ -0,0 +1,69 @@
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+#include <src/include/pokemon_char_encode.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+static void scene_change_from_main_cb(void* context, uint32_t index) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    /* The same trade scene is used for both gen i and ii. Set the real index to
+     * scene's state.
+     */
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneGenITrade, index);
+
+    /* Set scene state to the current index so we can have that element highlighted when
+     * we return.
+     */
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMainMenu, index);
+
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, index);
+}
+
+void pokemon_scene_main_menu_on_enter(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    submenu_reset(pokemon_fap->submenu);
+    submenu_set_header(pokemon_fap->submenu, "Pokemon Trade Tool");
+
+    submenu_add_item(
+        pokemon_fap->submenu,
+        "Gen I    (R/B/Y non-JPN)",
+        PokemonSceneGenITrade,
+        scene_change_from_main_cb,
+        pokemon_fap);
+    submenu_add_item(
+        pokemon_fap->submenu,
+        "Gen II   (G/S/C non-JPN)",
+        PokemonSceneGenIITrade,
+        scene_change_from_main_cb,
+        pokemon_fap);
+    submenu_add_item(
+        pokemon_fap->submenu,
+        "Select EXT Pinout",
+        PokemonScenePins,
+        scene_change_from_main_cb,
+        pokemon_fap);
+
+    submenu_set_selected_item(
+        pokemon_fap->submenu,
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMainMenu));
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+}
+
+bool pokemon_scene_main_menu_on_event(void* context, SceneManagerEvent event) {
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_main_menu_on_exit(void* context) {
+    UNUSED(context);
+}

+ 90 - 18
pokemon_trading/scenes/pokemon_move.c → pokemon_trading/src/scenes/pokemon_move.c

@@ -2,15 +2,16 @@
 #include <gui/scene_manager.h>
 #include <stdio.h>
 
-#include <named_list.h>
+#include <src/include/named_list.h>
 
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "pokemon_menu.h"
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+
+#include <src/scenes/include/pokemon_scene.h>
 
 static void select_move_selected_callback(void* context, uint32_t index) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
-    uint32_t move = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveScene);
+    uint32_t move = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMove);
     uint8_t num = pokemon_stat_get(pokemon_fap->pdata, STAT_NUM, NONE);
 
     if(index == UINT32_MAX) {
@@ -30,15 +31,15 @@ static void select_move_selected_callback(void* context, uint32_t index) {
         (int)move);
 
     /* Move back to move menu */
-    scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, SelectMoveScene);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, (PokemonSceneMove | PokemonSceneSearch));
 }
 
 static void select_move_index_callback(void* context, uint32_t index) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
     /* Move to next scene */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectMoveIndexScene, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, SelectMoveSetScene);
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMoveIndex, index);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneMoveSet);
 }
 
 static void select_move_number_callback(void* context, uint32_t index) {
@@ -47,11 +48,11 @@ static void select_move_number_callback(void* context, uint32_t index) {
     /* Move to move index scene, save which move number we're selecting,
      * This doubles as the move slot we're going to write to later.
      */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectMoveScene, index);
-    scene_manager_next_scene(pokemon_fap->scene_manager, SelectMoveIndexScene);
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMove, index);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneMoveIndex);
 }
 
-void select_move_scene_on_enter(void* context) {
+void pokemon_scene_select_move_on_enter(void* context) {
     furi_assert(context);
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     char buf[64];
@@ -75,19 +76,44 @@ void select_move_scene_on_enter(void* context) {
 
     submenu_set_selected_item(
         pokemon_fap->submenu,
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveScene));
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMove));
 
     /* Clear cursor position on MoveIndex */
-    scene_manager_set_scene_state(pokemon_fap->scene_manager, SelectMoveIndexScene, 0);
+    scene_manager_set_scene_state(pokemon_fap->scene_manager, PokemonSceneMoveIndex, 0);
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+}
+
+bool pokemon_scene_select_move_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_move_on_exit(void* context) {
+    UNUSED(context);
 }
 
-void select_move_index_scene_on_enter(void* context) {
+void pokemon_scene_select_move_index_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     int i;
     char letter[2] = {'\0'};
     char buf[32];
     const char* name;
-    uint32_t move_num = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveScene);
+    uint32_t move_num = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMove);
 
     submenu_reset(pokemon_fap->submenu);
     /* The move list should always start with No Move, put that at the start
@@ -132,15 +158,38 @@ void select_move_index_scene_on_enter(void* context) {
 
     submenu_set_selected_item(
         pokemon_fap->submenu,
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveIndexScene));
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMoveIndex));
 }
 
-void select_move_set_scene_on_enter(void* context) {
+bool pokemon_scene_select_move_index_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_move_index_on_exit(void* context) {
+    UNUSED(context);
+}
+
+void pokemon_scene_select_move_set_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     int i;
     const char* name;
     char letter =
-        (char)scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectMoveIndexScene);
+        (char)scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneMoveIndex);
 
     /* Populate submenu with all moves that start with `letter` */
     /* NOTE! Start with index of 1 in the move list since 0 should always be no move! */
@@ -159,3 +208,26 @@ void select_move_set_scene_on_enter(void* context) {
         };
     }
 }
+
+bool pokemon_scene_select_move_set_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom) {
+        if (event.event & PokemonSceneBack)
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+        else if (event.event & PokemonSceneSearch)
+            scene_manager_search_and_switch_to_previous_scene(pokemon_fap->scene_manager, (event.event & ~PokemonSceneSearch));
+        else
+            scene_manager_next_scene(pokemon_fap->scene_manager, event.event);
+
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_move_set_on_exit(void* context) {
+    UNUSED(context);
+}

+ 38 - 21
pokemon_trading/scenes/pokemon_name_input.c → pokemon_trading/src/scenes/pokemon_name_input.c

@@ -4,11 +4,12 @@
 #include <gui/view_dispatcher.h>
 #include <stdlib.h>
 
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "../pokemon_char_encode.h"
-#include "pokemon_menu.h"
-#include "unown_form.h"
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+#include <src/include/pokemon_char_encode.h>
+#include <src/include/pokemon_attribute.h>
+
+#include <src/scenes/include/pokemon_scene.h>
 
 static char name_buf[LEN_NAME_BUF];
 
@@ -24,11 +25,11 @@ static char name_buf[LEN_NAME_BUF];
 static bool select_name_input_validator(const char* text, FuriString* error, void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     uint32_t state =
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectNicknameScene);
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneNickname);
     unsigned int i;
 
     /* A blank field for the pokemon nickname means revert to default name */
-    if(text[0] == '\0' && state == SelectNicknameScene) {
+    if(text[0] == '\0' && state == PokemonSceneNickname) {
         /* Get the pokemon's name and populate our buffer with it */
         /* TODO: Nidoran M/F are still a problem with this. */
         pokemon_default_nickname_set(name_buf, pokemon_fap->pdata, sizeof(name_buf));
@@ -44,7 +45,7 @@ static bool select_name_input_validator(const char* text, FuriString* error, voi
     }
 
     /* Check for Unown setting is a character */
-    if(state == SelectUnownFormScene) {
+    if(state == PokemonSceneUnownForm) {
         if(!isalpha((int)text[0])) {
             furi_string_printf(error, "Form must\nbe a single\nletter!");
             return false;
@@ -52,13 +53,13 @@ static bool select_name_input_validator(const char* text, FuriString* error, voi
     }
 
     switch(state) {
-    case SelectNicknameScene:
+    case PokemonSceneNickname:
         pokemon_name_set(pokemon_fap->pdata, STAT_NICKNAME, (char*)text);
         break;
-    case SelectOTNameScene:
+    case PokemonSceneOTName:
         pokemon_name_set(pokemon_fap->pdata, STAT_OT_NAME, (char*)text);
         break;
-    case SelectUnownFormScene:
+    case PokemonSceneUnownForm:
         unown_form_set(pokemon_fap->pdata, text[0]);
         break;
     default:
@@ -72,29 +73,29 @@ static bool select_name_input_validator(const char* text, FuriString* error, voi
 static void select_name_input_callback(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
 }
 
-void select_name_scene_on_enter(void* context) {
+void pokemon_scene_select_name_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     uint32_t state =
-        scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectNicknameScene);
+        scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneNickname);
     char* header;
     int len;
     DataStat stat;
 
     switch(state) {
-    case SelectNicknameScene:
+    case PokemonSceneNickname:
         header = "Nickname (none for default)";
         len = LEN_NICKNAME;
         stat = STAT_NICKNAME;
         break;
-    case SelectOTNameScene:
+    case PokemonSceneOTName:
         header = "Enter OT Name";
         len = LEN_OT_NAME;
         stat = STAT_OT_NAME;
         break;
-    case SelectUnownFormScene:
+    case PokemonSceneUnownForm:
         header = "Enter Unown Letter Form";
         len = 2;
         stat = STAT_OT_NAME;
@@ -104,7 +105,7 @@ void select_name_scene_on_enter(void* context) {
         break;
     }
 
-    if(state == SelectUnownFormScene) {
+    if(state == PokemonSceneUnownForm) {
         /* Put the current letter in the buffer */
         name_buf[0] = unown_form_get(pokemon_fap->pdata);
         name_buf[1] = '\0';
@@ -118,7 +119,23 @@ void select_name_scene_on_enter(void* context) {
         pokemon_fap->text_input, select_name_input_callback, pokemon_fap, name_buf, len, true);
     text_input_set_header_text(pokemon_fap->text_input, header);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewTextInput);
+}
+
+bool pokemon_scene_select_name_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_name_on_exit(void* context) {
+    UNUSED(context);
+
 }

+ 30 - 14
pokemon_trading/scenes/pokemon_number_input.c → pokemon_trading/src/scenes/pokemon_number_input.c

@@ -3,15 +3,16 @@
 #include <gui/view_dispatcher.h>
 #include <stdlib.h>
 
-#include "../pokemon_app.h"
-#include "../pokemon_data.h"
-#include "pokemon_menu.h"
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+
+#include <src/scenes/include/pokemon_scene.h>
 
 static char number_buf[LEN_NUM_BUF];
 
 static bool select_number_input_validator(const char* text, FuriString* error, void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
-    uint32_t state = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectLevelScene);
+    uint32_t state = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneLevel);
     int number;
     char* error_str;
     int min;
@@ -21,13 +22,13 @@ static bool select_number_input_validator(const char* text, FuriString* error, v
     unsigned int i;
 
     switch(state) {
-    case SelectLevelScene:
+    case PokemonSceneLevel:
         error_str = "Level must\nbe a number\nbetween\n2-100!";
         min = 2;
         max = 100;
         stat = STAT_LEVEL;
         break;
-    case SelectOTIDScene:
+    case PokemonSceneOTID:
         error_str = "OT ID must\nbe between\n0-65535!";
         min = 0;
         max = 65535;
@@ -62,23 +63,23 @@ static bool select_number_input_validator(const char* text, FuriString* error, v
 static void select_number_input_callback(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
-    scene_manager_previous_scene(pokemon_fap->scene_manager);
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
 }
 
-void select_number_scene_on_enter(void* context) {
+void pokemon_scene_select_number_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     char* header;
-    uint32_t state = scene_manager_get_scene_state(pokemon_fap->scene_manager, SelectLevelScene);
+    uint32_t state = scene_manager_get_scene_state(pokemon_fap->scene_manager, PokemonSceneLevel);
     int len;
     DataStat stat;
 
     switch(state) {
-    case SelectLevelScene:
+    case PokemonSceneLevel:
         header = "Enter level (numbers only)";
         len = LEN_LEVEL;
         stat = STAT_LEVEL;
         break;
-    case SelectOTIDScene:
+    case PokemonSceneOTID:
         header = "Enter OT ID (numbers only)";
         len = LEN_OT_ID;
         stat = STAT_OT_ID;
@@ -96,7 +97,22 @@ void select_number_scene_on_enter(void* context) {
         pokemon_fap->text_input, select_number_input_callback, pokemon_fap, number_buf, len, true);
     text_input_set_header_text(pokemon_fap->text_input, header);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher, AppViewOpts, text_input_get_view(pokemon_fap->text_input));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewTextInput);
+}
+
+bool pokemon_scene_select_number_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_number_on_exit(void* context) {
+    UNUSED(context);
 }

+ 15 - 8
pokemon_trading/scenes/pokemon_pins.c → pokemon_trading/src/scenes/pokemon_pins.c

@@ -1,8 +1,9 @@
 #include <gui/modules/variable_item_list.h>
 #include <furi.h>
 
-#include "../pokemon_app.h"
-#include "pokemon_menu.h"
+#include <src/include/pokemon_app.h>
+
+#include <src/scenes/include/pokemon_scene.h>
 
 /* This is a bit of a hack to save some space and not have to refactor this scene.
  * We re-use the name and pin from the global gpio pin definition, but need to
@@ -143,14 +144,20 @@ static void select_pins_rebuild_list(PokemonFap* pokemon_fap) {
     variable_item_set_current_value_text(builder.clk, named_pins[builder.clk_index]->name);
 }
 
-void select_pins_scene_on_enter(void* context) {
+void pokemon_scene_select_pins_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
     select_pins_rebuild_list(pokemon_fap);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher,
-        AppViewOpts,
-        variable_item_list_get_view(pokemon_fap->variable_item_list));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
+}
+
+bool pokemon_scene_select_pins_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    return false;
+}
+
+void pokemon_scene_select_pins_on_exit(void* context) {
+    UNUSED(context);
 }

+ 18 - 38
pokemon_trading/scenes/pokemon_pokerus.c → pokemon_trading/src/scenes/pokemon_pokerus.c

@@ -1,15 +1,10 @@
 #include <gui/modules/variable_item_list.h>
 #include <furi.h>
 
-#include "../pokemon_app.h"
-#include "pokemon_menu.h"
+#include <src/include/pokemon_app.h>
 
-static const char* pokerus_states[] = {
-    "Clean",
-    "Infected",
-    "Cured",
-    "",
-};
+#include <src/scenes/include/pokemon_scene.h>
+#include <src/include/pokemon_attribute.h>
 
 static const char* strains[] = {
     "None",
@@ -20,16 +15,6 @@ static const char* strains[] = {
     "",
 };
 
-const char* select_pokerus_status(PokemonFap* pokemon_fap) {
-    uint8_t pokerus;
-
-    pokerus = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE);
-
-    if(pokerus == 0x00) return pokerus_states[0];
-    if((pokerus & 0x0f) != 0x00) return pokerus_states[1];
-    return pokerus_states[2];
-}
-
 struct pokerus_itemlist {
     VariableItem* strain;
     VariableItem* days;
@@ -40,13 +25,8 @@ static void select_pokerus_rebuild_list(PokemonFap* pokemon_fap);
 
 static void select_strain_callback(VariableItem* item) {
     uint8_t index = variable_item_get_current_value_index(item);
-    uint8_t pokerus;
     PokemonFap* pokemon_fap = variable_item_get_context(item);
 
-    /* Need to read/modify/write the existing stat */
-    pokerus = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE);
-    pokerus &= 0x0f;
-
     /* Need to set the new text from the mangled index */
     variable_item_set_current_value_text(item, strains[index]);
 
@@ -57,9 +37,8 @@ static void select_strain_callback(VariableItem* item) {
         index = 0x04; // Map this back to the A strain
     else
         index--;
-    pokerus |= (index << 4);
-    if((pokerus & 0xf0) == 0x00) pokerus = 0;
-    pokemon_stat_set(pokemon_fap->pdata, STAT_POKERUS, NONE, pokerus);
+
+    pokerus_set_strain(pokemon_fap->pdata, index);
 
     select_pokerus_rebuild_list(pokemon_fap);
     variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 0);
@@ -67,14 +46,9 @@ static void select_strain_callback(VariableItem* item) {
 
 static void select_days_callback(VariableItem* item) {
     uint8_t index = variable_item_get_current_value_index(item);
-    uint8_t pokerus;
     PokemonFap* pokemon_fap = variable_item_get_context(item);
 
-    /* Need to read/modify/write the existing stat */
-    pokerus = pokemon_stat_get(pokemon_fap->pdata, STAT_POKERUS, NONE);
-    pokerus &= 0xf0;
-    pokerus |= index;
-    pokemon_stat_set(pokemon_fap->pdata, STAT_POKERUS, NONE, pokerus);
+    pokerus_set_days(pokemon_fap->pdata, index);
 
     select_pokerus_rebuild_list(pokemon_fap);
     variable_item_list_set_selected_item(pokemon_fap->variable_item_list, 1);
@@ -159,14 +133,20 @@ static void select_pokerus_rebuild_list(PokemonFap* pokemon_fap) {
     furi_string_free(daystring);
 }
 
-void select_pokerus_scene_on_enter(void* context) {
+void pokemon_scene_select_pokerus_on_enter(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
 
     select_pokerus_rebuild_list(pokemon_fap);
 
-    view_dispatcher_add_view(
-        pokemon_fap->view_dispatcher,
-        AppViewOpts,
-        variable_item_list_get_view(pokemon_fap->variable_item_list));
-    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewOpts);
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewVariableItem);
+}
+
+bool pokemon_scene_select_pokerus_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    return false;
+}
+
+void pokemon_scene_select_pokerus_on_exit(void* context) {
+    UNUSED(context);
 }

+ 30 - 0
pokemon_trading/src/scenes/pokemon_scene.c

@@ -0,0 +1,30 @@
+#include "include/pokemon_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const pokemon_on_enter_handlers[])(void*) = {
+#include "include/pokemon_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_event handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
+bool (*const pokemon_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "include/pokemon_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
+void (*const pokemon_on_exit_handlers[])(void* context) = {
+#include "include/pokemon_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers pokemon_scene_handlers = {
+    .on_enter_handlers = pokemon_on_enter_handlers,
+    .on_event_handlers = pokemon_on_event_handlers,
+    .on_exit_handlers = pokemon_on_exit_handlers,
+    .scene_num = PokemonSceneNum,
+};

+ 28 - 0
pokemon_trading/src/scenes/pokemon_select.c

@@ -0,0 +1,28 @@
+#include <src/include/pokemon_app.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+void pokemon_scene_select_pokemon_on_enter(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+    // switch to select pokemon scene
+    // Note for the future, this might make sense to setup and teardown each view
+    // at runtime rather than at the start of the whole application
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSelectPokemon);
+}
+
+bool pokemon_scene_select_pokemon_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_pokemon_on_exit(void* context) {
+    UNUSED(context);
+}

+ 43 - 0
pokemon_trading/src/scenes/pokemon_shiny.c

@@ -0,0 +1,43 @@
+#include <gui/modules/submenu.h>
+
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_attribute.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+static void select_shiny_selected_callback(void* context, uint32_t index) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    pokemon_set_shiny(pokemon_fap->pdata, (bool)index);
+
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, PokemonSceneBack);
+}
+
+void pokemon_scene_select_shiny_on_enter(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    submenu_reset(pokemon_fap->submenu);
+
+    submenu_add_item(
+        pokemon_fap->submenu, "Shiny", 1, select_shiny_selected_callback, pokemon_fap);
+
+    submenu_add_item(
+        pokemon_fap->submenu, "Not Shiny", 0, select_shiny_selected_callback, pokemon_fap);
+}
+
+bool pokemon_scene_select_shiny_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_shiny_on_exit(void* context) {
+    UNUSED(context);
+}

+ 51 - 0
pokemon_trading/src/scenes/pokemon_stats.c

@@ -0,0 +1,51 @@
+#include <gui/modules/submenu.h>
+
+#include <src/include/named_list.h>
+
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+static void select_stats_selected_callback(void* context, uint32_t index) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    pokemon_stat_set(pokemon_fap->pdata, STAT_SEL, NONE, index);
+
+    scene_manager_previous_scene(pokemon_fap->scene_manager);
+}
+
+void pokemon_scene_select_stats_on_enter(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+    int i;
+
+    submenu_reset(pokemon_fap->submenu);
+    /* TODO: This is a magic number that this scene shouldn't need to know about */
+    for(i = 0; i < 6; i++) {
+        submenu_add_item(
+            pokemon_fap->submenu,
+            namedlist_name_get_index(pokemon_fap->pdata->stat_list, i),
+            i,
+            select_stats_selected_callback,
+            pokemon_fap);
+    }
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewSubmenu);
+}
+
+bool pokemon_scene_select_stats_on_event(void* context, SceneManagerEvent event) {
+    furi_assert(context);
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if (event.type == SceneManagerEventTypeCustom && event.event & PokemonSceneBack) {
+        scene_manager_previous_scene(pokemon_fap->scene_manager);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_select_stats_on_exit(void* context) {
+    UNUSED(context);
+}

+ 21 - 0
pokemon_trading/src/scenes/pokemon_trade.c

@@ -0,0 +1,21 @@
+#include <src/include/pokemon_app.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+void pokemon_scene_trade_on_enter(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+    // switch to select pokemon scene
+    // Note for the future, this might make sense to setup and teardown each view
+    // at runtime rather than at the start?
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewTrade);
+}
+
+bool pokemon_scene_trade_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    return false;
+}
+
+void pokemon_scene_trade_on_exit(void* context) {
+    UNUSED(context);
+}

+ 65 - 0
pokemon_trading/src/scenes/pokemon_trade_reset_confirm.c

@@ -0,0 +1,65 @@
+#include <gui/modules/dialog_ex.h>
+
+#include <pokemon_icons.h>
+#include <src/include/pokemon_app.h>
+#include <src/include/pokemon_data.h>
+
+#include <src/scenes/include/pokemon_scene.h>
+
+#include <src/views/select_pokemon.h>
+#include <src/views/trade.h>
+
+static void pokemon_scene_reset_confirm_dialog_callback(DialogExResult result, void* context) {
+    PokemonFap* pokemon_fap = context;
+
+    view_dispatcher_send_custom_event(pokemon_fap->view_dispatcher, result);
+}
+
+void pokemon_scene_reset_confirm_on_enter(void* context) {
+    PokemonFap* pokemon_fap = context;
+    DialogEx* dialog_ex = pokemon_fap->dialog_ex;
+
+    // Clean view
+    dialog_ex_reset(pokemon_fap->dialog_ex);
+
+    dialog_ex_set_left_button_text(dialog_ex, "Reset");
+    dialog_ex_set_right_button_text(dialog_ex, "Back");
+    dialog_ex_set_header(dialog_ex, "Reset Trade State?", 64, 0, AlignCenter, AlignTop);
+    dialog_ex_set_text(
+        dialog_ex,
+        "Trade partner will need to\nleave and re-enter the\nTrade Center!",
+        64,
+        12,
+        AlignCenter,
+        AlignTop);
+    dialog_ex_set_context(dialog_ex, pokemon_fap);
+    dialog_ex_set_result_callback(dialog_ex, pokemon_scene_reset_confirm_dialog_callback);
+
+    view_dispatcher_switch_to_view(pokemon_fap->view_dispatcher, AppViewDialogEx);
+}
+
+bool pokemon_scene_reset_confirm_on_event(void* context, SceneManagerEvent event) {
+    PokemonFap* pokemon_fap = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        switch (event.event) {
+        case DialogExResultLeft:
+            trade_reset_connection(pokemon_fap->trade);
+        [[fallthrough]];
+        case DialogExResultRight:
+            scene_manager_previous_scene(pokemon_fap->scene_manager);
+	    consumed = true;
+            break;
+        }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void pokemon_scene_reset_confirm_on_exit(void* context) {
+    UNUSED(context);
+}
+

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä