Skip to content

Commit

Permalink
attribute: combine calculated attributes to single file
Browse files Browse the repository at this point in the history
Handles gender, pokerus, shiny, and unown form

Signed-off-by: Kris Bahnsen <[email protected]>
  • Loading branch information
kbembedded committed Aug 6, 2024
1 parent eafd365 commit aca6bdf
Show file tree
Hide file tree
Showing 15 changed files with 289 additions and 325 deletions.
21 changes: 18 additions & 3 deletions src/include/pokemon_gender.h → src/include/pokemon_attribute.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef POKEMON_GENDER_H
#define POKEMON_GENDER_H
#ifndef POKEMON_ATTRIBUTE_H
#define POKEMON_ATTRIBUTE_H

#pragma once

Expand Down Expand Up @@ -36,4 +36,19 @@ const char* pokemon_gender_get(PokemonData* pdata);

void pokemon_gender_set(PokemonData* pdata, Gender gender);

#endif // POKEMON_GENDER_H
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
14 changes: 0 additions & 14 deletions src/include/pokemon_pokerus.h

This file was deleted.

10 changes: 0 additions & 10 deletions src/include/pokemon_shiny.h

This file was deleted.

13 changes: 0 additions & 13 deletions src/include/unown_form.h

This file was deleted.

265 changes: 265 additions & 0 deletions src/pokemon_attribute.c
Original file line number Diff line number Diff line change
@@ -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);
}
Loading

0 comments on commit aca6bdf

Please sign in to comment.