Simple Modifications Directory Page 2

Started by Avara December 30th, 2018 2:48 PM
  • 118109 views
  • 340 replies
Seen 25 Minutes Ago
Posted April 9th, 2021
787 posts
14.9 Years
Wrapping Summary Screen [EM]

In XY and later games, the Summary Screen wraps around. By that I mean if you press down on the summary screen of the last Pokémon in your party, you'll be taken back to the first Pokémon in your party (in earlier games, it would just do nothing). Similarly, if you press up while on the first Pokémon in your party, you'll go to the last.

To copy this behavior in In pokeemerald, in
src/pokemon_summary_screen.c
, change
sub_81C08F8
to the following:

static s8 sub_81C08F8(s8 delta)
{
    struct Pokemon *mon = sMonSummaryScreen->monList.mons;
    u8 index = sMonSummaryScreen->curMonIndex;
    u8 numMons = sMonSummaryScreen->maxMonIndex + 1;
    delta += numMons;

    index = (index + delta) % numMons;

    // skip over any Eggs unless on the Info Page
    if (sMonSummaryScreen->currPageIndex != PSS_PAGE_INFO)
        while (GetMonData(&mon[index], MON_DATA_IS_EGG))
            index = (index + delta) % numMons;

    // to avoid "scrolling" to the same Pokemon
    if (index == sMonSummaryScreen->curMonIndex)
        return -1;
    else
        return index;
}
Edit: As pointed out by Lunos,
sub_81C08F8
has been renamed to
AdvanceMonIndex
since I posted this.

Avara

She/Her
Seen 4 Days Ago
Posted 2 Weeks Ago
1,305 posts
10.1 Years
Updated the first post! Thanks a lot for sharing your contributions, troops x

AsparagusEdu

AsparagusEduardo

Age 28
Male
Seen 2 Weeks Ago
Posted 2 Weeks Ago
25 posts
7.9 Years
White out money calculation [EM]

In Gen I & II and RSE, you lose half of your money when defeated. However, in FLRG & Gen IV onwards the amount you lose is calculated by a formula based on the amount of badges and the highest level in your Pokémon's Party.
[Bulbapedia source]

This mod implements that formula (using the FLRG values).



GitHub link:
https://github.com/AsparagusEduardo/pokeemerald/tree/WhiteOutMoney

AsparagusEdu

AsparagusEduardo

Age 28
Male
Seen 2 Weeks Ago
Posted 2 Weeks Ago
25 posts
7.9 Years
"Move Pokémon" as first PSS option [EM]

Please don't use this until I fix a softlock when choosing the "Deposit Pokémon" option. Sorry for the inconvenience ^^;

In "src/pokemon_storage_system.c", change the order of this:
Spoiler:

and this:
Spoiler:

and below switch(task->data[2]) in Task_PokemonStorageSystemPC change these two:
Spoiler:
Male
Seen 3 Weeks Ago
Posted August 21st, 2021
5 posts
8.5 Years
About "Surviving poison outside of battle with 1hp":
It looks like the code there's an error in the code, or did I did something wrong ?

Error:
src/field_poison.c: In function `DoPoisonFieldEffect':
src/field_poison.c:135: `EventScript_PoisonSurvial' undeclared (first use in this function)
src/field_poison.c:135: (Each undeclared identifier is reported only once
src/field_poison.c:135: for each function it appears in.)
make: *** [Makefile:242: build/emerald/src/field_poison.o] Error 1

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
About "Surviving poison outside of battle with 1hp":
It looks like the code there's an error in the code, or did I did something wrong ?

Error:
src/field_poison.c: In function `DoPoisonFieldEffect':
src/field_poison.c:135: `EventScript_PoisonSurvial' undeclared (first use in this function)
src/field_poison.c:135: (Each undeclared identifier is reported only once
src/field_poison.c:135: for each function it appears in.)
make: *** [Makefile:242: build/emerald/src/field_poison.o] Error 1
Yeah, it doesn't seem to work. I asked TheXaman about this on his profile back in March and he never really answered.
I guess this is a good time to post this. I really should have done it sooner, but I kind of forgot :P

Overworld 1HP Poison Survival [EM]
Some time ago, Blurose made his own version of this mechanic for his project in Pokeruby.
Some months ago, I ported it to Pokeemerald, and this seems to be a good time to post it here as an alternative.

The relevant modifications can be seen in this commit, it's veery simple.
https://github.com/LOuroboros/pokeemerald/commit/c162100fdc5439ebd7eefabc5890dae56d1a88f7

Pics:


And that's pretty much it.

EDIT (31/12/2020): I decided to put this feature on a standalone branch too because why not.
To easily merge it in a project that is up-to-date with Pret's Pokeemerald, you just have to track my repository via
git remote
and then pull the branch in which I put it.
git remote add lunos https://github.com/LOuroboros/pokeemerald
git pull lunos ow_1hp_psn_survival

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
Full National Dex [EM]

Method 1: Script Loop
Spoiler:

A cheap and dirty way to get yourself a National Pokédex with the entries of the 386 Pokémon in the game.
There's probably better ways to go about reaching the same result, but this one worked and the commit might help people who don't know how to add new Specials to the game, so it's kinda like killing 2 birds with 1 stone.
https://github.com/LOuroboros/pokeemerald/commit/0b5336a64bdffed7bda92b5613b1a3ed3599a747



As you can see in the picture, after applying the changes to your repository, you just have to use call FillPokedex in your script of choice and trigger it inside the game.


Method 2: Code function
Spoiler:
Back in March I quickly wrote an alternative to this in C.
Originally, I used a script loop because I didn't know jack about C.
Today... well, I still don't think I can say that I know C all that well, but I know it better than before for sure.
First we'll go to
src/field_specials.c
and throw in
#include "pokedex.h"
at the end of the list of headers in the top of the file.

Then, we'll add this function somewhere in the file. Preferably, at the very end. Right after the last function.
void FillPokedex(void)
{
    u16 i;

    for (i = SPECIES_BULBASAUR; i <= SPECIES_DEOXYS; i++)
    {
        GetSetPokedexFlag(i, FLAG_SET_SEEN);
        GetSetPokedexFlag(i, FLAG_SET_CAUGHT);
    }
}
How do you use this? Pretty simple.
Define the special in
data/specials.inc
and then call
special FillPokedex
in a script.


EDIT (22/09/2021): I added an alternative method that I wrote back in March, but I completely forgot to post here.

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
Gen. 8 Synchronize [EM]
Synchronize in Gen. 8 always makes it so your Pokémon copies their nature onto the wild Pokémon that you can find. The effect doesn't have a 50% chance anymore.

This is a very simple thing to do. Just go to src/data/wild_encounter.c, Ctrl+F ABILITY_SYNCHRONIZE and delete the 3rd condition stated there.

From this:
if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)
        && GetMonAbility(&gPlayerParty[0]) == ABILITY_SYNCHRONIZE
        && Random() % 2 == 0)
It'll become this:
if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)
        && GetMonAbility(&gPlayerParty[0]) == ABILITY_SYNCHRONIZE)
And that's pretty much it.

