Advertiser Content

[DECOMP] Simple Modifications Directory

Started by Avara December 30th, 2018 2:48 PM
  • 2387 views
  • 19 replies

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Decomp Simple Modifications Directory
-----------------------------------------------------------------------------------------------------------------------------------------------------
This thread can hopefully be used to host instructions for a variety of small changes to pokéemerald (or pokéruby) that are much too short/simple to justify having their own thread/their own page on their respective wiki. Contributions can then be listed in this post for the sake of simplicity. Please test to ensure your implementation works before submitting!
If you can think of a small edit you'd like to be added to this list, go ahead and leave a comment, with a bit of luck it will help to encourage more rom hackers to switch to the decomps <3
-----------------------------------------------------------------------------------------------------------------------------------------------------

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Editing Player PC Items

To change the items the player has in their PC at the start of the game, open “src\player_pc.c” in Notepad++ and find the following:



Ctrl+F "POTION" to locate it quickly. It's self-explanatory - on the left you have the item and on the right you have the amount. Just make sure you don't accidentally overwrite the “{ ITEM_NONE, 0 }” line. For example, if I wanted my player to have five Sitrus Berries and three Lum Berries in their PC at the beginning of the game, I'd have:



A list of items can be found in “include\constants\items.h

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Modifying Starter Pokémon

To change the three starters in less than 30 seconds, open “src\starter_choose.c” in Notepad++ and Ctrl+F "TREECKO" to find the following section quickly:



You've probably guessed what to do already - just change the species names. If you wanted the Johto starters, you could have:



Compile and you're all set.

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Changing the Beginning Amount of Money

For Pokéemerald, open “src\new_game.c” and look for this line:
SetMoney(&gSaveBlock1Ptr->money, 3000);
All there is to do is change that amount (3000) to whatever you like. For Pokéruby, it's the same file but this line:
gSaveBlock1.money = 3000;

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Editing Default Options Settings

If you open “src\new_game.c” you'll come across this:



These are the attributes you can change from the "Options" window in the start menu - text speed, the menu frame, battle style (set/shift) etc. Having the text speed automatically set to fast is something I'd recommend to everyone, since going straight to the options menu and changing it is one of the first things a lot of people do in-game!

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Changing Birch's Intro Pokémon

Open “src\main_menu.c” and Ctrl+F for “SPECIES_LOTAD”. Modify the following lines to change the sprite and cry:





The Pokémon species list is in “include\constants\species.h”. For Pokéruby, substitute the instances of “SPECIES_LOTAD” for “SPECIES_AZURILL”. I've changed it to Trapinch, for example:

paccy

Pokeholic

Male
'Straya
Online now
Posted February 16th, 2019
4 posts
10 Years
Reusable TMs

To make TMs reusable open "src/party_menu.c" and search for the sub_81B6EB4 function.
In it delete the lines
if (item < ITEM_HM01_CUT)
    RemoveBagItem(item, 1);
If you also want to make TMs unholdable and remove the number from the bag saying how many of each TM you have open "src/data/items.h" and change the .importance number of each TM item from 0 to 1.

Avara

Author of Tales

Female
Izantine
Seen 12 Hours Ago
Posted 19 Hours Ago
1,029 posts
7.5 Years
Modifying the Start Location

Open “src\new_game.c”and look for the following section:
static void WarpToTruck(void)
{
    SetWarpDestination(MAP_GROUP(INSIDE_OF_TRUCK), MAP_NUM(INSIDE_OF_TRUCK), -1, -1, -1);
    WarpIntoMap();
}
The line in red is the one we want to make changes to as you could probably already tell. It's self explanatory so it shouldn't need very much breaking down. For instance, let's say we wanted the start map to be Oldale Town. We would have:
SetWarpDestination(MAP_GROUP(OLDALE_TOWN), MAP_NUM(OLDALE_TOWN), -1, 6, 18);
The above will have the player start in Oldale Town, specifically outside the Pokémon Center. -1 is used for no warp ID, 6, 18 are co-ordinates. Something different, say you wanted the player to start off in the middle of May's room:
SetWarpDestination(MAP_GROUP(LITTLEROOT_TOWN_MAYS_HOUSE_2F), MAP_NUM(LITTLEROOT_TOWN_MAYS_HOUSE_2F), -1, -1, -1);
Using “-1, -1, -1” as the default does will place the player in the center of the map. That's it!
Oh and to remove the truck animation, again you only have to tweak a single line, this time in “src\overworld.c”:
// gFieldCallback = ExecuteTruckSequence;

