diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index ac1f53bb51..74bc16cf2f 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -129,4 +129,9 @@ // param1: tera type #define FORM_CHANGE_BATTLE_TERASTALLIZATION 22 +// Form change that activates at midnight after a certain amount of days has passed. +// Adding this form change will automatically make the countdown start as soon the Pokémon changes into a species other than the one specified for this form change. +// param1: amount of days +#define FORM_CHANGE_DAYS_PASSED 23 + #endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H diff --git a/include/pokemon.h b/include/pokemon.h index 63a125f536..920aee7e2f 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -26,6 +26,7 @@ enum { MON_DATA_IS_SHINY, MON_DATA_HIDDEN_NATURE, MON_DATA_HP_LOST, + MON_DATA_DAYS_SINCE_FORM_CHANGE, MON_DATA_ENCRYPT_SEPARATOR, MON_DATA_NICKNAME, MON_DATA_NICKNAME10, @@ -246,7 +247,8 @@ struct BoxPokemon u8 hasSpecies:1; u8 isEgg:1; u8 blockBoxRS:1; // Unused, but Pokémon Box Ruby & Sapphire will refuse to deposit a Pokémon with this flag set. - u8 unused_13:4; + u8 daysSinceFormChange:3; // 7 days. + u8 unused_13:1; u8 otName[PLAYER_NAME_LENGTH]; u8 markings:4; u8 compressedStatus:4; @@ -877,5 +879,7 @@ void HealPokemon(struct Pokemon *mon); void HealBoxPokemon(struct BoxPokemon *boxMon); const u8 *GetMoveName(u16 moveId); const u8 *GetMoveAnimationScript(u16 moveId); +void UpdateDaysPassedSinceFormChange(u16 days); +void TrySetDayLimitToFormChange(struct Pokemon *mon); #endif // GUARD_POKEMON_H diff --git a/src/clock.c b/src/clock.c index 825ccc4448..7061f96b7f 100644 --- a/src/clock.c +++ b/src/clock.c @@ -54,6 +54,7 @@ static void UpdatePerDay(struct Time *localTime) UpdateFrontierGambler(daysSince); SetShoalItemFlag(daysSince); SetRandomLotteryNumber(daysSince); + UpdateDaysPassedSinceFormChange(daysSince); *days = localTime->days; } } diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index 78de99f140..52f888a55b 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -779,6 +779,14 @@ static const struct FormChange sGreninjaBattleBondFormChangeTable[] = { }; #endif //P_FAMILY_FROAKIE +#if P_FAMILY_FURFROU +static const struct FormChange sFurfrouFormChangeTable[] = { + {FORM_CHANGE_WITHDRAW, SPECIES_FURFROU_NATURAL}, + {FORM_CHANGE_DAYS_PASSED, SPECIES_FURFROU_NATURAL, 5}, + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FURFROU + #if P_FAMILY_HONEDGE static const struct FormChange sAegislashFormChangeTable[] = { {FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD}, @@ -841,8 +849,9 @@ static const struct FormChange sDiancieFormChangeTable[] = { #if P_FAMILY_HOOPA static const struct FormChange sHoopaFormChangeTable[] = { - {FORM_CHANGE_ITEM_USE, SPECIES_HOOPA_UNBOUND, ITEM_PRISON_BOTTLE, SPECIES_HOOPA_CONFINED}, - {FORM_CHANGE_WITHDRAW, SPECIES_HOOPA_CONFINED}, + {FORM_CHANGE_ITEM_USE, SPECIES_HOOPA_UNBOUND, ITEM_PRISON_BOTTLE, SPECIES_HOOPA_CONFINED}, + {FORM_CHANGE_WITHDRAW, SPECIES_HOOPA_CONFINED}, + {FORM_CHANGE_DAYS_PASSED, SPECIES_HOOPA_CONFINED, 3}, {FORM_CHANGE_TERMINATOR}, }; #endif //P_FAMILY_HOOPA diff --git a/src/data/pokemon/species_info/gen_6_families.h b/src/data/pokemon/species_info/gen_6_families.h index 09ad2a01d0..46c776639c 100644 --- a/src/data/pokemon/species_info/gen_6_families.h +++ b/src/data/pokemon/species_info/gen_6_families.h @@ -2156,6 +2156,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .teachableLearnset = sFurfrouTeachableLearnset, \ .eggMoveLearnset = sFurfrouEggMoveLearnset, \ .formSpeciesIdTable = sFurfrouFormSpeciesIdTable, \ + .formChangeTable = sFurfrouFormChangeTable, \ } [SPECIES_FURFROU_NATURAL] = FURFROU_MISC_INFO(Natural, FALSE, 48, 3, 56, 0, 0), diff --git a/src/party_menu.c b/src/party_menu.c index 2b80361141..c46c74393f 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -6361,6 +6361,7 @@ static void Task_TryItemUseFormChange(u8 taskId) case 0: targetSpecies = gTasks[taskId].tTargetSpecies; SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); + TrySetDayLimitToFormChange(mon); CalculateMonStats(mon); gTasks[taskId].tState++; break; diff --git a/src/pokemon.c b/src/pokemon.c index 8c6a5fcce6..19394b8dfd 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2856,6 +2856,9 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) retVal = nature ^ boxMon->hiddenNatureModifier; break; } + case MON_DATA_DAYS_SINCE_FORM_CHANGE: + retVal = boxMon->daysSinceFormChange; + break; default: break; } @@ -3290,6 +3293,9 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) boxMon->hiddenNatureModifier = nature ^ hiddenNature; break; } + case MON_DATA_DAYS_SINCE_FORM_CHANGE: + SET8(boxMon->daysSinceFormChange); + break; } } @@ -6523,6 +6529,7 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 break; case FORM_CHANGE_WITHDRAW: case FORM_CHANGE_FAINT: + case FORM_CHANGE_DAYS_PASSED: targetSpecies = formChanges[i].targetSpecies; break; case FORM_CHANGE_STATUS: @@ -6550,6 +6557,22 @@ u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 return targetSpecies; } +void TrySetDayLimitToFormChange(struct Pokemon *mon) +{ + u32 i; + u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); + const struct FormChange *formChanges = GetSpeciesFormChanges(species); + + for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++) + { + if (formChanges[i].method == FORM_CHANGE_DAYS_PASSED && species != formChanges[i].targetSpecies) + { + SetMonData(mon, MON_DATA_DAYS_SINCE_FORM_CHANGE, &formChanges[i].param1); + break; + } + } +} + bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method) { u32 i; @@ -6866,3 +6889,38 @@ const u8 *GetMoveAnimationScript(u16 moveId) } return gMovesInfo[moveId].battleAnimScript; } + +void UpdateDaysPassedSinceFormChange(u16 days) +{ + u32 i; + for (i = 0; i < PARTY_SIZE; i++) + { + struct Pokemon *mon = &gPlayerParty[i]; + u8 daysSinceFormChange; + + if (!GetMonData(mon, MON_DATA_SPECIES, 0)) + continue; + + daysSinceFormChange = GetMonData(mon, MON_DATA_DAYS_SINCE_FORM_CHANGE, 0); + if (daysSinceFormChange == 0) + continue; + + if (daysSinceFormChange > days) + daysSinceFormChange -= days; + else + daysSinceFormChange = 0; + + SetMonData(mon, MON_DATA_DAYS_SINCE_FORM_CHANGE, &daysSinceFormChange); + + if (daysSinceFormChange == 0) + { + u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_DAYS_PASSED, 0); + + if (targetSpecies != SPECIES_NONE) + { + SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); + CalculateMonStats(mon); + } + } + } +}