The credits for this go to Fontbane.
They dropped the tip in a certain Discord server and I decided to post it here as well, because there's no reason not to.
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
BW Repel

Whenever the Repel's effect wears off, a prompt will appear asking player if they wish to use another one. Similarly to my old pre-decomp implementation, this one also lets you choose which Repel(Regular, Super, Max) to use. Obviously, if you have only one kind, this part is skipped.

src/script_menu.c DrawMultichoiceMenu
I modified the function, so it works with custom menu options, in ours case Repels ones. Change that part to:
Spoiler:
static void DrawMultichoiceMenuCustom(u8 left, u8 top, u8 multichoiceId, u8 ignoreBPress, u8 cursorPos, const struct MenuAction *actions, int count)
{
    int i, windowId, width = 0;
    u8 newWidth;

    for (i = 0; i < count; i++)
    {
        width = DisplayTextAndGetWidth(actions[i].text, width);
    }

    newWidth = ConvertPixelWidthToTileWidth(width);
    left = ScriptMenu_AdjustLeftCoordFromWidth(left, newWidth);
    windowId = CreateWindowFromRect(left, top, newWidth, count * 2);
    SetStandardWindowBorderStyle(windowId, 0);
    PrintMenuTable(windowId, count, actions);
    InitMenuInUpperLeftCornerPlaySoundWhenAPressed(windowId, count, cursorPos);
    schedule_bg_copy_tilemap_to_vram(0);
    InitMultichoiceCheckWrap(ignoreBPress, count, windowId, multichoiceId);
}

static void DrawMultichoiceMenu(u8 left, u8 top, u8 multichoiceId, u8 ignoreBPress, u8 cursorPos)
{
    DrawMultichoiceMenuCustom(left, top, multichoiceId, ignoreBPress, cursorPos, sMultichoiceLists[multichoiceId].list, sMultichoiceLists[multichoiceId].count);
}

void TryDrawRepelMenu(void)
{
    static const u16 repelItems[] = {ITEM_REPEL, ITEM_SUPER_REPEL, ITEM_MAX_REPEL};
    struct MenuAction menuItems[4] = {NULL};
    int i, count = 0;

    for (i = 0; i < ARRAY_COUNT(repelItems); i++)
    {
        if (CheckBagHasItem(repelItems[i], 1))
        {
            VarSet(VAR_0x8004 + count, repelItems[i]);
            menuItems[count].text = ItemId_GetName(repelItems[i]);
            count++;
        }
    }

    if (count > 1)
        DrawMultichoiceMenuCustom(0, 0, 0, FALSE, 0, menuItems, count);

    gSpecialVar_Result = (count > 1);
}

void HandleRepelMenuChoice(void)
{
    gSpecialVar_0x8004 = VarGet(VAR_0x8004 + gSpecialVar_Result); // Get item Id;
    VarSet(VAR_REPEL_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_0x8004));
}

Now
data/scripts/repel.inc
Spoiler:
EventScript_RepelWoreOff:: @ 82A4B2A
	msgbox Text_RepelWoreOff, MSGBOX_SIGN
	checkitem ITEM_REPEL, 1
	compare VAR_RESULT, TRUE
	goto_if_eq EventScript_RepelWoreOff_AskAnother
	checkitem ITEM_SUPER_REPEL, 1
	compare VAR_RESULT, TRUE
	goto_if_eq EventScript_RepelWoreOff_AskAnother
	checkitem ITEM_MAX_REPEL, 1
	compare VAR_RESULT, FALSE
	goto_if_eq EventScript_RepelWoreOff_End
EventScript_RepelWoreOff_AskAnother:
	msgbox Text_RepelAskAnother, MSGBOX_YESNO
	closemessage
	compare VAR_RESULT, 0
	goto_if_eq EventScript_RepelWoreOff_End
	callnative TryDrawRepelMenu
	compare VAR_RESULT, FALSE
	goto_if_eq EventScript_RepelWoreOff_Chose
	waitstate
	compare VAR_RESULT, 127
	goto_if_eq EventScript_RepelWoreOff_End
EventScript_RepelWoreOff_Chose:
	callnative HandleRepelMenuChoice
	bufferitemname 1, VAR_0x8004
	takeitem VAR_0x8004, 1
	playse SE_TU_SAA
	msgbox gText_PlayerUsedVar2, MSGBOX_SIGN
EventScript_RepelWoreOff_End:
	end

Text_RepelWoreOff: @ 82A4B33
	.string "REPEL's effect wore off…$"
Text_RepelAskAnother:
	.string "Would you like to use another one?$"

Screenshots:
Spoiler:



I also have the code in my github branch called repel, so you can pull directly from it.
this one didn't work for me. it don't ask me if I want to use another repel...
EDIT: Solved, i didnt do a "make -j2", just a "make NODEP=1"
sorry for that
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
Evolution Moves (Emerald)

In the gen VII games many Pokemon have level up moves that they learn upon evolving, regardless of what level they are. This is a fantastic addition because it means Pokemon like Feebas don't stay useless if they evolve a level too late to learn their first damaging move.

To implement this in Emerald, first open include/pokemon.h and add an extra input argument to the function "MonTryLearningNewMove":
u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove, bool8 isEvolving);
Next, modify all code that calls this function to include a third input argument. There are two instances in src/evolution_scene.c where this should be set to "1", like so:
var = MonTryLearningNewMove(mon, gTasks[taskID].tLearnsFirstMove, 1);
All other instances should be set to "0". These can be found in src/party_menu.c, src/battle_script_commands.c, and src/daycare.c.

Following that, open pokemon.c and navigate to the function "MonTryLearningNewMove". Replace it with the following:
Spoiler:
u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove, bool8 isEvolving)
{
    u32 retVal = 0;
    u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
    u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL);

    // since you can learn more than one move per level
    // the game needs to know whether you decided to
    // learn it or keep the old set to avoid asking
    // you to learn the same move over and over again
    if (firstMove)
    {
        sLearningMoveTableID = 0;
    }
    // Added evolution moves; Pokemon will learn moves listed at level zero upon evolution
    if(isEvolving && (gLevelUpLearnsets[species][sLearningMoveTableID].level == 0))
    {
        gMoveToLearn = gLevelUpLearnsets[species][sLearningMoveTableID].move;
        retVal = GiveMoveToMon(mon, gMoveToLearn);
        sLearningMoveTableID++;
        return retVal;        
    }
    if(isEvolving && (gLevelUpLearnsets[species][sLearningMoveTableID].level > 0))
    {
        while (gLevelUpLearnsets[species][sLearningMoveTableID].level != level)
         {
            sLearningMoveTableID++;
            if (gLevelUpLearnsets[species][sLearningMoveTableID].move == LEVEL_UP_END)
                return 0;
         }
    }

    if (firstMove)
    {
        while (gLevelUpLearnsets[species][sLearningMoveTableID].level != level)
        {
            sLearningMoveTableID++;
            if (gLevelUpLearnsets[species][sLearningMoveTableID].move == LEVEL_UP_END)
                return 0;
        }
    }
    if (gLevelUpLearnsets[species][sLearningMoveTableID].level == level)
    {
        gMoveToLearn = gLevelUpLearnsets[species][sLearningMoveTableID].move;
        sLearningMoveTableID++;
        retVal = GiveMoveToMon(mon, gMoveToLearn);
    }
    return retVal;
}