DizzyEgg

Age 21
Male
Poland
Seen 20 Hours Ago
Posted 3 Days Ago
768 posts
5.3 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;
    u8 windowId;
    int width = 0;
    u8 newWidth;

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

    newWidth = convert_pixel_width_to_tile_width(width);
    left = sub_80E2D5C(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);
    sub_80E1FBC(ignoreBPress, count, windowId, multichoiceId);
}

static void DrawMultichoiceMenu(u8 left, u8 top, u8 multichoiceId, u8 ignoreBPress, u8 cursorPos)
{
    DrawMultichoiceMenuCustom(left, top, multichoiceId, ignoreBPress, cursorPos, gMultichoiceLists[multichoiceId].list, gMultichoiceLists[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/event_script.s EventScript_RepelWoreOff
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.

DizzyEgg

Age 21
Male
Poland
Seen 20 Hours Ago
Posted 3 Days Ago
768 posts
5.3 Years
Money Limit
Spoiler:

In this example, I'll be moving the cap to 9 999 999.

To change max possible money amount, go to
src/money.c
At line 13,
#define MAX_MONEY 9999999
At line 135
PrintMoneyAmount(windowId, 0x20, 1, amount, speed);
At line 143
ConvertIntToDecimalStringN(gStringVar1, amount, STR_CONV_MODE_LEFT_ALIGN, 7);
At line 145
strLength = 7 - StringLength(gStringVar1);
In
src/shop.c
At line 1148
PrintMoneyAmount(4, 32, 1, gShopDataPtr->totalCost, TEXT_SPEED_FF);
And in
src/trainer_card.c
At line 1014
ConvertIntToDecimalStringN(gStringVar1, sData->trainerCard.money, 0, 7);
Things that were changed were respectively, max money amount, x position on the money box and max digits(previously 6, now 7).

If you'd like to go above 7 digits, simply change the 7 to 8 and the x position argument from 0x20 to
0x1A.

Screenshots:
Spoiler:




I also have the code in my github branch called money, so you can pull directly from it.

Lunos

Random Uruguayan User

Male
Montevideo (Uruguay)
Online now
Posted 23 Hours Ago
1,897 posts
10.6 Years
-Snip-
I'm not entirely sure if I'm going OffTopic here, but while this implementation works perfectly on itself, it introduces one issue.
You can teach a TM to a pokémon, and the PPs for that move slot will refill as the pokémon learns a new move.
This kinda removes the necessity of healing when/if you run out of PPs in some of all of your moves.

ON: So, if we're talking about quick modifications, I have to give some love to my favourite ability.

Modifying the table of items of the Pickup ability

(outside of the Battle Pyramid)

To do this, we're going to open the src\battle_script_commands.c file.
Next, we'll take a look at the sPickupItems variable in the Line 824.
What it contains is a list of the items the Player can obtain with a 4%, 10% or 30% chances every time they faint a pokémon, if a Pickup user is in their party.


Right after it, we have the variable sRarePickupItems, which similarly, also contains a list of items.
These are the items that the Player has a 1% chance of obtaining, every time they faint a pokémon, if a Pickup user is in their party.


To modify any of these lists, you simply have to swap the defined item/s that you want to replace with a different one of your liking, save and compile.

Here's a quick video, where I replaced all the common items (those in the 1st list) with Master Balls.


I haven't looked into the separate table used for the Battle Pyramid, so I won't go into details with that one, but it looks fairly simple.
Any curious people can find them (Lv50 and Open) starting from the Line 317 of the src\battle_pyramid.c file.

DizzyEgg

Age 21
Male
Poland
Seen 20 Hours Ago
Posted 3 Days Ago
768 posts
5.3 Years
Scrolling Multichoices In Scripts

I was asked to implement this, so here it goes. Just so you know, scrolling lists are already coded in, they're called list menus in pokeemerald. Check out list_menu.h and list_menu.c.

Spoiler:

I put the code in script_menu.c, but you can put it whenever you want.
At the top of file make sure to include the header for the list menu. Add this.
#include "list_menu.h"
At the end of the file paste all this code.
Spoiler:

// Text displayed as options.
static const u8 sText_Example1[] = _("Example 1");
static const u8 sText_Example2[] = _("Example 2");
static const u8 sText_Example3[] = _("Example 3");
static const u8 sText_Example4[] = _("Example 4");
static const u8 sText_Example5[] = _("Example 5");
static const u8 sText_Example6[] = _("Example 6");
static const u8 sText_Example7[] = _("Example 7");
static const u8 sText_Example8[] = _("Example 8");
static const u8 sText_Example9[] = _("Example 9");

// Sets of multichoices.
static const struct ListMenuItem sSet1[] =
{
    {sText_Example1, 0},
    {sText_Example2, 1},
    {sText_Example3, 2},
    {sText_Example4, 3},
    {sText_Example5, 4},
    {sText_Example6, 5},
    {sText_Example7, 6},
    {sText_Example8, 7},
    {sText_Example9, 8},
};

static const struct ListMenuItem sSet2[] =
{
    {sText_Example9, 0},
    {sText_Example8, 1},
    {sText_Example7, 2},
    {sText_Example6, 3},
    {sText_Example5, 4},
    {sText_Example4, 5},
    {sText_Example3, 6},
    {sText_Example2, 7},
    {sText_Example1, 8},
};

// Table of your multichoice sets.
struct
{
    const struct ListMenuItem *set;
    int count;
} static const sScrollingSets[] =
{
    {sSet1, ARRAY_COUNT(sSet1)},
    {sSet2, ARRAY_COUNT(sSet2)},
};

static void Task_ScrollingMultichoiceInput(u8 taskId);

static const struct ListMenuTemplate sMultichoiceListTemplate =
{
    .header_X = 0,
    .item_X = 8,
    .cursor_X = 0,
    .upText_Y = 1,
    .cursorPal = 2,
    .fillValue = 1,
    .cursorShadowPal = 3,
    .lettersSpacing = 1,
    .itemVerticalPadding = 0,
    .scrollMultiple = LIST_NO_MULTIPLE_SCROLL,
    .fontId = 1,
    .cursorKind = 0
};

// 0x8004 = set id
// 0x8005 = window X
// 0x8006 = window y
// 0x8007 = showed at once
// 0x8008 = Allow B press
void ScriptMenu_ScrollingMultichoice(void)
{
    int i, windowId, taskId, width = 0;
    int setId = gSpecialVar_0x8004;
    int left = gSpecialVar_0x8005;
    int top = gSpecialVar_0x8006;
    int maxShowed = gSpecialVar_0x8007;

    for (i = 0; i < sScrollingSets[setId].count; i++)
        width = display_text_and_get_width(sScrollingSets[setId].set[i].name, width);

    width = convert_pixel_width_to_tile_width(width);
    left = sub_80E2D5C(left, width);
    windowId = CreateWindowFromRect(left, top, width, maxShowed * 2);
    SetStandardWindowBorderStyle(windowId, 0);
    CopyWindowToVram(windowId, 3);

    gMultiuseListMenuTemplate = sMultichoiceListTemplate;
    gMultiuseListMenuTemplate.windowId = windowId;
    gMultiuseListMenuTemplate.items = sScrollingSets[setId].set;
    gMultiuseListMenuTemplate.totalItems = sScrollingSets[setId].count;
    gMultiuseListMenuTemplate.maxShowed = maxShowed;

    taskId = CreateTask(Task_ScrollingMultichoiceInput, 0);
    gTasks[taskId].data[0] = ListMenuInit(&gMultiuseListMenuTemplate, 0, 0);
    gTasks[taskId].data[1] = gSpecialVar_0x8008;
    gTasks[taskId].data[2] = windowId;
}

static void Task_ScrollingMultichoiceInput(u8 taskId)
{
    bool32 done = FALSE;
    s32 input = ListMenu_ProcessInput(gTasks[taskId].data[0]);

    switch (input)
    {
    case LIST_HEADER:
    case LIST_NOTHING_CHOSEN:
        break;
    case LIST_CANCEL:
        if (gTasks[taskId].data[1])
        {
            gSpecialVar_Result = 0x7F;
            done = TRUE;
        }
        break;
    default:
        gSpecialVar_Result = input;
        done = TRUE;
        break;
    }

    if (done)
    {
        DestroyListMenuTask(gTasks[taskId].data[0], NULL, NULL);
        ClearStdWindowAndFrame(gTasks[taskId].data[2], TRUE);
        RemoveWindow(gTasks[taskId].data[2]);
        EnableBothScriptContexts();
        DestroyTask(taskId);
    }
}

Then, add this macro at the end of asm/macros/event.inc.
Spoiler:
	.macro scrollingmultichoice id:req, x:req, y:req, show:req, b:req
	setvar VAR_0x8004, \id,
	setvar VAR_0x8005, \x,
	setvar VAR_0x8006, \y,
	setvar VAR_0x8007, \show,
	setvar VAR_0x8008, \b,
	callnative ScriptMenu_ScrollingMultichoice
	waitstate
	.endm

How to use it? I provided two example sets of multichoices. Let me explain.
Spoiler:

Under the // Text displayed as options. comment I put all the strings that are displayed as options. Now, you may put the strings at any location, but keep in mind if the file location is different, you'll need to extern them.
Spoiler:
static const u8 sText_Example1[] = _("Example 1");
static const u8 sText_Example2[] = _("Example 2");
static const u8 sText_Example3[] = _("Example 3");
static const u8 sText_Example4[] = _("Example 4");
static const u8 sText_Example5[] = _("Example 5");


Then, under the // Sets of multichoices. comment I put all the sets of multichoices. What I mean by that is simply the options the player will be able to choose from. The syntax is simple, string name and id. The id is basically what you'll get in gSpecialVar_Result after the player chooses.
Spoiler:
static const struct ListMenuItem sSet1[] =
{
    {sText_Example1, 0},
    {sText_Example2, 1},
    {sText_Example3, 2},
    {sText_Example4, 3},
    {sText_Example5, 4},
    {sText_Example6, 5},
    {sText_Example7, 6},
    {sText_Example8, 7},
    {sText_Example9, 8},
};


And finally we have // Table of your multichoice sets. comment. As you may guess, this is the table with pointers to the multichoice sets along with the information how many options there are. Syntax is simple, set name and the number of options to choose from(I used a handy macro and advise you to do the same.)
Spoiler:
struct
{
    const struct ListMenuItem *set;
    int count;
} static const sScrollingSets[] =
{
    {sSet1, ARRAY_COUNT(sSet1)},
    {sSet2, ARRAY_COUNT(sSet2)},
};

Calling it from a script is simple, just use the macro you just put. The arguments are:
- set id(sScrollingSets table)
- window x
- window y
- amount of options showed at once on window
- whether the player can press B(if TRUE, the return value is 0x7F just as from normal multichoice)
Whichever option the player chooses is stored in gSpecialVar_Result.

Example:
scrollingmultichoice 1, 2, 3, 5, TRUE




I also have the code in my github branch called script_multichoice, so you can pull directly from it.

Petuuuhhh

Age 25
Male
Georgia
Seen 5 Hours Ago
Posted 2 Weeks Ago
613 posts
2.1 Years
Disable Trade Restrictions (EM)

This is untested, but I believe this works.

Spoiler:
Ctrl + F "IsNationalPokedexEnabled" in trade.c

You'll find
    if (!IsNationalPokedexEnabled())
    {
        if (gUnknown_0203229C->unk_51[1][a3] || !IsSpeciesInHoennDex(species))
        {
            return 2;
        }
    }
Delete this.

Then, find
    if (!IsNationalPokedexEnabled())
    {
        if (species2[monIdx] == SPECIES_EGG)
        {
            return 3;
        }

        if (!IsSpeciesInHoennDex(species2[monIdx]))
        {
            return 2;
        }
    }
Delete this as well.

Now you should be able to trade with FRLG without having the National Dex!


Disabled Disobedience (EM)

This is also untested, but I believe this also works.

Spoiler:
Ctrl + F "static void atk00_attackcanceler(void)" in battle_script_commands.c until you get the function details. Then, find
    if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
    {
        i = IsMonDisobedient(); // why use the 'i' variable...?
        switch (i)
        {
        case 0:
            break;
        case 2:
            gHitMarker |= HITMARKER_OBEYS;
            return;
        default:
            gMoveResultFlags |= MOVE_RESULT_MISSED;
            return;
        }
    }
Delete this.

Now your mon should obey you at any level!


Update Moves to Gen 7 Standards (C), except for targeting, contact, priority, move interaction, and Mirror Move

Seen March 23rd, 2019
Posted March 9th, 2019
3 posts
178 Days
Running Indoors (EM)


Simply remove the following from /src/bike.c and you should be able to use your running shoes inside any building.

Inside the file search for:
bool32 IsRunningDisallowed(u8 metatile)
and delete the following:
!(gMapHeader.flags & 4) ||
Thats it, now you should be good to go (or run in this case).
Seen March 23rd, 2019
Posted March 9th, 2019
3 posts
178 Days
Surviving poison outside of battle with 1hp


With just a few steps your pokemon should survive poison on the overworld now with 1hp, like in later gens.

Open the file /src/field_poison.c
Spoiler:

Find the following function:
s32 DoPoisonFieldEffect(void)
Simply add:
u32 numSurvived = 0;
Then find this code inside:
if(hp == 0 || --hp == 0)
and change the whole if-statement to:
if (hp == 1 || --hp == 1)
{
	u32 status = STATUS1_NONE;
	SetMonData(pokemon, MON_DATA_STATUS, &status);
	numSurvived++;
	ScriptContext1_SetupScript(EventScript_PoisonSurvial);
}
Last in this file add the following after the for-loop:
if (numSurvived != 0)
{
	return FLDPSN_NONE;
}


Next open /data/event_scripts.s and add the following to the end of the file:
Spoiler:

EventScript_PoisonSurvial::
	msgbox Text_PoisonSurvial, MSGBOX_SIGN
Text_PoisonSurvial:
	.string "Poison survived with 1hp…$"


Thats it, everything should be done.
Seen March 20th, 2019
Posted March 19th, 2019
1 posts
308 Days
Skipping the poochyena battle after choosing the starter (pokéemerald)

You can skip the poochyena battle started by the script command "special ChooseStarter" by modifying a few lines in src/battle_setup.c.

In the CB2_GiveStarter function

Spoiler:
comment/delete the following line
PlayBattleBGM();
change the following line
BattleTransition_Start(B_TRANSITION_BLUR);
to
BeginNormalPaletteFade(0xFFFFFFFF, -1, 0, 0x10, 0);


In the CB2_StartFirstBattle function

Spoiler:
change the line
SetMainCallback2(CB2_InitBattle);
to
SetMainCallback2(CB2_EndFirstBattle);
and the line
if (IsBattleTransitionDone() == TRUE)
to
if (!gPaletteFade.active)


This modification also adds a graceful transition (a simple fade) to the overworld to avoid glitches. I didn't extensively test this, however since it only affects functions which are used once in the entire game, it should not have any unexpected side-effects.
Seen 2 Weeks Ago
Posted March 24th, 2019
12 posts
1.9 Years
How to force the Battle style [Set|Shift] [EM]

This guide is for you when you want to force the player to play in set or shiftmode. For either the enteire game or just during important matches. ex: Always switch except during gyms matches were you force set.



Most changes are done in the option_menu.c file.

To dissable the user from change the setting we are going to remove this setting from the option menu. We'll start by commenting (or deleting) some lines.
Spoiler:

24: TD_BATTLESTYLE,
35: MENUITEM_BATTLESTYLE,

60: static u8 BattleStyle_ProcessInput(u8 selection);

61: static void BattleStyle_DrawChoices(u8 selection);

84: gText_BattleStyle,

235: gTasks[taskId].data[TD_BATTLESTYLE] = gSaveBlock2Ptr->optionsBattleStyle;
242: BattleStyle_DrawChoices(gTasks[taskId].data[TD_BATTLESTYLE]);

313->319:
case MENUITEM_BATTLESTYLE: break;
/*previousOption = gTasks[taskId].data[TD_BATTLESTYLE];
gTasks[taskId].data[TD_BATTLESTYLE] = BattleStyle_ProcessInput(gTasks[taskId].data[TD_BATTLESTYLE]);

if (previousOption != gTasks[taskId].data[TD_BATTLESTYLE])
BattleStyle_DrawChoices(gTasks[taskId].data[TD_BATTLESTYLE]);
break;

358: gSaveBlock2Ptr->optionsBattleStyle = gTasks[taskId].data[TD_BATTLESTYLE];


Then comment/delete the whole functions: BattleStyle_ProcessInput and BattleStyle_DrawChoices arround lines 470->491

Now the user can't change this setting anymore, but the options menu will look weird, what we now need to do is lower a few magic numbers.

Spoiler:

At 282: gTasks[taskId].data[TD_MENUSELECTION] = 6;
to gTasks[taskId].data[TD_MENUSELECTION] = /*6*/5;

At 287: if (gTasks[taskId].data[TD_MENUSELECTION] <= 5)
to if (gTasks[taskId].data[TD_MENUSELECTION] <= /*5*/4)

Then in the drawchoice functions we need to lower some y-cord by 16

At 513: DrawOptionMenuChoice(gText_SoundMono, 104, 48, styles[0]);
DrawOptionMenuChoice(gText_SoundStereo, GetStringRightAlignXOffset(1, gText_SoundStereo, 198), 48, styles[1]);

to DrawOptionMenuChoice(gText_SoundMono, 104, /*48*/32, styles[0]);
DrawOptionMenuChoice(gText_SoundStereo, GetStringRightAlignXOffset(1, gText_SoundStereo, 198), /*48*/32, styles[1]);

At 571: DrawOptionMenuChoice(gText_FrameType, 104, 80, 0);
DrawOptionMenuChoice(text, 128, /*80*/64, 1);
DrawOptionMenuChoice(text, 128, 80, 1);


to DrawOptionMenuChoice(gText_FrameType, 104, /*80*/64, 0);
DrawOptionMenuChoice(text, 128, /*80*/64, 1);
DrawOptionMenuChoice(text, 128, /*80*/64, 1);

Then do the same in ButtonMode_DrawChoices(u8 selection)
Around 598 for 64->48

And FrameType_DrawChoices(u8 selection)
Around 544 for 80->64



To set the default mode go to new_game.c

Spoiler:

set around line 102: gSaveBlock2Ptr->optionsBattleStyle = OPTIONS_BATTLE_STYLE_SHIFT;
to OPTIONS_BATTLE_STYLE_SET; if you want the default style to be set.


To change this style from a script set a var and make a new function where you check the var value and update the setting accordingly. And then call that funciton from the script. I'll extend this tutorial to do that if requested.
New to the community, have read a lot of posts already. Intresested in making a ROM hack.
I hate unnecessary big signatures.

Delta231

A noob

Male
India
Seen 20 Hours Ago
Posted 5 Days Ago
687 posts
3 Years
Have PokeBalls loading unique images [EM]


While, I was making my DS-Styled Balls for my Hack I noticed that some Balls loaded same 3rd animation image and only their palette was unique. This modification is for those who have their PokeBalls having different image.

Go to src/pokeball.c and go to function LoadBallGfx. You will find a switch case which would be similar to this
Spoiler:

 u16 var;

    if (GetSpriteTileStartByTag(gBallSpriteSheets[ballId].tag) == 0xFFFF)
    {
        LoadCompressedSpriteSheetUsingHeap(&gBallSpriteSheets[ballId]);
        LoadCompressedSpritePaletteUsingHeap(&gBallSpritePalettes[ballId]);
    }
    switch (ballId)
    {
    case BALL_DIVE:
    case BALL_LUXURY:
    case BALL_PREMIER:
    case BALL_ULTRA:
    case BALL_TIMER:
    case BALL_NEST:
    case BALL_NET:
    case BALL_REPEAT:
        break;
    default:
        var = GetSpriteTileStartByTag(gBallSpriteSheets[ballId].tag);
        LZDecompressVram(gOpenPokeballGfx, (void *)(VRAM + 0x10100 + var * 32));
        break;
    }


Just add your own entries by adding
case BALL_OUR_OWN_BALL:
Save and compile and you are good to go.

ThomasWinwood

Male
Seen 1 Week Ago
Posted 1 Week Ago
78 posts
5.5 Years

Remove badge boosts



Modern Pokemon games have done away with badge boosts and instead have the minimum level for obedience increase with every badge you acquire.

Ruby



First, open calculate_base_damage.c and edit the function CalculateBaseDamage by removing the BADGE_BOOST macro and the four lines where it's used.

#define BADGE_BOOST(badge, stat, bank) ({ \
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER))) \
{ \
    if ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) \
    && gTrainerBattleOpponent != SECRET_BASE_OPPONENT \
    && FlagGet(FLAG_BADGE0##badge##_GET) \
    && GetBattlerSide(bank) == B_SIDE_PLAYER) \
        (stat) = (110 * (stat)) / 100; \
} \
})
    BADGE_BOOST(1, attack, bankAtk);
    BADGE_BOOST(5, defense, bankDef);
    BADGE_BOOST(7, spAttack, bankAtk);
    BADGE_BOOST(7, spDefense, bankDef);
