|
|
@@ -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);
|
|
|
+}
|