Finally, add some evolution moves to src\data\pokemon\level_up_learnsets.h. These must be the first entries in each Pokemon's list, and must be learned at level zero e.g.
Spoiler:
static const struct LevelUpMove sMarshtompLevelUpLearnset[] = {
    LEVEL_UP_MOVE( 0, MOVE_MUD_SHOT),
    LEVEL_UP_MOVE( 1, MOVE_MUD_SHOT),
    LEVEL_UP_MOVE( 1, MOVE_TACKLE),
    LEVEL_UP_MOVE( 1, MOVE_GROWL),
    LEVEL_UP_MOVE( 1, MOVE_WATER_GUN),
    LEVEL_UP_MOVE( 1, MOVE_MUD_SLAP),
    LEVEL_UP_MOVE( 4, MOVE_WATER_GUN),
    LEVEL_UP_MOVE( 9, MOVE_MUD_SLAP),
    LEVEL_UP_MOVE(12, MOVE_FORESIGHT),
    LEVEL_UP_MOVE(18, MOVE_BIDE),
    LEVEL_UP_MOVE(22, MOVE_MUD_BOMB),
    LEVEL_UP_MOVE(28, MOVE_ROCK_SLIDE),
    LEVEL_UP_MOVE(32, MOVE_PROTECT),
    LEVEL_UP_MOVE(38, MOVE_MUDDY_WATER),
    LEVEL_UP_MOVE(42, MOVE_TAKE_DOWN),
    LEVEL_UP_MOVE(48, MOVE_EARTHQUAKE),
    LEVEL_UP_MOVE(52, MOVE_ENDEAVOR),
    LEVEL_UP_END
};
i've been trying to add this system, but the version used here is outdated and it makes my pokémon learn no moves at all
i tried this:
u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove, bool8 isEvolving)
{
    u16 moveLevel;
    u32 retVal = 0;
    u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
    u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL);
	moveLevel = (gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_LV);

    // since you can learn more than one move per level
    // the game needs to know whether you decided to
    // learn it or keep the old set to avoid asking
    // you to learn the same move over and over again
    if (firstMove)
    {
        sLearningMoveTableID = 0;
    // Added evolution moves; Pokemon will learn moves listed at level zero upon evolution
		if(isEvolving && (moveLevel > 0))
		{
			while ((gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_LV) != (level << 9))
			{
				sLearningMoveTableID++;
				if (gLevelUpLearnsets[species][sLearningMoveTableID] == LEVEL_UP_END)
					return 0;
			}
		}
		else if(isEvolving && (moveLevel == 0))
		{
			while ((gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_LV) != (level << 9))
			{
				sLearningMoveTableID++;
				if (gLevelUpLearnsets[species][sLearningMoveTableID] == LEVEL_UP_END)
					return 0;
			}
		}
		else

			if ((gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_LV) == (level << 9))
			{
				gMoveToLearn = (gLevelUpLearnsets[species][sLearningMoveTableID] & LEVEL_UP_MOVE_ID);
				sLearningMoveTableID++;
				retVal = GiveMoveToMon(mon, gMoveToLearn);
			}
	}

    return retVal;
}

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
Evolution Moves (Emerald)
Back in July 2018, Sagiri made an implementation of Evolution Moves for Pokémon Fire Red via C Injection.
Not so long ago, UltimaSoul ported it to Pokeemerald.
Today I got their permission to drop over here a commit of mine, showing pretty quickly that implementation of Evolution Moves as an alternative to Buffel's.

It's nothing particularly complicated, just 3 simple changes and then it's a matter of setting the Evolution Moves in the src/data/pokemon/level_up_learnsets.h file.
https://github.com/LOuroboros/pokeemerald/commit/b67b5bdd1d5d893c1cbe26386658094a8d1f3f84

Quick demonstration:


And that's pretty much it.



EDIT (27/07/2020): The commit linked above will not work on a clean copy of Pokeemerald. That was my mistake. I should have tested it better when I wrote this post.
It took some time until that fact was brought to my attention by user Funny Valentine, but hey, better late than never, right?

Here's an alternative commit, tested on a clean copy of Pokeemerald. It'll work there.
https://github.com/LOuroboros/pokeemerald/commit/d5f48a1af85be80f01ff2c3adde121db924727d1

Shout-out to ExpoSeed who helped me getting it to work.
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years

Back in July 2018, Sagiri made an implementation of Evolution Moves for Pokémon Fire Red via C Injection.
Not so long ago, UltimaSoul ported it to Pokeemerald.
Today I got their permission to drop over here a commit of mine, showing pretty quickly that implementation of Evolution Moves as an alternative to Buffel's.

It's nothing particularly complicated, just 3 simple changes and then it's a matter of setting the Evolution Moves in the src/data/pokemon/level_up_learnsets.h file.
https://github.com/LOuroboros/pokeemerald/commit/b67b5bdd1d5d893c1cbe26386658094a8d1f3f84

Quick demonstration:


And that's pretty much it.
That still doesn't work for me.
It gives me an error with the ".level" and ".move" things, and when i replace them with the " & LEVEL_UP_MOVE_ID" and " & LEVEL_UP_MOVE_LV" that the original script uses, it just freezes when the Pokémon is learning the move...

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
That still doesn't work for me.
It gives me an error with the ".level" and ".move" things, and when i replace them with the " & LEVEL_UP_MOVE_ID" and " & LEVEL_UP_MOVE_LV" that the original script uses, it just freezes when the Pokémon is learning the move...
I'm pretty sure I told you this in a different thread, but you seemed to be using an old version of Pokeemerald, at least back then.
Try it on the latest repository of Pokeemerald, it should work.
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
Set Trainer's Levels Dynamically POKEEMERALD
how to implement it?
just go to src/battle_main.c and inside of CreateNPCTrainerParty, define this:
	u8 reallevel = 0;
	u8 fixedLVL = 0;
	{
	if (GetMonData(&gPlayerParty[5], MON_DATA_SPECIES) != SPECIES_NONE)
		fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[1], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[2], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[3], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[4], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[5], MON_DATA_LEVEL)) / 6;
	else if ((GetMonData(&gPlayerParty[5], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[4], MON_DATA_SPECIES) != SPECIES_NONE))
			fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[3], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[4], MON_DATA_LEVEL)) / 5;
		else if ((GetMonData(&gPlayerParty[4], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[3], MON_DATA_SPECIES) != SPECIES_NONE))
			fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[3], MON_DATA_LEVEL)) / 4;
			else if ((GetMonData(&gPlayerParty[3], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[2], MON_DATA_SPECIES) != SPECIES_NONE))
				fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)) / 3;
				else if ((GetMonData(&gPlayerParty[2], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[1], MON_DATA_SPECIES) != SPECIES_NONE))
					fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)) / 2;
					else if ((GetMonData(&gPlayerParty[1], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[0], MON_DATA_SPECIES) != SPECIES_NONE))
						fixedLVL = GetMonData(&gPlayerParty[0], MON_DATA_LEVEL);
	}
