You'll first want to look at data/scripts/surf.inc and data/scripts/field_move_scripts.inc. Across these two files, you can edit Surf, Cut, Rock Smash, Strength, Waterfall, and Dive. Each of these HM moves can be triggered by interacting with things in the overworld, like a tree, a rock, or water. In every script for each of these moves, there's one important series of lines:
Code:
lockall
checkpartymove MOVE_<WHATEVER THE MOVE IS>
compare VAR_RESULT, PARTY_SIZE
goto_if_eq EventScript_Check<CAN'T USE MOVE>
setfieldeffectargument 0, VAR_RESULT
bufferpartymonnick 0, VAR_RESULT
buffermovename 1, MOVE_<WHATERVER THE MOVE IS>
msgbox Text_WantTo<USE MOVE>, MSGBOX_YESNO
compare VAR_RESULT, NO
goto_if_eq EventScript_Cancel<MOVE>
msgbox Text_MonUsedFieldMove, MSGBOX_DEFAULT
closemessage
These lines handle checking to see if a Pokemon on the player's team has the proper move, and if so, displays the text that says "Pokemon used <Move>". All we have to do is change these lines to instead look for a specific item in the player's bag. If the player has it, then the move goes forward like normal. Otherwise, the game'll say the move can't be used. Let's say, for example, that I wanted the player to need a Potion in order to use Rock Smash on a rock. This would be done a little ways down into field_move_scripts.inc. This is how the first four lines after "lockall" of the script would look:
Code:
checkitem ITEM_POTION, 1
compare VAR_RESULT, FALSE
goto_if_eq EventScript_CantSmashRock
setitemarg ITEM_POTION
The command "checkitem" needs both the item index (the name of the item) and the quantity, which is why I added a 1 at the end. With this, as long as the player has at least 1 Potion, they will be able to smash a rock. It also takes the Potion's index as the "Item Argument", which will be used later. The only problem is that the game also needs to get the Pokemon's nickname and sprite to display while doing the "Pokemon used Cut" animation. And we don't want that. So, the first thing we do is delete the following lines:
Code:
bufferpartymonnick 0, VAR_RESULT
buffermovename 1, MOVE_ROCK_SMASH
msgbox Text_MonUsedFieldMove, MSGBOX_DEFAULT
Deleting these lines makes sure that we aren't using the dialogue that normally appears when using cut.
Now we need to account for the sprite of the Pokemon that usually appears during the animation. For this, we're going to need to jump over to src/field_effect.c. Find this:
Code:
bool8 FldEff_FieldMoveShowMonInit(void)
{
struct Pokemon *pokemon;
u32 flag = gFieldEffectArguments[0] & 0x80000000;
pokemon = &gPlayerParty[(u8)gFieldEffectArguments[0]];
gFieldEffectArguments[0] = GetMonData(pokemon, MON_DATA_SPECIES);
gFieldEffectArguments[1] = GetMonData(pokemon, MON_DATA_OT_ID);
gFieldEffectArguments[2] = GetMonData(pokemon, MON_DATA_PERSONALITY);
gFieldEffectArguments[0] |= flag;
FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON);
FieldEffectActiveListRemove(FLDEFF_FIELD_MOVE_SHOW_MON_INIT);
return FALSE;
}
We're going to change it to this:
Code:
bool8 FldEff_FieldMoveShowMonInit(void)
{
u32 flag = gSaveBlock2Ptr->ItemArg & 0x80000000;
ItemArg |= flag;
FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON);
FieldEffectActiveListRemove(FLDEFF_FIELD_MOVE_SHOW_MON_INIT);
return FALSE;
}
What we've done here is just deleted a huge chunk of the code that messes up the process, as well as swapped out "gFieldEffectArguments[0]" with "gSaveBlock2Ptr->ItemArg". You may notice that last change showing up quite a bit. If you're nervous about committing to this change, you can instead comment-out the code like this:
Code:
bool8 FldEff_FieldMoveShowMonInit(void)
{
//struct Pokemon *pokemon;
u32 flag = gSaveBlock2Ptr->ItemArg & 0x80000000;
/*pokemon = &gPlayerParty[(u8)gFieldEffectArguments[0]];
gFieldEffectArguments[0] = GetMonData(pokemon, MON_DATA_SPECIES);
gFieldEffectArguments[1] = GetMonData(pokemon, MON_DATA_OT_ID);
gFieldEffectArguments[2] = GetMonData(pokemon, MON_DATA_PERSONALITY);*/
gSaveBlock2Ptr->ItemArg |= flag;
FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON);
FieldEffectActiveListRemove(FLDEFF_FIELD_MOVE_SHOW_MON_INIT);
return FALSE;
}
This way, in case you decide to go back to using HM moves instead of items, you can just undo this change.
Next, we're going over to include/global.h. Add this to the end of struct SaveBlock2:
Code:
struct SaveBlock2
{
.......................
u16 ItemArg;
}; // sizeof=0xF2C
This variable will hold the index for the item that we are using. It'll be important for animation section.
Next, go to src/scrcmd.c, and add this to the end:
Code:
void ScrCmd_SetItemArg(void)
{
gSaveBlock2Ptr->ItemArg = gSpecialVar_0x8000;
}
And then go to asm/macros/event.inc and add this to the end:
Code:
.macro setitemarg id:req
setvar VAR_0x8000, \id,
callnative ScrCmd_SetItemArg
.endm
This sets up that "setitemarg" macro that I used in the Cut script. It allows us to set our ItemArg variable from within scripts, which is nice.
At this point, the game will work as you have intended it: as long as the player has at least 1 Potion (and the third Gym Badge, but you can delete that check as well if you want), they can smash a rock without any glitches. However, the animation will look a little strange, with a seemingly random Pokemon appearing. If you don't want that, the following changes will fix that.
First, return to field_effect.c, and at the top, you'll see several instances of "#include". Add this to the end of that section:
This will give us access to the "AddItemIconSprite" method that will be used in the next section of code.
The next thing we look for is this:
Code:
static u8 sub_80B8C60(u32 a0, u32 a1, u32 a2)
{
u16 v0;
u8 monSprite;
struct Sprite *sprite;
v0 = (a0 & 0x80000000) >> 16;
a0 &= 0x7fffffff;
monSprite = CreateMonSprite_FieldMove(a0, a1, a2, 0x140, 0x50, 0);
sprite = &gSprites[monSprite];
sprite->callback = SpriteCallbackDummy;
sprite->oam.priority = 0;
sprite->data[0] = a0;
sprite->data[6] = v0;
return monSprite;
}
We then change it to this:
Code:
static u8 sub_80B8C60(u32 a0, u32 a1, u32 a2)
{
u16 v0;
u8 monSprite;
struct Sprite *sprite;
v0 = (a0 & 0x80000000) >> 16;
a0 &= 0x7fffffff;
monSprite = AddItemIconSprite(2110,2110,a0);
gSprites[monSprite].pos1.y = 0x50;
gSprites[monSprite].pos1.x = 0x140;
sprite = &gSprites[monSprite];
sprite->callback = SpriteCallbackDummy;
sprite->oam.priority = 0;
sprite->data[0] = a0;
sprite->data[6] = v0;
return monSprite;
}
This makes the sprite that appears for the animation use the sprite of the item rather than the sprite of a Pokemon. This is where that "setitemarg" line that we changed from the script comes into play, as a0 is equal to the item index of the Potion.
Immediately below that function is this one:
Code:
static void sub_80B8CC0(struct Sprite *sprite)
{
if ((sprite->pos1.x -= 20) <= 0x78)
{
sprite->pos1.x = 0x78;
sprite->data[1] = 30;
sprite->callback = sub_80B8D04;
if (sprite->data[6])
{
PlayCry2(sprite->data[0], 0, 0x7d, 0xa);
}
else
{
PlayCry1(sprite->data[0], 0);
}
}
}
The following change can vary depending on how you want to implement it. Changing this function will change the sound effect that is played during the animation. Normally, the Pokemon's cry is played. We aren't using a Pokemon anymore, though. Currently, this is the change that I've made:
Code:
static void sub_80B8CC0(struct Sprite *sprite)
{
if ((sprite->pos1.x -= 20) <= 0x78)
{
sprite->pos1.x = 0x78;
sprite->data[1] = 30;
sprite->callback = sub_80B8D04;
PlaySE(SE_KAIFUKU);
}
}
This change makes it so that the Potion healing sound effect plays during the animation, which I specifically chose since you're using a Potion to cut a tree. The only problem with this is that every single time an HM move is used, no matter what item is required, it will always play that same sound effect. If you want it to change depending on which item is being used, you'll want to make a switch statement, where you compare sprite->data[0] to whatever item it is that the player is using. For example, say you wanted the Potion sound effect to be used when a Potion is used, and the Bicycle Bell sound effect to be used when a Pokeball is used. Here's what it would look like:
Code:
static void sub_80B8CC0(struct Sprite *sprite)
{
if ((sprite->pos1.x -= 20) <= 0x78)
{
sprite->pos1.x = 0x78;
sprite->data[1] = 30;
sprite->callback = sub_80B8D04;
switch(sprite->data[0])
{
case 4:
PlaySE(SE_JITENSYA);
break;
case 28:
PlaySE(SE_KAIFUKU);
break;
}
}
}
The numbers used for the cases in the switch statement are unique to each item. The names used in PlaySE are unique to each sound effect. You can find the values for each item in include/constants/items.h, and you can find the names for each sound effect in include/constants/songs.h.
You'll also want to look for this:
Code:
bool8 FldEff_FieldMoveShowMon(void)
{
u8 taskId;
if (IsMapTypeOutdoors(GetCurrentMapType()) == TRUE)
{
taskId = CreateTask(sub_80B8554, 0xff);
} else
{
taskId = CreateTask(sub_80B88B4, 0xff);
}
gTasks[taskId].data[15] = sub_80B8C60(gFieldEffectArguments[0], gFieldEffectArguments[1], gFieldEffectArguments[2]);
return FALSE;
}
And swap out "gFieldEffectArguments[0]" with "gSaveBlock2Ptr->ItemArg". This will make sure that ItemArg is passed in to those functions, giving you the right image and/or sound effect.
And with that, you're done!....with the overworld stuff. You've got Rock Smash to work as long as the player is holding a Potion! If you want to change which item is required for each HM move, you'll have to go through data/scripts/field_move_scripts.inc and data/scripts/surf.inc and make similar changes to each HM's script. You only need to do most of the stuff in field_effect.c once, as it applies to all HM move animations and sound effects. The one thing you may need to go back to and change is if you want to add more sound effects. In that case, you just add more cases in that last switch statement. If you have any questions or errors when applying this, just let me know, and I'll try to help you out.
However, if you want the player to be able to go into their bag, click on the item, and then activate the effect, or allow the player to register the item so that they can easily walk around, smashing rocks with a single press of a button, that'll require a little bit more work.
I'll show you how I implemented my Rock Smash item, as it is the quickest to explain out of all of the HM items that I've made. I would show you how I've implemented all of them, but I've made some personal adjustments to some of them for my current project, so those might have mechanics that other's don't necessarily want.
In src/item_use.c, right beneath all of the #includes, add this:
Code:
extern const u8 EventScript_SmashRock[];
Then, at the end, add all of this:
Code:
static void FieldCallback_RockSmash(void)
{
FadeInFromBlack();
ScriptContext1_SetupScript(EventScript_FldEffRockSmash);
}
void ItemUseOutOfBattle_Pickaxe(u8 taskId)
{
if (CheckObjectGraphicsInFrontOfPlayer(OBJ_EVENT_GFX_BREAKABLE_ROCK) == TRUE)
{
if(!gTasks[taskId].tUsingRegisteredKeyItem)
{
gSaveBlock2Ptr->ItemArg = 116;
gFieldCallback = FieldCallback_RockSmash;
gBagMenu->mainCallback2 = CB2_ReturnToField;
Task_FadeAndCloseBagMenu(taskId);
}
else
{
PlaySE(SE_W088);
ScriptContext1_SetupScript(EventScript_SmashRock);
DestroyTask(taskId);
}
}
else
DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
}
What I've done here is I've copied over some elements from src/fldeff_rocksmash.c, made a few tweaks here and there to make them work with an item, and pasted them in item_use.c. I then created this ItemUseOutOfBattle_Pickaxe method, which will be given to the item I want to hold the Rock Smash effect. (I created a Pickaxe item to have this effect, hence the name) I copied over the check to see if the player is facing a breakable rock. If so, it'll then check to see if the item that is being used is being used as a registered item, or is being used directly from the bag. If it's from the bag, it assigns ItemArg to be 116, which is the value for my Pickaxe item, sets up FieldCallback_RockSmash, then exits the bag, where the normal Rock Smash process will occur. In FieldCallback_RockSmash, I FadeInFromBlack to re-enter the overworld and run the FldEffRockSmash script, which can be found in data/scripts/field_move_scripts.inc. If the item was being used as a registered item, it just immediately breaks the rock, with no animation happening whatsoever. If the player isn't facing a breakable rock, it'll just play the "There's a time and place for everything" message.
At this point, you have the item effect all set up, but you have no item that actually uses it! To go about doing that, we first need to go over to include/item_use.h, and add "void ItemUseOutOfBattle_Pickaxe(u8);" near the end of the file, but not past the #endif.
Next, we go over to src/data/items.h. Go to any item of your choosing and swap out the .fieldUseFunc value with "ItemUseOutOfBattle_Pickaxe,". If you want the icon that appears during the animation to match the item that you assigned it to, you'll have to go to include/constants/items.h, find the number that is associated with name of your item, and change the ItemArg assignment back in src/item_use.c from 116 to whatever the number is for your item. For the sake of consistency, if we wanted a Potion to be the item that allows us to use Rock Smash, we'd go up to the potion section in src/data/items.h and swap out "ItemUseOutOfBattle_Medicine" with our "ItemUseOutOfBattle_Pickaxe", and change "gSaveBlock2Ptr->ItemArg = 116;" in src/item_use.c to "gSaveBlock2Ptr->ItemArg = 28;", since 28 is the index for a Potion.
You'll also want to hop over to src/field_effect.c and look for methods "sub_80B8A64" and "overworld_bg_setup_2". In both of those methods, you'll see this line of code:
Code:
FreeResourcesAndDestroySprite(&gSprites[task->data[15]], task->data[15]);
Swap this line out for this:
Code:
FieldEffectFreeGraphicsResources(&gSprites[task->data[15]]);
This'll make it so that if you were to, for example, use your Rock Smash item and then use your Surf item, the proper sprites will appear for each item. Otherwise, the Rock Smash item will appear for both the Rock Smash and Surf animations.
And now you're (really) done! You can now make an item has the effect of an HM, both when using it in the overworld, when using it from your bag, and when using it as a registered item. If you're wanting to create a brand new item for your HM effect instead of replacing the effect of a pre-existing item....I'm not going to go through how to do that here, since this post is already pretty massive as it is. I would be shocked if someone hasn't already made a tutorial on how to make new items.