• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Porting over new gen daycare mechanics (help needed)

takyon

Villain
17
Posts
6
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:
    Code:
    #define DESTINY_KNOT_INHERITED_IV_COUNT 5
    All of these changes will now mostly be on src/daycare.c
    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);
    }
    The function InheritPokeball(&egg, daycare); is called after InheritIVs(&egg, daycare); under _GiveEggFromDaycare(struct DayCare *daycare)
    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;
    		}
    	}
    }
    This has been tested to work. Here are the IVs of a Magikarp bred from two 6IV perfects with one holding Destiny Knot
    Porting over new gen daycare mechanics (help needed)


    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;
    }
    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:
    PokemonCrazy said:
    I just added the do while loop from daycare.c if it has a fixed personality, and it works!
    Code:
                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);
    this goes in pokemon.c, right after the variable declarations in if (CheckBagHasItem(ITEM_SHINY_CHARM, 1)) in CreateBoxMon

    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:
    Code:
    u8 numLevelsGained = GetNumLevelsGainedFromSteps(daycareMon);
    cost = 100 + 100 * numLevelsGained;
    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.)

    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:
    146
    Posts
    16
    Years
    • Age 26
    • Seen Apr 29, 2024
    In trying to figure out nature inheritance, I've narrowed down the problem with being in DizzyEgg's item_expansion.

    I tested Everstone functionality in a clean pret pokeemerald and it worked as intended, then I tested Everstone functionality in DizzyEgg's battle_engine_v2 and it again, worked as intended, but once I added item_expansion, the Everstone no longer worked to pass down nature. I then tested it with just item_expansion, and it still did not work, leading me to believe that item_expansion is the problem.

    I tested it using base daycare.c code, with the only modification being changing Random() >= USHRT_MAX / 2 to Random() >= USHRT_MAX on line 452. This modification worked on base pokeemerald and battle_engine_v2, but not at all in item_expansion. That's the only code I changed in the branch, and it just does not work.

    I don't really know what causes this, but maybe someone with a better knowledge of C/pokeemerald (or perhaps DizzyEgg himself) could figure out what's going awry.

    EDIT: I also should've mentioned, I believe that this is caused by a discrepancy in the personality value when it's made in daycare.c and when the egg hatches in egg_hatch.c (as those two personality values return different natures when you call GetNatureByPersonality), but item_expansion doesn't touch either of those files, so I'm at a loss.
     
    Last edited:
    55
    Posts
    14
    Years
    • Seen Feb 1, 2023
    In trying to figure out nature inheritance, I've narrowed down the problem with being in DizzyEgg's item_expansion.

    I tested Everstone functionality in a clean pret pokeemerald and it worked as intended, then I tested Everstone functionality in DizzyEgg's battle_engine_v2 and it again, worked as intended, but once I added item_expansion, the Everstone no longer worked to pass down nature. I then tested it with just item_expansion, and it still did not work, leading me to believe that item_expansion is the problem.

    I tested it using base daycare.c code, with the only modification being changing Random() >= USHRT_MAX / 2 to Random() >= USHRT_MAX on line 452. This modification worked on base pokeemerald and battle_engine_v2, but not at all in item_expansion. That's the only code I changed in the branch, and it just does not work.

    I don't really know what causes this, but maybe someone with a better knowledge of C/pokeemerald (or perhaps DizzyEgg himself) could figure out what's going awry.

    EDIT: I also should've mentioned, I believe that this is caused by a discrepancy in the personality value when it's made in daycare.c and when the egg hatches in egg_hatch.c (as those two personality values return different natures when you call GetNatureByPersonality), but item_expansion doesn't touch either of those files, so I'm at a loss.


    @PokemonCrazy, I may have a clue to your answer. I'm playing with some code that lets the player choose a nature and all wild pkmn should have that nature, but I was having some issues. Upon investigation, it could be related to the Shiny Charm mechanic added y Dizzy's item expansion. In pokemon.c, specifically the CreateBoxMon function, the ShinyCharm mechanic rerolls the personality (and therefore nature) value. My suggestions:
    1. Double check you don't have Shiny Charm in your inventory, as it will definitely mess up your nature selection.
    2. Even if Shiny Charm isn't in your inventory, try commenting out the SC code in CreateBoxMon and see if your results improve.
    3. Barring that, take a look at the diff for pokemon.c on the item expansion branch and verify that nothing else there could be messing with the nature you select.

    I hope one of those things helps!

    Edit: ha, just read the OP again and it seems I'm spot on and that it's already been fixed. Cheers!
     
    Back
    Top