This tutorial will cover how to add items that act like HM Field moves, using CUT as an example. ## Contents 1. [Adding the item](#1-adding-the-item) 2. [Fixing the success message](#2-fixing-the-success-message) 3. [Fixing Oak's message](#3-fixing-oaks-message) 4. [Including other HMs](#4-including-other-hms) ## 1. Adding the item Follow the guide on [adding new items](#Add-a-new-item) to create the item that will act like an HM. I changed ITEM_19 into CHAINSAW with the following: [constants/item_constants.asm](../blob/master/constants/item_constants.asm): ```Diff const WATER_STONE ; 18 - const ITEM_19 ; 19 + const CHAINSAW ; 19 const HP_UP ; 1a ``` [data/items/names.asm](../blob/master/data/items/names.asm): ```Diff db "WATER STONE@" - db "TERU-SAMA@" + db "CHAINSAW@" db "HP UP@" ``` [data/items/descriptions.asm](../blob/master/data/items/descriptions.asm): ```diff dw WaterStoneDesc - dw TeruSama2Desc + dw ChainsawDesc dw HPUpDesc ... -TeruSama2Desc: - db "?@" +ChainsawDesc: + db "Cuts down pesky" + next "plants.@" ``` [data/items/attributes.asm](../blob/master/data/items/attributes.asm): ```Diff -; 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](../blob/master/data/items/catch_rate_items.asm): ```Diff 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](../blob/master/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](../blob/master/engine/items/item_effects.asm ): ```Diff dw EvoStoneEffect ; WATER_STONE - dw NoEffect ; ITEM_19 + dw ChainsawEffect ; CHAINSAW ... +ChainsawEffect: + farcall CutFunction + ret ``` ## 2. Fixing the success message 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](../blob/master/engine/events/overworld.asm): ```Diff Script_Cut: - callasm GetPartyNickname writetext UseCutText ``` Then, we can change the text to be a bit more neutral. `UseCutText` points to `_UseCutText` in [data/text/common_2.asm](../blob/master/data/text/common_2.asm): ```Diff _UseCutText:: - text_ram wStringBuffer2 - text " used" - line "CUT!" + text "You cut some" + line "plants!" prompt ``` ## 3. Fixing Oak's message 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](../blob/master/wram.asm): ```Diff 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](../blob/master/engine/items/item_effects.asm) ```Diff 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](../blob/master/engine/items/pack.asm): ```Diff 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. ## 4. Including other HMs 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. ### HM Function List All of these are in [engine/events/overworld.asm](../blob/master/engine/events/overworld.asm). * `CutFunction` * `FlyFunction` * `SurfFunction` * `StrengthFunction` * `OWFlash` * `WhirlpoolFunction` * `WaterfallFunction` Additionally, functions like `TeleportFunction` can be used as well. ### HM Effect Scripts All of these are in [engine/events/overworld.asm](../blob/master/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` ### Using the item as default on the overworld 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](../blob/master/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. ```Diff 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 ```Diff 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.