Now, search "CreateMon(&party[i], partyData[i].species" and replace the whole line with this:
                CreateMon(&party[i], partyData[i].species, reallevel, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
now, right before those lines, put this:
			    {
					min = fixedLVL-2;
					max = fixedLVL+2;
				        range = max - min + 1;
				        rand = Random() % range;
				}

				if (min <=0)
					min=1;
				reallevel = min + rand;
now, modify the "-2" in the first one, and put a -4 or a -3 (this will be the minimum level that the trainer will have) and in the last one, change the +2 for a +3 or a +4.
this is for making regular trainers weaker and gym leaders, rivals and elite 4 stronger and making the game harder without having to grind so much... because you don't have to grind at all...

PD: I don't know if i can post this here, because it already has its own page but, i wanted to contribute
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
Set Wild Pokémon's Levels Dynamically POKEEEMERALD

And now, you'll learn how to make Wild Pokémon's level being around the same as yours, and is easier than trainer's one...
just go to
src\wild_encounter.c
and search this:
static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon)
Now, just replace this part:
    // Make sure minimum level is less than maximum level
    if (wildPokemon->maxLevel >= wildPokemon->minLevel)
    {
        min = wildPokemon->minLevel;
        max = wildPokemon->maxLevel;
    }
    else
    {
        min = wildPokemon->maxLevel;
        max = wildPokemon->minLevel;
    }
    range = max - min + 1;
    rand = Random() % range;
with this:
	u8 fixedLVL = 0;
	{
	if (GetMonData(&gPlayerParty[5], MON_DATA_SPECIES) != SPECIES_NONE)
		fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[1], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[2], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[3], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[4], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[5], MON_DATA_LEVEL)) / 6;
	else if ((GetMonData(&gPlayerParty[5], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[4], MON_DATA_SPECIES) != SPECIES_NONE))
			fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[3], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[4], MON_DATA_LEVEL)) / 5;
		else if ((GetMonData(&gPlayerParty[4], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[3], MON_DATA_SPECIES) != SPECIES_NONE))
			fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[3], MON_DATA_LEVEL)) / 4;
			else if ((GetMonData(&gPlayerParty[3], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[2], MON_DATA_SPECIES) != SPECIES_NONE))
				fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)) / 3;
				else if ((GetMonData(&gPlayerParty[2], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[1], MON_DATA_SPECIES) != SPECIES_NONE))
					fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)) / 2;
					else if ((GetMonData(&gPlayerParty[1], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[0], MON_DATA_SPECIES) != SPECIES_NONE))
						fixedLVL = GetMonData(&gPlayerParty[0], MON_DATA_LEVEL);
	}

    // Make sure minimum level is less than maximum level
    {
        min = fixedLVL-3;
        max = fixedLVL+3;
    }
	if (min <= 0)
		min = 1;
    range = max - min + 1;
    rand = Random() % range;
And that's it! now Wild Pokémon's levels will be minor by 3 or mayor by 3 to yours. if the "min" value is equal or minor than 0, it'll be set to one, just for the optimal calculations and a wild pokémon not having level 0 or 57.
Seen October 5th, 2021
Posted September 3rd, 2021
50 posts
4.5 Years
Set Wild Pokémon's Levels Dynamically POKEEEMERALD
Spoiler:
Set Wild Pokémon's Levels Dynamically POKEEEMERALD

And now, you'll learn how to make Wild Pokémon's level being around the same as yours, and is easier than trainer's one...
just go to

src\wild_encounter.c

and search this:

static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon)

Now, just replace this part:

// Make sure minimum level is less than maximum level
if (wildPokemon->maxLevel >= wildPokemon->minLevel)
{
min = wildPokemon->minLevel;
max = wildPokemon->maxLevel;
}
else
{
min = wildPokemon->maxLevel;
max = wildPokemon->minLevel;
}
range = max - min + 1;
rand = Random() % range;

with this:

u8 fixedLVL = 0;
{
if (GetMonData(&gPlayerParty[5], MON_DATA_SPECIES) != SPECIES_NONE)
fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[1], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[2], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[3], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[4], MON_DATA_LEVEL) + GetMonData(&gPlayerParty[5], MON_DATA_LEVEL)) / 6;
else if ((GetMonData(&gPlayerParty[5], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[4], MON_DATA_SPECIES) != SPECIES_NONE))
fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[3], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[4], MON_DATA_LEVEL)) / 5;
else if ((GetMonData(&gPlayerParty[4], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[3], MON_DATA_SPECIES) != SPECIES_NONE))
fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[3], MON_DATA_LEVEL)) / 4;
else if ((GetMonData(&gPlayerParty[3], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[2], MON_DATA_SPECIES) != SPECIES_NONE))
fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[2], MON_DATA_LEVEL)) / 3;
else if ((GetMonData(&gPlayerParty[2], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[1], MON_DATA_SPECIES) != SPECIES_NONE))
fixedLVL = (GetMonData(&gPlayerParty[0], MON_DATA_LEVEL)+GetMonData(&gPlayerParty[1], MON_DATA_LEVEL)) / 2;
else if ((GetMonData(&gPlayerParty[1], MON_DATA_SPECIES) == SPECIES_NONE) && (GetMonData(&gPlayerParty[0], MON_DATA_SPECIES) != SPECIES_NONE))
fixedLVL = GetMonData(&gPlayerParty[0], MON_DATA_LEVEL);
}

// Make sure minimum level is less than maximum level
{
min = fixedLVL-3;
max = fixedLVL+3;
}
if (min <= 0)
min = 1;
range = max - min + 1;
rand = Random() % range;

And that's it! now Wild Pokémon's levels will be minor by 3 or mayor by 3 to yours. if the "min" value is equal or minor than 0, it'll be set to one, just for the optimal calculations and a wild pokémon not having level 0 or 57.



Not to break you down, but your code can be a little improved. I assume your code calculates the mean and assign it to fixedLVL. It is untested but this version should essentially do the same as you posted:

