Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Shiny Charm #2806

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,18 @@ struct Fusion

extern const struct Fusion *const gFusionTablePointers[NUM_SPECIES];

struct PIDParameters
{
u16 species;
bool8 shinyRerolls;
bool8 forceNature;
u8 nature;
bool8 forceGender;
u8 gender;
bool8 forceUnownLetter;
u8 unownLetter;
};

#define NUM_UNOWN_FORMS 28

#define GET_UNOWN_LETTER(personality) (( \
Expand Down Expand Up @@ -627,6 +639,7 @@ void ZeroBoxMonData(struct BoxPokemon *boxMon);
void ZeroMonData(struct Pokemon *mon);
void ZeroPlayerPartyMons(void);
void ZeroEnemyPartyMons(void);
u32 GeneratePIDMaster(struct PIDParameters parameters);
void CreateMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId);
void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId);
void CreateMonWithNature(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 nature);
Expand Down
32 changes: 17 additions & 15 deletions src/daycare.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,34 +509,36 @@ static s32 GetParentToInheritNature(struct DayCare *daycare)
static void _TriggerPendingDaycareEgg(struct DayCare *daycare)
{
s32 parent;
s32 natureTries = 0;
u32 personality;
struct PIDParameters parameters;

parameters.species = SPECIES_NONE;
parameters.shinyRerolls = TRUE;
parameters.forceNature = FALSE;
parameters.nature = 0;
parameters.forceGender = FALSE;
parameters.gender = 0;
parameters.forceUnownLetter = FALSE;
parameters.unownLetter = 0;

SeedRng2(gMain.vblankCounter2);
parent = GetParentToInheritNature(daycare);

// don't inherit nature
if (parent < 0)
{
daycare->offspringPersonality = (Random2() << 16) | ((Random() % 0xfffe) + 1);
personality = GeneratePIDMaster(parameters);
}
// inherit nature
else
{
u8 wantedNature = GetNatureFromPersonality(GetBoxMonData(&daycare->mons[parent].mon, MON_DATA_PERSONALITY, NULL));
u32 personality;
parameters.forceNature = TRUE;
parameters.nature = GetNatureFromPersonality(GetBoxMonData(&daycare->mons[parent].mon, MON_DATA_PERSONALITY, NULL));

do
{
personality = (Random2() << 16) | (Random());
if (wantedNature == GetNatureFromPersonality(personality) && personality != 0)
break; // found a personality with the same nature

natureTries++;
} while (natureTries <= 2400);

daycare->offspringPersonality = personality;
personality = GeneratePIDMaster(parameters);
}

daycare->offspringPersonality = personality;

FlagSet(FLAG_PENDING_DAYCARE_EGG);
}

Expand Down
202 changes: 153 additions & 49 deletions src/pokemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,98 @@ void ZeroEnemyPartyMons(void)
ZeroMonData(&gEnemyParty[i]);
}

static inline u32 GeneratePID(struct PIDParameters parameters)
{
return Random32();
}

static inline u32 GeneratePIDUnownLetter(struct PIDParameters parameters)
{
u32 pid;

if (parameters.forceUnownLetter)
{
do
{
pid = GeneratePID(parameters);
} while (GET_UNOWN_LETTER(pid) != parameters.unownLetter);
}
else
{
pid = GeneratePID(parameters);
}

return pid;
}

static inline u32 GeneratePIDGender(struct PIDParameters parameters)
{
u32 pid;

if (parameters.forceGender)
{
do
{
pid = GeneratePIDUnownLetter(parameters);
} while (GetGenderFromSpeciesAndPersonality(parameters.species, pid) != parameters.gender);
}
else
{
pid = GeneratePIDUnownLetter(parameters);
}

return pid;
}

static inline u32 GeneratePIDNature(struct PIDParameters parameters)
{
u32 pid;

if (parameters.forceNature)
{
do
{
pid = GeneratePIDGender(parameters);
} while (GetNatureFromPersonality(pid) != parameters.nature);
}
else
{
pid = GeneratePIDGender(parameters);
}

return pid;
}

u32 GeneratePIDMaster(struct PIDParameters parameters)
{
u32 pid;
u32 tid = gSaveBlock2Ptr->playerTrainerId[0]
| (gSaveBlock2Ptr->playerTrainerId[1] << 8)
| (gSaveBlock2Ptr->playerTrainerId[2] << 16)
| (gSaveBlock2Ptr->playerTrainerId[3] << 24);
u32 rolls = 1;

if (CheckBagHasItem(ITEM_SHINY_CHARM, 1))
rolls += I_SHINY_CHARM_ADDITIONAL_ROLLS;
if (LURE_STEP_COUNT != 0)
rolls += 1;

if (parameters.shinyRerolls)
{
do
{
pid = GeneratePIDNature(parameters);
rolls--;
} while (GET_SHINY_VALUE(tid, pid) >= SHINY_ODDS && rolls > 0);
}
else
{
pid = GeneratePIDNature(parameters);
}

return pid;
}

void CreateMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)
{
u32 mail;
Expand All @@ -836,56 +928,64 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
u8 availableIVs[NUM_STATS];
u8 selectedIvs[LEGENDARY_PERFECT_IV_COUNT];
bool32 isShiny;
struct PIDParameters parameters;

ZeroBoxMonData(boxMon);
parameters.species = species;

if (hasFixedPersonality)
personality = fixedPersonality;
if (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY))
isShiny = FALSE;
else if (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY))
isShiny = TRUE;
else
personality = Random32();
isShiny = 2; // Neither locked nor forced

parameters.shinyRerolls = TRUE;
parameters.forceNature = FALSE;
parameters.nature = 0;
parameters.forceGender = FALSE;
parameters.gender = 0;
parameters.forceUnownLetter = FALSE;
parameters.unownLetter = 0;

ZeroBoxMonData(boxMon);

// Determine original trainer ID
if (otIdType == OT_ID_RANDOM_NO_SHINY)
{
if (hasFixedPersonality)
personality = fixedPersonality;
else
personality = GeneratePIDMaster(parameters);

value = Random32();
isShiny = FALSE;
}
else if (otIdType == OT_ID_PRESET)
{
if (hasFixedPersonality)
personality = fixedPersonality;
else
personality = GeneratePIDMaster(parameters);

value = fixedOtId;
isShiny = GET_SHINY_VALUE(value, personality) < SHINY_ODDS;

if (isShiny == 2)
isShiny = GET_SHINY_VALUE(value, personality) < SHINY_ODDS;
}
else // Player is the OT
{
if (hasFixedPersonality)
personality = fixedPersonality;
else
personality = GeneratePIDMaster(parameters);

value = gSaveBlock2Ptr->playerTrainerId[0]
| (gSaveBlock2Ptr->playerTrainerId[1] << 8)
| (gSaveBlock2Ptr->playerTrainerId[2] << 16)
| (gSaveBlock2Ptr->playerTrainerId[3] << 24);

if (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY))
{
isShiny = FALSE;
}
else if (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY))
{
isShiny = TRUE;
}
else
{
u32 totalRerolls = 0;
if (CheckBagHasItem(ITEM_SHINY_CHARM, 1))
totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS;
if (LURE_STEP_COUNT != 0)
totalRerolls += 1;

while (GET_SHINY_VALUE(value, personality) >= SHINY_ODDS && totalRerolls > 0)
{
personality = Random32();
totalRerolls--;
}

if (isShiny == 2)
isShiny = GET_SHINY_VALUE(value, personality) < SHINY_ODDS;
}
}

SetBoxMonData(boxMon, MON_DATA_PERSONALITY, &personality);
Expand Down Expand Up @@ -1008,43 +1108,47 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
void CreateMonWithNature(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 nature)
{
u32 personality;
struct PIDParameters parameters;

do
{
personality = Random32();
}
while (nature != GetNatureFromPersonality(personality));
parameters.species = species;
parameters.shinyRerolls = TRUE;
parameters.forceNature = TRUE;
parameters.nature = nature;
parameters.forceGender = FALSE;
parameters.gender = 0;
parameters.forceUnownLetter = FALSE;
parameters.unownLetter = 0;

personality = GeneratePIDMaster(parameters);

CreateMon(mon, species, level, fixedIV, TRUE, personality, OT_ID_PLAYER_ID, 0);
}

void CreateMonWithGenderNatureLetter(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 gender, u8 nature, u8 unownLetter)
{
u32 personality;
struct PIDParameters parameters;

parameters.species = species;
parameters.shinyRerolls = TRUE;
parameters.forceNature = TRUE;
parameters.nature = nature;
parameters.forceGender = TRUE;
parameters.gender = gender;

if ((u8)(unownLetter - 1) < NUM_UNOWN_FORMS)
{
u16 actualLetter;

do
{
personality = Random32();
actualLetter = GET_UNOWN_LETTER(personality);
}
while (nature != GetNatureFromPersonality(personality)
|| gender != GetGenderFromSpeciesAndPersonality(species, personality)
|| actualLetter != unownLetter - 1);
parameters.forceUnownLetter = TRUE;
parameters.unownLetter = unownLetter - 1;
}
else
{
do
{
personality = Random32();
}
while (nature != GetNatureFromPersonality(personality)
|| gender != GetGenderFromSpeciesAndPersonality(species, personality));
parameters.forceUnownLetter = FALSE;
parameters.unownLetter = 0;
}

personality = GeneratePIDMaster(parameters);

CreateMon(mon, species, level, fixedIV, TRUE, personality, OT_ID_PLAYER_ID, 0);
}

Expand Down
2 changes: 1 addition & 1 deletion src/script_pokemon_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ void ScrCmd_givemon(struct ScriptContext *ctx)
u16 move2 = PARSE_FLAG(18, MOVE_NONE);
u16 move3 = PARSE_FLAG(19, MOVE_NONE);
u16 move4 = PARSE_FLAG(20, MOVE_NONE);
bool8 isShiny = PARSE_FLAG(21, FALSE);
bool8 isShiny = PARSE_FLAG(21, Random() < SHINY_ODDS);
bool8 ggMaxFactor = PARSE_FLAG(22, FALSE);
u8 teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES);

Expand Down
Loading