Next, open battle_2.c and edit the function GetWhoStrikesFirst by removing these two blocks of code.

    // Only give badge speed boost to the player's mon.
    if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) && FlagGet(FLAG_BADGE03_GET) && GetBattlerSide(bank1) == 0)
        bank1AdjustedSpeed = (bank1AdjustedSpeed * 110) / 100;
    // Only give badge speed boost to the player's mon.
    if (!(gBattleTypeFlags & BATTLE_TYPE_LINK) && FlagGet(FLAG_BADGE03_GET) && GetBattlerSide(bank2) == 0)
    {
        bank2AdjustedSpeed = (bank2AdjustedSpeed * 110) / 100;
    }
Finally, open battle_util.c and edit the function IsMonDisobedient. You should be able to find this section of code.

	if (FlagGet(FLAG_BADGE02_GET))
	    obedienceLevel = 30;
	if (FlagGet(FLAG_BADGE04_GET))
	    obedienceLevel = 50;
	if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;
How badge boosts correspond to increases in the minimum obedience level is up to you. As an example, here's how obedience works in Omega Ruby/Alpha Sapphire, Gen 7 and the Let's Go games. (For X/Y-style obedience, increase all these values by 10.)

	if (FlagGet(FLAG_BADGE01_GET))
	    obedienceLevel = 20;
	if (FlagGet(FLAG_BADGE02_GET))
	    obedienceLevel = 30;
	if (FlagGet(FLAG_BADGE03_GET))
	    obedienceLevel = 40;
	if (FlagGet(FLAG_BADGE04_GET))
	    obedienceLevel = 50;
	if (FlagGet(FLAG_BADGE05_GET))
	    obedienceLevel = 60;
	if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;
	if (FlagGet(FLAG_BADGE07_GET))
	    obedienceLevel = 80;