static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon)
{
    u8 min;
    u8 max;
    u8 range;
    u8 rand;

    u8 count = gPlayerPartyCount;
    u8 fixedLVL = 0;

    while (count-- > 0)
    {
        if (GetMonData(&gPlayerParty[count], MON_DATA_SPECIES) != SPECIES_NONE){
            fixedLVL += (GetMonData(&gPlayerParty[count], MON_DATA_LEVEL);
        }
    }
    fixedLVL = fixedLVL / gPlayerPartyCount;
    

// Make sure minimum level is less than maximum level
    {
        min = fixedLVL-3;
        max = fixedLVL+3;
    }
	if (min <= 0)
		min = 1;
    range = max - min + 1; // note that range will always be equal to 7 in this case: fixedLVL+3 - (fixedLVL-3) + 1 = fixedLVL - fixedLVL + 3 +3 +1 = 7
    rand = Random() % range;

...
Emerald master race
Male
Seen 54 Minutes Ago
Posted 1 Day Ago
228 posts
5.9 Years
Remove Pokemon Data Encryption [Pokeemerald]
This will remove all of the (in my opinion) unecessary data encryption of the pokemon structure. So you can freely mess around with the size or individual elements.

in pokemon.c:
Spoiler:
line 58:
static union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u8 substructType);
line 3529:
static union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u8 substructType)
{
    union PokemonSubstruct *substructs = boxMon->secure.substructs;
    return &substructs[substructType];
}
line 3632:
u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data)
{
    s32 i;
    u32 retVal = 0;
    
    struct PokemonSubstruct0 *substruct0 = NULL;
    struct PokemonSubstruct1 *substruct1 = NULL;
    struct PokemonSubstruct2 *substruct2 = NULL;
    struct PokemonSubstruct3 *substruct3 = NULL;

    if (field > MON_DATA_ENCRYPT_SEPARATOR)
    {
        substruct0 = &(GetSubstruct(boxMon, 0)->type0);
        substruct1 = &(GetSubstruct(boxMon, 1)->type1);
        substruct2 = &(GetSubstruct(boxMon, 2)->type2);
        substruct3 = &(GetSubstruct(boxMon, 3)->type3);
    }

    switch (field)
    (etc...)
line 3977: remove the following
    if (field > MON_DATA_ENCRYPT_SEPARATOR)
        EncryptBoxMon(boxMon);
line 4031:
void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
{
    const u8 *data = dataArg;

    struct PokemonSubstruct0 *substruct0 = NULL;
    struct PokemonSubstruct1 *substruct1 = NULL;
    struct PokemonSubstruct2 *substruct2 = NULL;
    struct PokemonSubstruct3 *substruct3 = NULL;

    if (field > MON_DATA_ENCRYPT_SEPARATOR)
    {
        substruct0 = &(GetSubstruct(boxMon, 0)->type0);
        substruct1 = &(GetSubstruct(boxMon, 1)->type1);
        substruct2 = &(GetSubstruct(boxMon, 2)->type2);
        substruct3 = &(GetSubstruct(boxMon, 3)->type3);
    }

    switch (field)
    (etc...)
line 4295: remove the following
    if (field > MON_DATA_ENCRYPT_SEPARATOR)
    {
        boxMon->checksum = CalculateBoxMonChecksum(boxMon);
        EncryptBoxMon(boxMon);
    }
line 2203: remove the following
    checksum = CalculateBoxMonChecksum(boxMon);
    SetBoxMonData(boxMon, MON_DATA_CHECKSUM, &checksum);
    EncryptBoxMon(boxMon);
line 2745: you can remove the entire function, CalculateBoxMonChecksum, or remove boxMon->personality from the GetSubstruct function call



I also made a branch for simple repo pulling. Please report any errors.
Seen 25 Minutes Ago
Posted April 9th, 2021
787 posts
14.9 Years

Move Item [EM]



Adds a
MOVE
option to the
ITEM
menu which allows you to move held items directly between Pokémon in your party, instead of having to use the bag as a middle man.

I've had this up in my pokeemerald fork for a while, but I never got around to writing it up here. Since I originally made it, the relevant functions got actual names in pokeemerald, so I'm taking this as an opportunity to update it and post it here.

There's going to be multiple changes required across multiple files, so I'm going to try to keep them in a logical order that minimizes jumping between files. Also, at the end of each step, pokeemerald will still be in a compilable state if done properly.

In the code blocks throughout this post, new lines of code are highlighted with the color green. Red highlights denote deleted lines of code. If a line of code isn't highlighted either color, it is only included for context.

Adding the strings



In
include/strings.h
, add the following to the end of the file:

Spoiler:
extern const u8 gMenuText_Move[];
extern const u8 gText_MoveItemWhere[];
extern const u8 gText_XsYAnd[];
extern const u8 gText_XsYWereSwapped[];

#endif // GUARD_STRINGS_H


In
src/strings.c
, add the following to the end of the file:

Spoiler:

const u8 gMenuText_Move[] = _("MOVE");
const u8 gText_MoveItemWhere[] = _("Move item to where?");
const u8 gText_XsYAnd[] = _("{STR_VAR_1}'s\n{STR_VAR_2} and\l");
const u8 gText_XsYWereSwapped[] = _("{STR_VAR_1}'s\l{STR_VAR_2} were swapped!{PAUSE_UNTIL_PRESS}");


Adding the code



You'll need to add a forward declaration for
CursorCb_MoveItem
in
src/party_menu.c
, like so:

Spoiler:
static void CursorCb_Summary(u8);
static void CursorCb_Switch(u8);
static void CursorCb_Cancel1(u8);
static void CursorCb_Item(u8);
static void CursorCb_Give(u8);
static void CursorCb_TakeItem(u8);
static void CursorCb_MoveItem(u8);
static void CursorCb_Mail(u8);
static void CursorCb_Read(u8);
static void CursorCb_TakeMail(u8);
static void CursorCb_Cancel2(u8);
static void CursorCb_SendMon(u8);
static void CursorCb_Enter(u8);
static void CursorCb_NoEntry(u8);
static void CursorCb_Store(u8);
static void CursorCb_Register(u8);
static void CursorCb_Trade1(u8);
static void CursorCb_Trade2(u8);
static void CursorCb_Toss(u8);
static void CursorCb_FieldMove(u8);


At the end of
src/party_menu.c
, add the following:

Spoiler:

void CursorCb_MoveItemCallback(u8 taskId)
{
    u16 item1, item2;
    u8 buffer[100];

    if (gPaletteFade.active || sub_81221EC())
        return;

    switch (PartyMenuButtonHandler(&gPartyMenu.slotId2))
    {
    case 2:     // User hit B or A while on Cancel
        HandleChooseMonCancel(taskId, &gPartyMenu.slotId2);
        break;
    case 1:     // User hit A on a Pokemon
        // Pokemon can't give away items to eggs or themselves
        if (GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_IS_EGG)
            || gPartyMenu.slotId == gPartyMenu.slotId2)
        {
            PlaySE(SE_HAZURE);
            return;
        }

        PlaySE(SE_SELECT);
        gPartyMenu.action = PARTY_ACTION_CHOOSE_MON;

        // look up held items
        item1 = GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_HELD_ITEM);
        item2 = GetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_HELD_ITEM);

        // swap the held items
        SetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_HELD_ITEM, &item2);
        SetMonData(&gPlayerParty[gPartyMenu.slotId2], MON_DATA_HELD_ITEM, &item1);

        // update the held item icons
        UpdatePartyMonHeldItemSprite(
            &gPlayerParty[gPartyMenu.slotId],
            &sPartyMenuBoxes[gPartyMenu.slotId]
        );

        UpdatePartyMonHeldItemSprite(
            &gPlayerParty[gPartyMenu.slotId2],
            &sPartyMenuBoxes[gPartyMenu.slotId2]
        );

        // create the string describing the move
        if (item2 == ITEM_NONE)
        {
            GetMonNickname(&gPlayerParty[gPartyMenu.slotId2], gStringVar1);
            CopyItemName(item1, gStringVar2);
            StringExpandPlaceholders(gStringVar4, gText_PkmnWasGivenItem);
        }
        else
        {
            GetMonNickname(&gPlayerParty[gPartyMenu.slotId], gStringVar1);
            CopyItemName(item1, gStringVar2);
            StringExpandPlaceholders(buffer, gText_XsYAnd);

            StringAppend(buffer, gText_XsYWereSwapped);
            GetMonNickname(&gPlayerParty[gPartyMenu.slotId2], gStringVar1);
            CopyItemName(item2, gStringVar2);
            StringExpandPlaceholders(gStringVar4, buffer);
        }

        // display the string
        DisplayPartyMenuMessage(gStringVar4, TRUE);

        // update colors of selected boxes
        AnimatePartySlot(gPartyMenu.slotId2, 0);
        AnimatePartySlot(gPartyMenu.slotId, 1);

        // return to the main party menu
        schedule_bg_copy_tilemap_to_vram(2);
        gTasks[taskId].func = Task_UpdateHeldItemSprite;
        break;
    }
}

void CursorCb_MoveItem(u8 taskId)
{
    struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId];

    PlaySE(SE_SELECT);

    // delete old windows
    PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]);
    PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]);

    if (GetMonData(mon, MON_DATA_HELD_ITEM) != ITEM_NONE)
    {
        gPartyMenu.action = PARTY_ACTION_SWITCH;

        // show "Move item to where" in bottom left
        DisplayPartyMenuStdMessage(PARTY_MSG_MOVE_ITEM_WHERE);
        // update color of first selected box
        AnimatePartySlot(gPartyMenu.slotId, 1);

        // set up callback
        gPartyMenu.slotId2 = gPartyMenu.slotId;
        gTasks[taskId].func = CursorCb_MoveItemCallback;
    }
    else
    {
        // create and display string about lack of hold item
        GetMonNickname(mon, gStringVar1);
        StringExpandPlaceholders(gStringVar4, gText_PkmnNotHolding);
        DisplayPartyMenuMessage(gStringVar4, TRUE);

        // return to the main party menu
        schedule_bg_copy_tilemap_to_vram(2);
        gTasks[taskId].func = Task_UpdateHeldItemSprite;
    }
}


Open
include/constants/party_menu.h
, and look for
#define
s of the form
PARTY_MSG_WHATEVER
. We need to add a
#define
for
PARTY_MSG_MOVE_ITEM_WHERE
like so:

Spoiler:
#define PARTY_MSG_CHOOSE_MON                0
#define PARTY_MSG_CHOOSE_MON_OR_CANCEL      1
#define PARTY_MSG_CHOOSE_MON_AND_CONFIRM    2
#define PARTY_MSG_MOVE_TO_WHERE             3 
#define PARTY_MSG_TEACH_WHICH_MON           4
#define PARTY_MSG_USE_ON_WHICH_MON          5
#define PARTY_MSG_GIVE_TO_WHICH_MON         6
#define PARTY_MSG_NOTHING_TO_CUT            7
#define PARTY_MSG_CANT_SURF_HERE            8
#define PARTY_MSG_ALREADY_SURFING           9
#define PARTY_MSG_CURRENT_TOO_FAST          10
#define PARTY_MSG_ENJOY_CYCLING             11
#define PARTY_MSG_ALREADY_IN_USE            12
#define PARTY_MSG_CANT_USE_HERE             13
#define PARTY_MSG_NO_MON_FOR_BATTLE         14
#define PARTY_MSG_CHOOSE_MON_2              15
#define PARTY_MSG_NOT_ENOUGH_HP             16
#define PARTY_MSG_X_MONS_ARE_NEEDED         17
#define PARTY_MSG_MONS_CANT_BE_SAME         18
#define PARTY_MSG_NO_SAME_HOLD_ITEMS        19
#define PARTY_MSG_UNUSED                    20
#define PARTY_MSG_DO_WHAT_WITH_MON          21
#define PARTY_MSG_RESTORE_WHICH_MOVE        22
#define PARTY_MSG_BOOST_PP_WHICH_MOVE       23
#define PARTY_MSG_DO_WHAT_WITH_ITEM         24
#define PARTY_MSG_DO_WHAT_WITH_MAIL         25
#define PARTY_MSG_ALREADY_HOLDING_ONE       26
#define PARTY_MSG_MOVE_ITEM_WHERE           27
#define PARTY_MSG_NONE                      127


Updating relevant data



Everything from here on will be in
src/data/party_menu.h
.

Look for an unnamed
enum
with values such as
MENU_SUMMARY
. Add
MENU_MOVE_ITEM
to the
enum
's list of values, like so:

Spoiler:
enum
{
    MENU_SUMMARY,
    MENU_SWITCH,
    MENU_CANCEL1,
    MENU_ITEM,
    MENU_GIVE,
    MENU_TAKE_ITEM,
    MENU_MOVE_ITEM,
    MENU_MAIL,
    MENU_TAKE_MAIL,
    MENU_READ,
    MENU_CANCEL2,
    MENU_SHIFT,
    MENU_SEND_OUT,
    MENU_ENTER,
    MENU_NO_ENTRY,
    MENU_STORE,
    MENU_REGISTER,
    MENU_TRADE1,
    MENU_TRADE2,
    MENU_TOSS,
    MENU_FIELD_MOVES,
};


Now, we need to add an entry to the
sCursorOptions
array. Add an entry for
MENU_MOVE_ITEM
like so:

Spoiler:
struct
{
    const u8 *text;
    TaskFunc func;
} static const sCursorOptions[] =
{
    [MENU_SUMMARY] = {gText_Summary5, CursorCb_Summary},
    [MENU_SWITCH] = {gText_Switch2, CursorCb_Switch},
    [MENU_CANCEL1] = {gText_Cancel2, CursorCb_Cancel1},
    [MENU_ITEM] = {gText_Item, CursorCb_Item},
    [MENU_GIVE] = {gMenuText_Give, CursorCb_Give},
    [MENU_TAKE_ITEM] = {gText_Take, CursorCb_TakeItem},
    [MENU_MOVE_ITEM] = {gMenuText_Move, CursorCb_MoveItem},
    [MENU_MAIL] = {gText_Mail, CursorCb_Mail},
    [MENU_TAKE_MAIL] = {gText_Take2, CursorCb_TakeMail},
    [MENU_READ] = {gText_Read2, CursorCb_Read},
    [MENU_CANCEL2] = {gText_Cancel2, CursorCb_Cancel2},
    [MENU_SHIFT] = {gText_Shift, CursorCb_SendMon},
    [MENU_SEND_OUT] = {gText_SendOut, CursorCb_SendMon},
    [MENU_ENTER] = {gText_Enter, CursorCb_Enter},
    [MENU_NO_ENTRY] = {gText_NoEntry, CursorCb_NoEntry},
    [MENU_STORE] = {gText_Store, CursorCb_Store},
    [MENU_REGISTER] = {gText_Register, CursorCb_Register},
    [MENU_TRADE1] = {gText_Trade4, CursorCb_Trade1},
    [MENU_TRADE2] = {gText_Trade4, CursorCb_Trade2},
    [MENU_TOSS] = {gMenuText_Toss, CursorCb_Toss},
    [MENU_FIELD_MOVES + FIELD_MOVE_CUT] = {gMoveNames[MOVE_CUT], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_FLASH] = {gMoveNames[MOVE_FLASH], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_ROCK_SMASH] = {gMoveNames[MOVE_ROCK_SMASH], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_STRENGTH] = {gMoveNames[MOVE_STRENGTH], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_SURF] = {gMoveNames[MOVE_SURF], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_FLY] = {gMoveNames[MOVE_FLY], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_DIVE] = {gMoveNames[MOVE_DIVE], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_WATERFALL] = {gMoveNames[MOVE_WATERFALL], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_TELEPORT] = {gMoveNames[MOVE_TELEPORT], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_DIG] = {gMoveNames[MOVE_DIG], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_SECRET_POWER] = {gMoveNames[MOVE_SECRET_POWER], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_MILK_DRINK] = {gMoveNames[MOVE_MILK_DRINK], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_SOFT_BOILED] = {gMoveNames[MOVE_SOFT_BOILED], CursorCb_FieldMove},
    [MENU_FIELD_MOVES + FIELD_MOVE_SWEET_SCENT] = {gMoveNames[MOVE_SWEET_SCENT], CursorCb_FieldMove},
};


