pokemon_attribute.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. #include <stdint.h>
  2. #include <src/include/pokemon_app.h>
  3. #include <src/include/pokemon_data.h>
  4. #include <src/include/pokemon_attribute.h>
  5. static const char* gender_str[] = {
  6. "Unknown",
  7. "Female",
  8. "Male",
  9. };
  10. /* This returns a string pointer if the gender is static, NULL if it is not and
  11. * the gender needs to be calculated.
  12. */
  13. const char* pokemon_gender_is_static(PokemonData* pdata, uint8_t ratio) {
  14. switch(ratio) {
  15. case 0xFF:
  16. return gender_str[0];
  17. case 0xFE:
  18. return gender_str[1];
  19. case 0x00:
  20. if(pokemon_stat_get(pdata, STAT_NUM, NONE) != 0xEB) { // Tyrogue can be either gender
  21. return gender_str[2];
  22. }
  23. break;
  24. default:
  25. break;
  26. }
  27. return NULL;
  28. }
  29. const char* pokemon_gender_get(PokemonData* pdata) {
  30. uint8_t ratio = table_stat_base_get(
  31. pdata->pokemon_table,
  32. pokemon_stat_get(pdata, STAT_NUM, NONE),
  33. STAT_BASE_GENDER_RATIO,
  34. NONE);
  35. uint8_t atk_iv;
  36. const char* rc;
  37. rc = pokemon_gender_is_static(pdata, ratio);
  38. if(rc) return rc;
  39. /* Falling through here means now we need to calculate the gender from
  40. * its ratio and ATK_IV.
  41. */
  42. atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
  43. if(atk_iv * 17 <= ratio)
  44. return gender_str[1];
  45. else
  46. return gender_str[2];
  47. }
  48. void pokemon_gender_set(PokemonData* pdata, Gender gender) {
  49. uint8_t ratio = table_stat_base_get(
  50. pdata->pokemon_table,
  51. pokemon_stat_get(pdata, STAT_NUM, NONE),
  52. STAT_BASE_GENDER_RATIO,
  53. NONE);
  54. uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
  55. /* If we need to make the pokemon a male, increase atk IV until it exceeds
  56. * the gender ratio.
  57. *
  58. * Note that, there is no checking here for impossible situations as the
  59. * scene enter function will immediately quit if its not possible to change
  60. * the gender (the extremes of gender_ratio value).
  61. *
  62. * The check for gender is a percentage, if ATK_IV*(255/15) <= the ratio,
  63. * then the pokemon is a female. The gender ratio values end up being:
  64. * DEF GENDER_F0 EQU 0 percent
  65. * DEF GENDER_F12_5 EQU 12 percent + 1
  66. * DEF GENDER_F25 EQU 25 percent
  67. * DEF GENDER_F50 EQU 50 percent
  68. * DEF GENDER_F75 EQU 75 percent
  69. * DEF GENDER_F100 EQU 100 percent - 1
  70. * Where percent is (255/100)
  71. */
  72. if(gender == GENDER_MALE) {
  73. while((atk_iv * 17) <= ratio) atk_iv++;
  74. } else {
  75. while((atk_iv * 17) > ratio) atk_iv--;
  76. }
  77. pokemon_stat_set(pdata, STAT_ATK_IV, NONE, atk_iv);
  78. }
  79. static const char* pokerus_states[] = {
  80. "Clean",
  81. "Infected",
  82. "Cured",
  83. "",
  84. };
  85. const char* pokerus_get_status_str(PokemonData* pdata) {
  86. uint8_t pokerus;
  87. pokerus = pokemon_stat_get(pdata, STAT_POKERUS, NONE);
  88. if(pokerus == 0x00) return pokerus_states[0];
  89. if((pokerus & 0x0f) != 0x00) return pokerus_states[1];
  90. return pokerus_states[2];
  91. }
  92. void pokerus_set_strain(PokemonData* pdata, uint8_t strain) {
  93. uint8_t pokerus;
  94. /* Need to read/modify/write the existing stat */
  95. pokerus = pokemon_stat_get(pdata, STAT_POKERUS, NONE);
  96. pokerus &= 0x0f;
  97. pokerus |= (strain << 4);
  98. if((pokerus & 0xf0) == 0x00) pokerus = 0;
  99. pokemon_stat_set(pdata, STAT_POKERUS, NONE, pokerus);
  100. }
  101. void pokerus_set_days(PokemonData* pdata, uint8_t days) {
  102. uint8_t pokerus;
  103. days &= 0x0f;
  104. /* Need to read/modify/write the existing stat */
  105. pokerus = pokemon_stat_get(pdata, STAT_POKERUS, NONE);
  106. pokerus &= 0xf0;
  107. pokerus |= days;
  108. pokemon_stat_set(pdata, STAT_POKERUS, NONE, pokerus);
  109. }
  110. /* This just assumes gen ii for now */
  111. /* For a Gen II pokemon to be shiny, the following must be met:
  112. * Spd, Def, and Spc must all be 10
  113. * Atk must be 2, 3, 6, 7, 10, 11, 14, or 15
  114. */
  115. bool pokemon_is_shiny(PokemonData* pdata) {
  116. uint8_t atk_iv = pokemon_stat_get(pdata, STAT_ATK_IV, NONE);
  117. uint8_t def_iv = pokemon_stat_get(pdata, STAT_DEF_IV, NONE);
  118. uint8_t spd_iv = pokemon_stat_get(pdata, STAT_SPD_IV, NONE);
  119. uint8_t spc_iv = pokemon_stat_get(pdata, STAT_SPC_IV, NONE);
  120. bool rc = 1;
  121. if(spd_iv != 10) rc = 0;
  122. if(def_iv != 10) rc = 0;
  123. if(spc_iv != 10) rc = 0;
  124. switch(atk_iv) {
  125. case 0:
  126. case 1:
  127. case 4:
  128. case 5:
  129. case 8:
  130. case 9:
  131. case 12:
  132. case 13:
  133. rc = 0;
  134. break;
  135. default:
  136. break;
  137. }
  138. return rc;
  139. }
  140. void pokemon_set_shiny(PokemonData* pdata, bool shiny) {
  141. if(!shiny) {
  142. do {
  143. /* First, reset the IV to the selected stat */
  144. pokemon_stat_set(pdata, STAT_SEL, NONE, pokemon_stat_get(pdata, STAT_SEL, NONE));
  145. /* XXX: This may not be right? */
  146. /* Next, ensure the current IVs wouldn't make the pokemon shiny */
  147. } while(pokemon_is_shiny(pdata));
  148. } else {
  149. /* Set Def, Spd, Spc to 10 */
  150. pokemon_stat_set(pdata, STAT_DEF_IV, NONE, 10);
  151. pokemon_stat_set(pdata, STAT_SPD_IV, NONE, 10);
  152. pokemon_stat_set(pdata, STAT_SPC_IV, NONE, 10);
  153. /* Increase ATK IV until we hit a shiny number. Note that, this only
  154. * affects IVs that are randomly generated, max IV will already be set
  155. * at 15 which will make it shiny.
  156. */
  157. while(!pokemon_is_shiny(pdata)) {
  158. pokemon_stat_set(
  159. pdata, STAT_ATK_IV, NONE, pokemon_stat_get(pdata, STAT_ATK_IV, NONE) + 1);
  160. }
  161. }
  162. }
  163. /* This is used to get the current IVs from the trade struct.
  164. * Unown form is calculated by taking the middle bytes of each nibble of IV,
  165. * pressing them in order to a single byte, and dividing that by 10 (rounded
  166. * down/floor). This will create a value from 0 to 25 that is a 1:1 mapping
  167. * of the English alphabet and is how Unown forms are represented.
  168. *
  169. * C integer division truncates to 0 rather than does any proper rounding.
  170. *
  171. * https://bulbapedia.bulbagarden.net/wiki/Individual_values#Unown's_letter
  172. */
  173. static uint8_t unown_ivs_get(PokemonData* pdata) {
  174. furi_assert(pdata);
  175. uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE);
  176. uint8_t ivs_mid;
  177. ivs_mid =
  178. (((ivs & 0x6000) >> 7) | ((ivs & 0x0600) >> 5) | ((ivs & 0x0060) >> 3) |
  179. ((ivs & 0x0006) >> 1));
  180. return ivs_mid;
  181. }
  182. static void unown_ivs_set(PokemonData* pdata, uint8_t ivs_mid) {
  183. furi_assert(pdata);
  184. uint16_t ivs = pokemon_stat_get(pdata, STAT_IV, NONE);
  185. /* Clear the middle bits of each nibble */
  186. ivs &= ~(0x6666);
  187. /* Set the updated ivs_mid in to those cleared bits */
  188. ivs |=
  189. (((ivs_mid & 0xC0) << 7) | ((ivs_mid & 0x30) << 5) | ((ivs_mid & 0x0C) << 3) |
  190. ((ivs_mid & 0x03) << 1));
  191. pokemon_stat_set(pdata, STAT_IV, NONE, ivs);
  192. }
  193. char unown_form_get(PokemonData* pdata) {
  194. uint8_t form = unown_ivs_get(pdata);
  195. /* The forumula is specifically the center two bits of each IV slapped
  196. * together and floor(/10)
  197. */
  198. form /= 10;
  199. form += 'A';
  200. return form;
  201. }
  202. /* Try and get to the desired form by adding/subtracting the current IVs */
  203. void unown_form_set(PokemonData* pdata, char letter) {
  204. uint8_t ivs = unown_ivs_get(pdata);
  205. uint8_t form;
  206. letter = toupper(letter);
  207. furi_check(isalpha(letter));
  208. while(1) {
  209. form = ((ivs / 10) + 'A');
  210. if(form == letter) break;
  211. if(form > letter)
  212. ivs--;
  213. else
  214. ivs++;
  215. }
  216. /* form is now the target letter, set IVs back up */
  217. unown_ivs_set(pdata, ivs);
  218. }