Emerald



First, open pokemon.c and edit the function CalculateBaseDamage by removing the ShouldGetBadgeBoost function and the eight lines of code that use it.

static bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId);
    if (ShouldGetStatBadgeBoost(FLAG_BADGE01_GET, battlerIdAtk))
        attack = (110 * attack) / 100;
    if (ShouldGetStatBadgeBoost(FLAG_BADGE05_GET, battlerIdDef))
        defense = (110 * defense) / 100;
    if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerIdAtk))
        spAttack = (110 * spAttack) / 100;
    if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerIdDef))
        spDefense = (110 * spDefense) / 100;
static bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 battlerId)
{
    if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
        return FALSE;
    else if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
        return FALSE;
    else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
        return FALSE;
    else if (FlagGet(badgeFlag))
        return TRUE;
    else
        return FALSE;
}
Next, open battle_main.c and edit the function GetWhoStrikesFirst. There are two blocks of seven lines of code with the comment "badge boost"; remove them.

    // badge boost
    if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
        && FlagGet(FLAG_BADGE03_GET)
        && GetBattlerSide(battler1) == B_SIDE_PLAYER)
    {
        speedBattler1 = (speedBattler1 * 110) / 100;
    }
    // badge boost
    if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_FRONTIER))
        && FlagGet(FLAG_BADGE03_GET)
        && GetBattlerSide(battler2) == B_SIDE_PLAYER)
    {
        speedBattler2 = (speedBattler2 * 110) / 100;
    }
Finally, open battle_util.c and edit the function IsMonDisobedient. You should be able to find this section of code.

        if (FlagGet(FLAG_BADGE02_GET))
            obedienceLevel = 30;
        if (FlagGet(FLAG_BADGE04_GET))
            obedienceLevel = 50;
        if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;
How badge boosts correspond to increases in the minimum obedience level is up to you. As an example, here's how obedience works in Omega Ruby/Alpha Sapphire, Gen 7 and the Let's Go games. (For X/Y-style obedience, increase all these values by 10.)

        if (FlagGet(FLAG_BADGE01_GET))
            obedienceLevel = 20;
        if (FlagGet(FLAG_BADGE02_GET))
            obedienceLevel = 30;
        if (FlagGet(FLAG_BADGE03_GET))
            obedienceLevel = 40;
        if (FlagGet(FLAG_BADGE04_GET))
            obedienceLevel = 50;
        if (FlagGet(FLAG_BADGE05_GET))
            obedienceLevel = 60;
        if (FlagGet(FLAG_BADGE06_GET))
            obedienceLevel = 70;
        if (FlagGet(FLAG_BADGE07_GET))
            obedienceLevel = 80;
The rival in Red and Blue is called Green. Gary is some character from a lame cartoon.

ThomasWinwood

Male
Seen 1 Week Ago
Posted 1 Week Ago
78 posts
5.5 Years

Change the limbo slots' hardcoded Unown cry



First, open the file pokemon_3.c (Ruby)/pokemon.c (Emerald) and find the function SpeciesToCryId. Remove the two if statements and alter the final line such that the function looks like this.

u16 SpeciesToCryId(u16 species)
{
    return gSpeciesIdToCryId[species];
}
Now extend the list gSpeciesIdToCryId in cry_ids.h to include BULBASAUR through OLD_UNOWN_Z. To replicate the vanilla experience the first 251 entries (Bulbasaur through Celebi) should be the National Pokédex number of that Pokémon minus one; after that are 26 copies of the value 200 for the limbo slots.
The rival in Red and Blue is called Green. Gary is some character from a lame cartoon.
Advertiser Content