Next, find the definition of
sActionStringTable
. Add an entry to the end like so:

Spoiler:
static const u8 *const sActionStringTable[] =
{
    [PARTY_MSG_CHOOSE_MON]             = gText_ChoosePokemon,
    [PARTY_MSG_CHOOSE_MON_OR_CANCEL]   = gText_ChoosePokemonCancel,
    [PARTY_MSG_CHOOSE_MON_AND_CONFIRM] = gText_ChoosePokemonConfirm,
    [PARTY_MSG_MOVE_TO_WHERE]          = gText_MoveToWhere,
    [PARTY_MSG_TEACH_WHICH_MON]        = gText_TeachWhichPokemon,
    [PARTY_MSG_USE_ON_WHICH_MON]       = gText_UseOnWhichPokemon,
    [PARTY_MSG_GIVE_TO_WHICH_MON]      = gText_GiveToWhichPokemon,
    [PARTY_MSG_NOTHING_TO_CUT]         = gText_NothingToCut,
    [PARTY_MSG_CANT_SURF_HERE]         = gText_CantSurfHere,
    [PARTY_MSG_ALREADY_SURFING]        = gText_AlreadySurfing,
    [PARTY_MSG_CURRENT_TOO_FAST]       = gText_CurrentIsTooFast,
    [PARTY_MSG_ENJOY_CYCLING]          = gText_EnjoyCycling,
    [PARTY_MSG_ALREADY_IN_USE]         = gText_InUseAlready_PM,
    [PARTY_MSG_CANT_USE_HERE]          = gText_CantUseHere,
    [PARTY_MSG_NO_MON_FOR_BATTLE]      = gText_NoPokemonForBattle,
    [PARTY_MSG_CHOOSE_MON_2]           = gText_ChoosePokemon2,
    [PARTY_MSG_NOT_ENOUGH_HP]          = gText_NotEnoughHp,
    [PARTY_MSG_X_MONS_ARE_NEEDED]      = gText_PokemonAreNeeded,
    [PARTY_MSG_MONS_CANT_BE_SAME]      = gText_PokemonCantBeSame,
    [PARTY_MSG_NO_SAME_HOLD_ITEMS]     = gText_NoIdenticalHoldItems,
    [PARTY_MSG_UNUSED]                 = gText_EmptyString2,
    [PARTY_MSG_DO_WHAT_WITH_MON]       = gText_DoWhatWithPokemon,
    [PARTY_MSG_RESTORE_WHICH_MOVE]     = gText_RestoreWhichMove,
    [PARTY_MSG_BOOST_PP_WHICH_MOVE]    = gText_BoostPp,
    [PARTY_MSG_DO_WHAT_WITH_ITEM]      = gText_DoWhatWithItem,
    [PARTY_MSG_DO_WHAT_WITH_MAIL]      = gText_DoWhatWithMail,
    [PARTY_MSG_ALREADY_HOLDING_ONE]    = gText_AlreadyHoldingOne,
    [PARTY_MSG_MOVE_ITEM_WHERE]        = gText_MoveItemWhere,
};


And finally, we need to adjust the
ITEM
menu so that it actually includes our new menu option.

Find the definition of
sPartyMenuAction_GiveTakeItemCancel
, and modify it:

Spoiler:
static const u8 sPartyMenuAction_GiveTakeItemCancel[] = {MENU_GIVE, MENU_TAKE_ITEM, MENU_CANCEL2};
static const u8 sPartyMenuAction_GiveTakeItemCancel[] = {MENU_GIVE, MENU_TAKE_ITEM, MENU_MOVE_ITEM, MENU_CANCEL2};


Find the definition of
sItemGiveTakeWindowTemplate
and modify it:

Spoiler:
static const struct WindowTemplate sItemGiveTakeWindowTemplate =
{
    .bg = 2,
    .tilemapLeft = 23,
    .timemapTop = 13,
    .tilemapTop = 11,
    .width = 6,
    .height = 6,
    .height = 8,
    .paletteNum = 14,
    .baseBlock = 0x39D,
};


And that's it. Let me know if you have problems.

Edit: Oh, since I forgot to mention, my code here is licensed under the 0BSD license. In short, use it for whatever. Attribution is appreciated, but not required.

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
Nicknaming as an option in the Pokémon Party Screen (Emerald)

This code allows you to change the nickname of a Pokémon in your party on the Pokémon Party Screen with a new option called "Nickname".
Honestly, the idea of requiring the service of an NPC in X Town or City to change a Pokémon's nickname is silly.
You should always be able to nickname your own Pokémon, in my opinion.

The code can be found in this commit, it's super easy stuff.
https://github.com/shinny456/pokeemerald/commit/c92e5861e3ba85abaf53af81aa0bb70acae505af

Quick demonstration:


Bugs:
-You can't nickname a Pokémon that knows 4 Field Moves
To fix this, simply change u8 actions[8]; in the Line 123 of src/party_menu.c to u8 actions[9]; instead.
Credits to Ghoulslash for this fix.

Improvements:
-Hide the "Nickname" option in the party screen's context menu for Pokémon whose OT ID doesn't match the Player's
Read this post: https://www.pokecommunity.com/showpost.php?p=10376476&postcount=279
Credits to TheXaman for that.

-Make the naming screen return to the party screen instead of the overworld
Apply the changes shown here: https://github.com/LOuroboros/pokeemerald/commit/7273fae0afe6026bb7561cc9ff67aa750617aadc

The credits for this feature go to Shinny456. I'm just reposting it here because he wanted to share it with y'all.

And that's pretty much it.
Male
Seen 54 Minutes Ago
Posted 1 Day Ago
228 posts
5.9 Years
[Emerald] Item Descriptions On First Obtain

Recent games included a description of an item when you obtain it for the first time. This adds that feature to pokeemerald. it also adds the item icon to your message box on subsequent events.



Here is my repo branch.

How to Add:
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
POKEEMERALD

Set a Trainer's Pokémon's abilities

For doing this, we'll have first to set the option in include/data.h
We search for
TrainerMonNoItemDefaultMoves
(line 17) and we add in the ones which we want to add abilities (if you want to code more, you can make new ones for setting and not setting the ability...)
Therefore, we add this at the end, before the "};":
u8 abilityNums;
Like this:

We're done with this, we have to go to src/battle_main.c
We add this in every "TrainerMon" that we added the abilityNums:
Before the "break":
SetMonData(&party[i], MON_DATA_ABILITY_NUM, &partyData[i].abilityNums);
Like this:


Then, were ready to set Trainer's Pokémon's abilities in src/data/trainer_parties.h!
We will have to set the abilities to every single Pokémon of each Trainer of each "TrainerMon" we add the abilityNums, if you added new "TrainerMon", just create new Trainer for setting their Pokémon's abilities!
This is the most boring part, we'll need to add ".abilityNums =x," which x is "0=fist ability", "1=secondary ability" and (again, just if you have it) "2=hidden ability"
Like this:


Then, when you're done with that, you'll need to add a "comma" in the line before the ".abilityNums = x" one.
It happens mostly in the "TrainerMonItemDefaultMoves" and the "TrainerMonNoItemCustomMoves", tho...


PD: you'll have ALWAYS to add the .abilityNums = x for every Trainer's Pokémon that you added at first. Like, if you add this sistem just for "TrainerMonItemCustomMoves", you won't have to and DO NOT have to add this to the "TrainerMonNoItemDefaultMoves", for example.
When we're done with that, we successfully added the option to set a Trainer's Pokémon's ability!
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
POKEEMERALD
PSS IN THE START MENU
First, we add a new Flag in include/constants/flags.h
FLAG_POKEMONPCMENU
(this will be used after)
Then, we go to include/pokemon_storage_system.h
There, we add anywhere:
void Cb2_EnterPSS(u8 boxOption);
Then we go to src/pokemon_storage_system.c, and we delete
static void Cb2_EnterPSS(u8 boxOption);
(when its definied, the first one)
and we search for "static void Cb2_EnterPSS(u8 boxOption) ", then we erase the "static " (the second one)
Then, we search for:
static void FieldCb_ReturnToPcMenu(void)
And we replace it entirely for this:
static void FieldCb_ReturnToPcMenu(void)
{
    u8 taskId;
    MainCallback vblankCb = gMain.vblankCallback;
	if (FlagGet(FLAG_POKEMONPCMENU)==TRUE)
	{
		SetVBlankCallback(NULL);
		taskId = CreateTask(Task_PokemonStorageSystemPC, 80);
		gTasks[taskId].data[0] = 0;
		gTasks[taskId].data[1] = sPreviousBoxOption;
		Task_PokemonStorageSystemPC(taskId);
		SetVBlankCallback(vblankCb);
		FadeInFromBlack();
	}
	else
	{
	    SetVBlankCallback(CB2_ReturnToField);
		FadeInFromBlack();
		DisableInterrupts(FLAG_POKEMONPCMENU);
	}
}
Then, we go to src/start_menu.c, and we search for: static bool8 StartMenuBagCallback(void);, and right after, we add:
static bool8 StartMenuPCCallback(void);
Then, we go to "{gText_MenuBag, {.u8_void = StartMenuBagCallback}}," and again we add bellow:
{gText_MenuPC, {.u8_void = StartMenuPCCallback}},
Then, we go to "static bool8 StartMenuBagCallback(void)" and after the whole funcion we add:
static bool8 StartMenuPCCallback(void)
{
	u8 taskId;
    if (!gPaletteFade.active)
    {
        PlayRainStoppingSoundEffect();
        RemoveExtraStartMenuWindows();
		Cb2_EnterPSS(x);
        return TRUE;
    }

    return FALSE;
}
(in my case, its "0" the number for the Move Pokémon System, but I have made some changes {I changed the Move option to the first place}, and I'm sure the original number for the option is "2"...)

Then, we search for: "MENU_ACTION_BAG"
And after we add: "MENU_ACTION_PC,"

Now we go to: "if (FlagGet(FLAG_SYS_POKEMON_GET) == TRUE)" and inside there we add:
AddStartMenuAction(MENU_ACTION_PC);
Like this:
    if (FlagGet(FLAG_SYS_POKEMON_GET) == TRUE)
    {
        AddStartMenuAction(MENU_ACTION_POKEMON);
		AddStartMenuAction(MENU_ACTION_PC);
    }
Then, we go to "AddStartMenuAction(MENU_ACTION_BAG);" and right after we add:
AddStartMenuAction(MENU_ACTION_PC);

Then, we go to data/scripts/pc.inc and we add this after "playse SE_PC_ON" in "EventScript_PC:: @ 8271D92":
setflag FLAG_POKEMONPCMENU
Now, after "special DoPCTurnOffEffect", in "EventScript_TurnOffPC:: @ 8271E47" we add:
clearflag FLAG_POKEMONPCMENU

Lastly, we need to add the strings for the PC in the Start Menu, (thanks, Lunos)
We go to include/strings.h and we add this somewhere:

extern const u8 gText_MenuPC[];

And this is the last step. We go to src/strings.c and we add this somewhere:
const u8 gText_MenuPC[] = _("PC");

And we're done! this time, we are We should be able to enter the Move Pokémon PC, and the Pokécenter PC's won't be affected.

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Seen 8 Hours Ago
Posted 8 Hours Ago
2,889 posts
13.3 Years
POKEEMERALD
PSS IN THE START MENU
You forgot to mention that the user needs to define the text for gText_MenuPC in include/strings.h and src/strings.c
Also, you can't really deposit Pokémon, for some reason. Not sure if it's intentional or not, but I thought I should mention it.
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
You forgot to mention that the user needs to define the text for gText_MenuPC in include/strings.h and src/strings.c
Oh, you're right. I totally forgot about that, thank you!

Also, you can't really deposit Pokémon, for some reason. Not sure if it's intentional or not, but I thought I should mention it.
Actually, that happens because of this: Cb2_EnterPSS(x);
Where "x" is a number between 0 and 2 if I recall, I think the number should be "2" in a game without the implementation of this: Move as first PSS Option, because I'm sure the reason because you can't deposite Pokémon is that you put the "Withdraw" option in "Cb2_EnterPSS(x);" (And would be nice if you say what number it is, maybe it could be helpfull)
Seen 4 Days Ago
Posted 5 Days Ago
158 posts
4.4 Years
"Move Pokémon" as first PSS option [EM]

In "src/pokemon_storage_system.c", change the order of this:
Spoiler:

and this:
Spoiler:

and below switch(task->data[2]) in Task_PokemonStorageSystemPC change these two:
Spoiler:
Yeah, that's cool but... Something happens when you do this...
You can't press the "B" button while on the "Deposit Pokémon" option, which softlockes the game, as you can't go back, you're stuck in the Deposite Option...