takyon
Villain
- 17
- Posts
- 7
- Years
- Seen May 4, 2024
PokemonCrazy and I have been working on porting over the daycare mechanics from the newer games. Some of them work, some of them don't. Some of them work but with some caveats.
Porting over these changes needed the DizzyEgg engine(s), but can be used on vanilla pokeemerald by replacing Destiny Knot and Cherish Ball with anything else. Incense baby Pokemon would need the Pokemon and incenses required however. Here are our findings:
- Pokeball inheritance works as intended.
- Experience gain removal implemented thanks to PokemonCrazy
- IV inheritance works as intended (Destiny Knot and Power Items thanks to PokemonCrazy)
- Nature inheritance works as intended, added fix for DizzyEgg's shiny charm (from item-expansion)
- Incense baby pokemon implemented but not tested, should work though https://github.com/TimeRamen/pokeemerald/commit/9ef5398a047d0590f620e09ee389b7c5d93b52e9
- Regional form inheritance not implemented yet
- Abilities (and hidden ability) inheritance not implemented yet.
Edit include/constants/daycare.h to have:
All of these changes will now mostly be on src/daycare.c
For Pokeball Inheritance
The function InheritPokeball(&egg, daycare); is called after InheritIVs(&egg, daycare); under _GiveEggFromDaycare(struct DayCare *daycare)
This is the inheritIVs function (accounts for Destiny Knot and Power Items.
This has been tested to work. Here are the IVs of a Magikarp bred from two 6IV perfects with one holding Destiny Knot
Next is the nature inheriting code. The data type for the return value has been changed to u8, because there's absolutely no reason why a function that can only return three possible outcomes needs all that extra data.
Since the data type has been changed to u8, and not s32, we need to change every instance of GetParentToInheritNature. Thankfully, there's only one time it is used, and it is right below under _TriggerPendingDaycareEgg. Just change it to u8 parent; and change the if condition to if(parent > 1)
If you plan to keep it as s32 for any reason, just change the return 2; into return -1.
PokemonCrazy figured out how to work it with Shiny Charm:
Removing exp gain from the DayCare:
If anyone could help figure out what's wrong with our approach or whether or not there's extra checks we are not aware of that would be really helpful. And pointers on implementing the rest of the planned features would also help.
Porting over these changes needed the DizzyEgg engine(s), but can be used on vanilla pokeemerald by replacing Destiny Knot and Cherish Ball with anything else. Incense baby Pokemon would need the Pokemon and incenses required however. Here are our findings:
- Pokeball inheritance works as intended.
- Experience gain removal implemented thanks to PokemonCrazy
- IV inheritance works as intended (Destiny Knot and Power Items thanks to PokemonCrazy)
- Nature inheritance works as intended, added fix for DizzyEgg's shiny charm (from item-expansion)
- Incense baby pokemon implemented but not tested, should work though https://github.com/TimeRamen/pokeemerald/commit/9ef5398a047d0590f620e09ee389b7c5d93b52e9
- Regional form inheritance not implemented yet
- Abilities (and hidden ability) inheritance not implemented yet.
Edit include/constants/daycare.h to have:
Code:
#define DESTINY_KNOT_INHERITED_IV_COUNT 5
For Pokeball Inheritance
Code:
static u16 InheritPokeball(struct Pokemon *egg, struct DayCare *daycare)
{
s32 i;
s32 j;
s32 parent = -1;
s32 ball;
for (i = 0, j=1; i < DAYCARE_MON_COUNT; i++,j--)
{
if (GetBoxMonGender(&daycare->mons[i].mon) == MON_FEMALE)
{
parent = i;
}else{
parent = j;
}
}
if(GetBoxMonData(&daycare->mons[0].mon, MON_DATA_SPECIES == SPECIES_DITTO))
{
parent = 1;
}
if (GetBoxMonData(&daycare->mons[0].mon, MON_DATA_SPECIES) ==
GetBoxMonData(&daycare->mons[1].mon, MON_DATA_SPECIES))
{
if (Random() >= USHRT_MAX / 2)
parent = 0;
else
parent = 1;
}
ball = GetBoxMonData(&daycare->mons[parent].mon, MON_DATA_POKEBALL);
if (ball == ITEM_MASTER_BALL || ball == ITEM_CHERISH_BALL)
ball = ITEM_POKE_BALL;
SetMonData(egg, MON_DATA_POKEBALL, &ball);
}
PokemonCrazy said:got the ball inheritance to work properly by doing this:
removing u16 ball;, ball = ITEM_POKE_BALL;, and SetMonData(mon, MON_DATA_POKEBALL, &ball); in CreateEgg in daycare.c
removing ball = ITEM_POKE_BALL; and SetMonData(mon, MON_DATA_POKEBALL, &ball); in AddHatchedMonToParty in egg_hatch.c
adding u16 ball; (at the top ofc), ball = GetMonData(egg, MON_DATA_POKEBALL);, and SetMonData(temp, MON_DATA_POKEBALL, &ball); (i placed these right above the *egg = *temp; line at the end of the method) in CreateHatchedMon in egg_hatch.c
This is the inheritIVs function (accounts for Destiny Knot and Power Items.
Code:
static void InheritIVs(struct Pokemon *egg, struct DayCare *daycare)
{
u8 i;
u8 iv;
u8 randomStat;
u32 motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM);
u32 fatherItem = GetBoxMonData(&daycare->mons[1].mon, MON_DATA_HELD_ITEM);
u8 ivCount = (motherItem == ITEM_DESTINY_KNOT || fatherItem == ITEM_DESTINY_KNOT) ? DESTINY_KNOT_INHERITED_IV_COUNT : INHERITED_IV_COUNT;
u32 powerItems[6] = { ITEM_POWER_WEIGHT, ITEM_POWER_BRACER, ITEM_POWER_BELT, ITEM_POWER_LENS, ITEM_POWER_BAND, ITEM_POWER_ANKLET };
u32 motherPowerItem = -1;
u32 fatherPowerItem = -1;
u8 selectedIvs[ivCount];
u8 whichParents[ivCount];
u8 availableIVs[NUM_STATS];
// check for power items
for (i = 0; i < 6; i++)
{
if (motherItem == powerItems[i])
{
motherPowerItem = i;
}
if (fatherItem == powerItems[i])
{
fatherPowerItem = i;
}
}
// Initialize a list of IV indices.
for (i = 0; i < NUM_STATS; i++)
{
availableIVs[i] = i;
}
// check if both parents have power items
if (motherPowerItem != -1 && fatherPowerItem != -1)
{
// inherit mother's IV
selectedIvs[0] = availableIVs[motherPowerItem];
RemoveIVIndexFromList(availableIVs, motherPowerItem);
// if mother < father, father has to be decremented to inherit correct IV
if (motherPowerItem < fatherPowerItem)
{
selectedIvs[1] = availableIVs[fatherPowerItem - 1];
RemoveIVIndexFromList(availableIVs, fatherPowerItem - 1);
}
else
{
selectedIvs[1] = availableIVs[fatherPowerItem];
RemoveIVIndexFromList(availableIVs, fatherPowerItem);
}
// make sure the IV gets inherited from the correct parents
whichParents[motherPowerItem] = 0;
whichParents[fatherPowerItem] = 1;
// if both parents have power item, no need for a loop
randomStat = Random() % (NUM_STATS - 2);
selectedIvs[2] = availableIVs[randomStat];
RemoveIVIndexFromList(availableIVs, randomStat);
// Determine which parent each of the selected IVs should inherit from.
for (i = 0; i < ivCount; i++)
{
if (i != motherPowerItem && i != fatherPowerItem)
{
whichParents[i] = Random() % DAYCARE_MON_COUNT;
}
}
}
// if just the mother has a power item
else if (motherPowerItem != -1)
{
selectedIvs[0] = availableIVs[motherPowerItem];
RemoveIVIndexFromList(availableIVs, motherPowerItem);
// loop for other inherited IVs
for (i = 1; i < ivCount; i++)
{
randomStat = Random() % (NUM_STATS - i);
selectedIvs[i] = availableIVs[randomStat];
RemoveIVIndexFromList(availableIVs, randomStat);
}
whichParents[motherPowerItem] = 0;
for (i = 0; i < ivCount; i++)
{
if (i != motherPowerItem)
{
whichParents[i] = Random() % DAYCARE_MON_COUNT;
}
}
}
// if just the father has a power item
else if (fatherPowerItem != -1)
{
selectedIvs[0] = availableIVs[fatherPowerItem];
RemoveIVIndexFromList(availableIVs, fatherPowerItem);
for (i = 1; i < ivCount; i++)
{
randomStat = Random() % (NUM_STATS - i);
selectedIvs[i] = availableIVs[randomStat];
RemoveIVIndexFromList(availableIVs, randomStat);
}
whichParents[fatherPowerItem] = 1;
for (i = 0; i < ivCount; i++)
{
if (i != fatherPowerItem)
{
whichParents[i] = Random() % DAYCARE_MON_COUNT;
}
}
}
// otherwise, if no parents have a power item
else {
for (i = 0; i < ivCount; i++)
{
// Randomly pick an IV from the available list and stop from being chosen again.
randomStat = Random() % (NUM_STATS - i);
selectedIvs[i] = availableIVs[randomStat];
RemoveIVIndexFromList(availableIVs, randomStat);
}
// Determine which parent each of the selected IVs should inherit from.
for (i = 0; i < ivCount; i++)
{
whichParents[i] = Random() % DAYCARE_MON_COUNT;
}
}
// Set each of inherited IVs on the egg mon.
for (i = 0; i < ivCount; i++)
{
switch (selectedIvs[i])
{
case 0:
iv = GetBoxMonData(&daycare->mons[whichParents[i]].mon, MON_DATA_HP_IV);
SetMonData(egg, MON_DATA_HP_IV, &iv);
break;
case 1:
iv = GetBoxMonData(&daycare->mons[whichParents[i]].mon, MON_DATA_ATK_IV);
SetMonData(egg, MON_DATA_ATK_IV, &iv);
break;
case 2:
iv = GetBoxMonData(&daycare->mons[whichParents[i]].mon, MON_DATA_DEF_IV);
SetMonData(egg, MON_DATA_DEF_IV, &iv);
break;
case 3:
iv = GetBoxMonData(&daycare->mons[whichParents[i]].mon, MON_DATA_SPATK_IV);
SetMonData(egg, MON_DATA_SPATK_IV, &iv);
break;
case 4:
iv = GetBoxMonData(&daycare->mons[whichParents[i]].mon, MON_DATA_SPDEF_IV);
SetMonData(egg, MON_DATA_SPDEF_IV, &iv);
break;
case 5:
iv = GetBoxMonData(&daycare->mons[whichParents[i]].mon, MON_DATA_SPEED_IV);
SetMonData(egg, MON_DATA_SPEED_IV, &iv);
break;
}
}
}
![[PokeCommunity.com] Porting over new gen daycare mechanics (help needed) [PokeCommunity.com] Porting over new gen daycare mechanics (help needed)](https://media.discordapp.net/attachments/713591874086240337/714171696294133760/unknown.png)
Next is the nature inheriting code. The data type for the return value has been changed to u8, because there's absolutely no reason why a function that can only return three possible outcomes needs all that extra data.
Code:
static u8 GetParentToInheritNature(struct DayCare *daycare)
{
u16 motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM);
u16 fatherItem = GetBoxMonData(&daycare->mons[1].mon, MON_DATA_HELD_ITEM);
if(motherItem == ITEM_EVERSTONE && fatherItem == ITEM_EVERSTONE)
{
if (Random() >= USHRT_MAX / 2)
return 0;
else
return 1;
}else
{
if(motherItem == ITEM_EVERSTONE)
{
return 0;
}
if(fatherItem == ITEM_EVERSTONE)
{
return 1;
}
}
return 2;
}
If you plan to keep it as s32 for any reason, just change the return 2; into return -1.
PokemonCrazy figured out how to work it with Shiny Charm:
PokemonCrazy said:I just added the do while loop from daycare.c if it has a fixed personality, and it works!
this goes in pokemon.c, right after the variable declarations in if (CheckBagHasItem(ITEM_SHINY_CHARM, 1)) in CreateBoxMonCode:do { if (hasFixedPersonality) { u8 wantedNature = GetNatureFromPersonality(fixedPersonality); s32 natureTries = 0; do { personality = (Random2() << 16) | (Random()); if (wantedNature == GetNatureFromPersonality(personality) && personality != 0) break; // found a personality with the same nature natureTries++; } while (natureTries <= 2400); } else { personality = Random32(); } shinyValue = HIHALF(value) ^ LOHALF(value) ^ HIHALF(personality) ^ LOHALF(personality); rolls++; } while (shinyValue >= SHINY_ODDS && rolls < SHINY_CHARM_REROLLS);
Removing exp gain from the DayCare:
PokemonCrazy said:here's all the steps to remove experience gain in daycare:
remove this if statement from TakeSelectedPokemonFromDaycare:
Code:if (GetMonData(&pokemon, MON_DATA_LEVEL) != MAX_LEVEL) { experience = GetMonData(&pokemon, MON_DATA_EXP) + daycareMon->steps; SetMonData(&pokemon, MON_DATA_EXP, &experience); ApplyDaycareExperience(&pokemon); }
remove these 3 methods:
Code:static u8 GetLevelAfterDaycareSteps(struct BoxPokemon *mon, u32 steps) { struct BoxPokemon tempMon = *mon; u32 experience = GetBoxMonData(mon, MON_DATA_EXP) + steps; SetBoxMonData(&tempMon, MON_DATA_EXP, &experience); return GetLevelFromBoxMonExp(&tempMon); } static u8 GetNumLevelsGainedFromSteps(struct DaycareMon *daycareMon) { u8 levelBefore; u8 levelAfter; levelBefore = GetLevelFromBoxMonExp(&daycareMon->mon); levelAfter = GetLevelAfterDaycareSteps(&daycareMon->mon, daycareMon->steps); return levelAfter - levelBefore; } static u8 GetNumLevelsGainedForDaycareMon(struct DaycareMon *daycareMon) { u8 numLevelsGained = GetNumLevelsGainedFromSteps(daycareMon); ConvertIntToDecimalStringN(gStringVar2, numLevelsGained, STR_CONV_MODE_LEFT_ALIGN, 2); GetBoxMonNickname(&daycareMon->mon, gStringVar1); return numLevelsGained; }
in GetDaycareCostForSelectedMon, remove these two lines:
and change u32 cost; to u32 cost = 200; (Or any cost you want. In fact if you are keeping it below 255, might as well make it u8 instead of u32.)Code:u8 numLevelsGained = GetNumLevelsGainedFromSteps(daycareMon); cost = 100 + 100 * numLevelsGained;
remove the DaycarePrintMonLvl method and remove the line that calls it in DaycarePrintMonInfo
remove the GetDaycareLevelMenuLevelText method
remove the if statement in GetNumLevelsGainedFromDaycare so it always returns 0
If anyone could help figure out what's wrong with our approach or whether or not there's extra checks we are not aware of that would be really helpful. And pointers on implementing the rest of the planned features would also help.
Last edited: