-
Notifications
You must be signed in to change notification settings - Fork 806
Adding items that act like HMs
This tutorial will cover how to add items that act like HM Field moves, using CUT as an example.
Follow the guide on adding new items to create the item that will act like an HM. I changed ITEM_19 into CHAINSAW with the following:
const WATER_STONE ; 18
- const ITEM_19 ; 19
+ const CHAINSAW ; 19
const HP_UP ; 1a
db "WATER STONE@"
- db "TERU-SAMA@"
+ db "CHAINSAW@"
db "HP UP@"
dw WaterStoneDesc
- dw TeruSama2Desc
+ dw ChainsawDesc
dw HPUpDesc
...
-TeruSama2Desc:
- db "?@"
+ChainsawDesc:
+ db "Cuts down pesky"
+ next "plants.@"
-; ITEM_19
- item_attribute $9999, HELD_NONE, 0, NO_LIMITS, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE
+; CHAINSAW
+ item_attribute 0, HELD_NONE, 0, CANT_TOSS, KEY_ITEM, ITEMMENU_CLOSE, ITEMMENU_NOUSE
data/items/catch_rate_items.asm:
TimeCapsule_CatchRateItems:
- db ITEM_19, LEFTOVERS
In this example, Chainsaw will act like the HM Cut, so we'll use CutFunction
in engine/events/overworld.asm. A list of HM Functions is at the end of this tutorial. Since these functions are in a different bank from the item effect functions, we just need to write a small function that can farcall our HM Function. engine/items/item_effects.asm:
dw EvoStoneEffect ; WATER_STONE
- dw NoEffect ; ITEM_19
+ dw ChainsawEffect ; CHAINSAW
...
+ChainsawEffect:
+ farcall CutFunction
+ ret
The above works, but it has a few flaws. Firstly, a message will pop up saying a Pokémon used the relevant HM Effect. There are several ways to change this, but the easiest is to edit the text that's displayed when your HM's effect script is run. The HM Effect scripts will be listed at the end.
First, skip loading the Pokémon's name. At best this finds the first Pokémon that has cut, at worse it fails and the text is incorrect. engine/events/overworld.asm:
Script_Cut:
- callasm GetPartyNick
writetext Text_UsedCut
Then, we can change the text to be a bit more neutral. Text_UsedCut
points to UnknownText_0x1c05dd
in data/text/common_2.asm:
UnknownText_0x1c05dd::
- text_ram wStringBuffer2
- text " used"
- line "CUT!"
+ text "You cut some"
+ line "plants!"
prompt
As it stands, if you use your item and it fails, you'll be told the HM's error message AND be yelled at by Oak. To avoid this, we can introduce a new temporary var that can be used to skip Oak's message for HM-like-items.
First off, we need to create a new label in wram. There's a nice chunk of free space in wram bank 0 right after wDaysSince
. wram.asm:
wDaysSince:: db
+wUsingHMItem:: db
SECTION "WRAM 1", WRAMX
Next, we'll change our item effect so that it sets wUsingHMItem
to 1, signifying that it's okay to skip Oak's Message. engine/items/item_effects.asm
ChainsawEffect:
+ ld a, 1
+ ld [wUsingHMItem], a
farcall CutFunction
ret
Finally, we'll skip Oak's message if wUsingHMItem
is set. Oak's message is handled in engine/items/pack.asm:
ld a, [wItemEffectSucceeded]
and a
- jr z, .Oak
+
+ ; grab and reset wUsingHMItem without changing flag
+ ld hl, wUsingHMItem
+ ld a, [hl]
+ ld [hl], 0
+
+ jr z, .tryOak
ld a, PACKSTATE_QUITRUNSCRIPT
ld [wJumptableIndex], a
ret
+.tryOak
+ or a
+ jr z, .Oak
+ ret
TossMenu:
ld hl, Text_ThrowAwayHowMany
The above loads wUsingHMItem
's value and resets it to 0 so Oak's message won't be skipped for normal items. If Oak's message would normally plays, it will do one quick check of wUsingHMItem
's old value, and go right to returning if it wasn't zero.
Including the other HM effects is as simple as repeating the above with different effect functions and new items. Our code to handle Oak's message based on wUsingHMItem
doesn't need to be changed to allow other HMs, however every HM must include code to it to 1 (or any other nonzero value).
The following are lists of HM Functions as of time of writing. These may not all work as well as Cut, and may change naming conventions over time.
All of these are in engine/events/overworld.asm.
CutFunction
FlyFunction
SurfFunction
StrengthFunction
OWFlash
WhirlpoolFunction
WaterfallFunction
Additionally, functions like TeleportFunction
can be used as well.
All of these are in engine/events/overworld.asm.
Script_Cut
- Fly does not show a message
UsedSurfScript
Script_UsedStrength
- Flash does not show the Pokémon's name
Script_UsedWhirlpool
Script_UsedWaterfall
Even with the item added and it being functional, the game will still check for a pokemon in the party to use the HM move when attempting to interact with a cuttable tree on the overworld. This is a simple fix.
If we look in engine/events/overworld.asm at the bottom, we'll see TryCutOW
. This function is called when the player interacts with a cuttable tree, normally it checks the party first for a pokemon with cut, then for the appropriate badge, so we'll change it.
CutFunction:
...
.CheckAble:
- ld de, ENGINE_HIVEBADGE
- call CheckBadge
- jr c, .nohivebadge
call CheckMapForSomethingToCut
jr c, .nothingtocut
ld a, $1
ret
-.nohivebadge
- ld a, $80
- ret
and
TryCutOW::
- ld d, CUT
- call CheckPartyMove
- jr c, .cant_cut
- ld de, ENGINE_HIVEBADGE
- call CheckEngineFlag
+ ld a, CHAINSAW
+ ld [wCurItem], a
+ ld hl, wNumItems
+ call CheckItem
+ jr nc, .cant_cut
This removes the checks for an eligible pokemon and badge, and just checks for the item in the bag.