This tutorial is for how to add different kinds of new items, including a healing item, Poké Ball, evolution stone, key item, and held item. ## Contents 1. [How item constants work](#1-how-item-constants-work) 2. [Essential item data: name, description, attributes, and effect](#2-essential-item-data-name-description-attributes-and-effect) 3. [Examples](#3-examples) - [No effect: Big Nugget](#no-effect-big-nugget) - [`RestoreHPEffect`: Sweet Heart](#restorehpeffect-sweet-heart) - [`StatusHealingEffect`: Lava Cookie](#statushealingeffect-lava-cookie) - [`PokeBallEffect`: Dusk Ball](#pokeballeffect-dusk-ball) - [`EvoStoneEffect`: Mist Stone](#evostoneeffect-mist-stone) - [`XItemEffect`: X Sp.Def](#xitemeffect-x-spdef) - [`TownMapEffect`: Town Map](#townmapeffect-town-map) - [Held effect: Eviolite](#held-effect-eviolite) 4. [Adding up to 254 items](#4-adding-up-to-254-items) ## 1. How item constants work Item constants are defined in [constants/item_constants.asm](../blob/master/constants/item_constants.asm). But unlike some constants, they're not a simple sequence where you can append new items to the end. - `NO_ITEM` is the first item ID, which is used to indicate a lack of item. Leave this alone. - Item constants start out as an ordinary sequence, from `MASTER_BALL` to `ITEM_BE`, including 23 unused ITEM_XX constants. Those are simplest to replace with any kind of item you want, except for TMs or HMs. - After the ordinary items come the TMs, from `TM_DYNAMICPUNCH` to `TM_NIGHTMARE`. These are defined with an `add_tm` macro that simultaneously defines the next TM_MOVENAME item constant *and* the next MOVENAME_TMNUM constant (starting at 1 for the first `add_tm` use). The first time `add_tm` is used it defines `TM01` as the current item, and any items after that are assumed to also be TMs. Note that `ITEM_C3` and `ITEM_DC` are two unusable item IDs in-between the TMs—they can't become normal items, since they're greater than `TM01`, and some TM-related code manually skips over those two slots—so if you want to use them you'll have to [correct that design flaw](../blob/master/docs/design_flaws.md#item_c3-and-item_dc-break-up-the-continuous-sequence-of-tm-items). - After the TMs come the HMs, from `HM_CUT` to `HM_WATERFALL`. These are defined with an `add_hm` macro that simultaneously defines the next HM_MOVENAME item constant *and* the next MOVENAME_TMNUM constant (continuing from the TMs, so for instance, `CUT_TMNUM` is 51). The first time `add_hm` is used it defines `HM01` as the current item, and any items after that are assumed to also be HMs, with all the differences that implies (they'll have an "H" in the Pack, using them will print "Booted up an HM", they can't be tossed, etc). - There can't be useful items after the HMs, since by definition anything after `HM01` is treated as an HM itself. In fact, `ITEM_FA` is defined after the HMs, so you might need to move or delete it. - `ITEM_FROM_MEM` is the last item ID, which is used in some scripts to give whatever item is in `wScriptVar` instead of a hard-coded item. (For instance, fruit trees rely on it so they don't need a separate script for each kind of Berry and Apricorn.) (Note that after the `add_tm`s and `add_hm`s, there are also some `add_mt`s. This macro defines more MOVENAME\_TMNUM constants, but not more TM\_MOVENAME or HM\_MOVENAME item constants, so the moves are recognized as teachable but don't have an associated item.) It's important to understand that there's nothing special about the specific numeric values, except $00 for `NO_ITEM` and $FF for `ITEM_FROM_MEM`. `const_def` starts a new constant sequence at 0, and every `const`, `add_tm`, or `add_hm` after that defines the next constant in the sequence. ## 2. Essential item data: name, description, attributes, and effect You may have already guessed this from the comment at the top of [constants/item_constants.asm](../blob/master/constants/item_constants.asm): ```asm ; item ids ; indexes for: ; - ItemNames (see data/items/names.asm) ; - ItemDescriptions (see data/items/descriptions.asm) ; - ItemAttributes (see data/items/attributes.asm) ; - ItemEffects (see engine/items/item_effects.asm) ``` Every kind of item has these pieces of data. `ItemNames`, `ItemDescriptions`, `ItemAttributes`, and `ItemEffects` are four tables with an entry for each item constant, one after another. It's important for them all to be in sync, so that the Nth constant correctly matches the Nth name, the Nth description, and so on. **Names** are defined in [data/items/names.asm](../blob/master/data/items/names.asm). They're simply written as db "NAME@": an opening quote, the name, an ending "@", and a closing quote. Names can be up to 12 characters long. The number of *printed* characters also matters, since screens like the Pack and the Mart menus are a fixed width. For example, when the name `"# DOLL@"` gets printed as "POKé DOLL", that's 9 characters, not 6. **Descriptions** are defined in [data/items/descriptions.asm](../blob/master/data/items/descriptions.asm). Unlike with names, each entry in the table of descriptions is a pointer to the actual description data. Descriptions have two lines, each with up to 18 characters. Again, what matters is the printed length, since they have to fit in a text box of that size. **Attributes** are defined in [data/items/attributes.asm](../blob/master/data/items/attributes.asm). They use an `item_attribute` macro that defines many pieces of data at once: - **price:** The price in Marts. Prices range from ¥0 to ¥65535 ($FFFF, the maximum value of a two-byte quantity). Items can be resold for half the price. - **held effect:** The effect when held by a Pokémon. Usually `HELD_NONE`, except for items like Leftovers. The `HELD_*` constants are defined in [constants/item_data_constants.asm](../blob/master/constants/item_data_constants.asm). We'll see how to create a new held effect later, for [Eviolite](#held-effect-eviolite). - **parameter:** A piece of extra data associated with the item. Usually 0, but some item effects use this parameter. For instance, BrightPowder's parameter of 20 is interpreted by `BattleCommand_CheckHit` as an extra 20/256 (~7.8%) chance to miss a move. - **property:** Controls whether you can select and/or toss the item. `NO_LIMITS`, `CANT_SELECT`, `CANT_TOSS`, or `CANT_SELECT | CANT_TOSS`. Most items have `CANT_SELECT`, except for the usefully selectable ones like Bicycle or ItemFinder. `CANT_TOSS` is for key items and HMs. - **pocket:** Which pocket it goes in. `ITEM`, `KEY_ITEM`, `BALL`, or `TM_HM`. - **field menu:** What the item does when you try to use it in the field (i.e. outside of battle). - `ITEMMENU_NOUSE` can't be used at all ("OAK: PLAYER! This isn't the time to use that!") - `ITEMMENU_CURRENT` just uses it right away (like Repel or Coin Case) - `ITEMMENU_PARTY` lets you choose a party Pokémon to use it on (like Potion or HP Up) - `ITEMMENU_CLOSE` has a confirmation menu before using it (like Bicycle or Escape Rope) - **battle menu:** What the item does when you try to use it during battle. Another `ITEMMENU_*` constant. **Effects** are defined in [engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm). Like descriptions, there's a table of pointers to the effects themselves, and the pointers are what correspond directly with item constants. Effects are implemented in assembly code, and are virtually unlimited in what they can do. But many of them are flexible. Effects like `StatusHealingEffect`, `PokeBallEffect`, or `EvoStoneEffect` get reused for many different items, and the items' particular details come from their attributes or from extra data tables related to that kind of item. Next we'll see how to add new items that use some of these general-purpose effects. ## 3. Examples ### No effect: Big Nugget To start with, we'll implement a new item that just has the essential data. A Big Nugget doesn't do anything, it just has a high price. So here's how to add one: Edit [constants/item_constants.asm](../blob/master/constants/item_constants.asm): ```diff const WATER_STONE ; 18 - const ITEM_19 ; 19 + const BIG_NUGGET ; 19 const HP_UP ; 1a ``` Edit [data/items/names.asm](../blob/master/data/items/names.asm): ```diff db "WATER STONE@" - db "TERU-SAMA@" + db "BIG NUGGET@" db "HP UP@" ``` Edit [data/items/descriptions.asm](../blob/master/data/items/descriptions.asm): ```diff dw WaterStoneDesc - dw TeruSama2Desc + dw BigNuggetDesc dw HPUpDesc ... -TeruSama2Desc: - db "?@" +BigNuggetDesc: + db "Made of pure gold." + next "Sell very high.@" ``` Edit [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 +; BIG_NUGGET + item_attribute 20000, HELD_NONE, 0, CANT_SELECT, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE ``` Edit [engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm): ```diff dw EvoStoneEffect ; WATER_STONE - dw NoEffect ; ITEM_19 + dw NoEffect ; BIG_NUGGET dw VitaminEffect ; HP_UP ``` And last, edit [data/items/catch_rate_items.asm](../blob/master/data/items/catch_rate_items.asm): ```diff TimeCapsule_CatchRateItems: - db ITEM_19, LEFTOVERS ... ``` This is an easy-to-miss edit that's needed because of the Time Capsule. When a Pokémon is traded via Time Capsule from RBY to GSC, the byte in its data structure that represents its catch rate is interpreted as its held item. (A catch rate byte no longer exists in GSC, since that's part of base data.) For example, Jigglypuff's catch rate is 170, or $AA, so it holds a Polkadot Bow when traded to GSC because `POLKADOT_BOW` is $AA. The `TimeCapsule_CatchRateItems` is used to convert catch rate values that don't correspond to valid items. So a Pokémon with a catch rate of $19, when traded from RBY to GSC, would hold Leftovers instead of `ITEM_19`. (And even without any trading, if a Pokémon's held item is `ITEM_19`, it will appear as "LEFTOVERS" in the status screen!) But since we're replacing `ITEM_19` with a valid item, we don't want this to happen any more. Anyway, that's all you need to add a basic item: ![Screenshot](screenshots/big-nugget.png) ### `RestoreHPEffect`: Sweet Heart A Sweet Heart, from Gen 5, restores 20 HP, just like RageCandyBar. It can be used on the field or during battle, and enemy trainer AI should know how to use one too. First, add the essential data. Replace `ITEM_2D` with `SWEET_HEART`; give it a name, description, and attributes (`100, HELD_NONE, 0, CANT_SELECT, ITEM, ITEMMENU_PARTY, ITEMMENU_PARTY`); give it the `RestoreHPEffect`; and remove `ITEM_2D` from `TimeCapsule_CatchRateItems`. Then it's time to implement the specific HP healing amount for Sweet Heart. Notice how most healing items—Potion, Fresh Water, etc—have an `item_attribute` parameter value equal to how much they heal? Those aren't actually used anywhere. Instead, the healing amounts for items used by the player, by the enemy trainer, and (when possible) by the Pokémon holding it are all handled separately. Edit [data/items/heal_hp.asm](../blob/master/data/items/heal_hp.asm): ```diff HealingHPAmounts: dbw FRESH_WATER, 50 ... dbw BERRY_JUICE, 20 + dbw SWEET_HEART, 20 dbw -1, 0 ; end ``` `HealingHPAmounts` is used by `GetHealingItemAmount`, which is called by `ItemRestoreHP`, which is called by `RestoreHPEffect`, which is the effect we already assigned to Sweet Heart; so now it will successfully heal 20 HP when used by the player. Now edit [engine/battle/ai/items.asm](../blob/master/engine/battle/ai/items.asm): ```diff AI_Items: dbw FULL_RESTORE, .FullRestore ... dbw X_SPECIAL, .XSpecial + dbw SWEET_HEART, .SweetHeart db -1 ; end ... .Potion: call .HealItem jp c, .DontUse ld b, 20 call EnemyUsedPotion jp .Use + +.SweetHeart: + call .HealItem + jp c, .DontUse + ld b, 20 + call EnemyUsedSweetHeart + jp .Use ... EnemyUsedPotion: ld a, POTION ld b, 20 jr EnemyPotionContinue + +EnemyUsedSweetHeart: + ld a, SWEET_HEART + ld b, 20 + jr EnemyPotionContinue ``` Now if a trainer has a Sweet Heart (as defined in [data/trainers/attributes.asm](../blob/master/data/trainers/attributes.asm)) they'll be able to use it. The `.HealItem` subroutine called by `.SweetHeart` determines whether the healing item will be used, with different random chances when the enemy has half or a quarter of their HP left; and the `EnemyPotionContinue` routine does the whole process of restoring HP, animating the HP bar, playing the sound effect, etc. ![Screenshot](screenshots/sweet-heart.png) ### `StatusHealingEffect`: Lava Cookie A Lava Cookie, from Gen 3, heals any status condition, just like Full Heal. It can be used on the field or during battle, and enemy trainer AI should know how to use one too. First, add the essential data. Replace `ITEM_32` with `LAVA_COOKIE`; give it a name, description, and attributes (`200, HELD_NONE, 0, CANT_SELECT, ITEM, ITEMMENU_PARTY, ITEMMENU_PARTY`); give it the `StatusHealingEffect`; and remove `ITEM_32` from `TimeCapsule_CatchRateItems`. Then it's time to implement the specific status-healing effect. Edit [data/items/heal_status.asm](../blob/master/data/items/heal_status.asm): ```diff StatusHealingActions: ; item, party menu action text, status db ANTIDOTE, PARTYMENUTEXT_HEAL_PSN, 1 << PSN ... db MIRACLEBERRY, PARTYMENUTEXT_HEAL_ALL, %11111111 + db LAVA_COOKIE, PARTYMENUTEXT_HEAL_ALL, %11111111 db -1, 0, 0 ; end ``` `%11111111` is a bit mask for all status conditions, but that particular value is checked for by `HealStatus` to allow healing confusion as well. A different value, like `1 << PSN` or `(1 << BRN) | (1 << FRZ)`, could be used to heal only certain conditions. `StatusHealingActions` is used by `GetItemHealingAction`, which is called by `UseStatusHealer`, which is called by `StatusHealingEffect`, which is the effect we already assigned to Lava Cookie; so now it will successfully heal all status conditions when used by the player. Now edit [engine/battle/ai/items.asm](../blob/master/engine/battle/ai/items.asm): ```diff AI_Items: dbw FULL_RESTORE, .FullRestore ... dbw X_SPECIAL, .XSpecial + dbw LAVA_COOKIE, .LavaCookie db -1 ; end .FullHeal: call .Status jp c, .DontUse call EnemyUsedFullHeal jp .Use + +.LavaCookie: + call .Status + jp c, .DontUse + call EnemyUsedLavaCookie + jp .Use ... EnemyUsedFullHeal: call AIUsedItemSound call AI_HealStatus ld a, FULL_HEAL jp PrintText_UsedItemOn_AND_AIUpdateHUD + +EnemyUsedLavaCookie: + call AIUsedItemSound + call AI_HealStatus + ld a, LAVA_COOKIE + jp PrintText_UsedItemOn_AND_AIUpdateHUD ``` Now if a trainer has a Lava Cookie (as defined in [data/trainers/attributes.asm](../blob/master/data/trainers/attributes.asm)) they'll be able to use it. The `.Status` subroutine called by `.LavaCookie` determines whether the healing item will be used, with different random chances depending on the enemy AI and the battle situation; and the `EnemyUsedLavaCookie` routine does the whole process of healing status, playing the sound effect, etc. ![Screenshot](screenshots/lava-cookie.png) ### `PokeBallEffect`: Dusk Ball A Dusk Ball, from Gen 4, has a 3.5× catch rate if used in caves or at night. First, add the essential data. Replace `ITEM_5A` with `DUSK_BALL`; give it a name, description, and attributes (`1000, HELD_NONE, 0, CANT_SELECT, BALL, ITEMMENU_NOUSE, ITEMMENU_CLOSE`); give it the `PokeBallEffect`; and remove `ITEM_5A` from `TimeCapsule_CatchRateItems`. A piece of data specific to Poké Balls is what color they are when thrown in battle. Edit [data/battle_anims/ball_colors.asm](../blob/master/data/battle_anims/ball_colors.asm): ```diff BallColors: db MASTER_BALL, PAL_BATTLE_OB_GREEN ... db LOVE_BALL, PAL_BATTLE_OB_RED + db DUSK_BALL, PAL_BATTLE_OB_GREEN db -1, PAL_BATTLE_OB_GRAY ``` Then it's time to implement the specific Pokémon-catching effect. Edit [engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm) again: ```diff BallMultiplierFunctionTable: ; table of routines that increase or decrease the catch rate based on ; which ball is used in a certain situation. dbw ULTRA_BALL, UltraBallMultiplier ... dbw PARK_BALL, ParkBallMultiplier + dbw DUSK_BALL, DuskBallMultiplier db -1 ; end +DuskBallMultiplier: +; is it night? + ld a, [wTimeOfDay] + cp NITE + jr z, .night_or_cave +; or are we in a cave? + ld a, [wEnvironment] + cp CAVE + jr z, .night_or_cave +; neither night nor cave + ret + +.night_or_cave +; b is the catch rate +; a := b / 2 + b + b + b == b × 3.5 + ld a, b + srl a +rept 3 + add b + jr c, .max +endr + ret + +.max + ld b, $ff + ret ``` `DuskBallMultiplier`, like all the Ball multiplier routines, just has to modify `b` according to the relevant factors. If it's nighttime or we're in a cave, it multiplies `b` by 3.5; otherwise it doesn't modify `b`. ![Screenshot](screenshots/dusk-ball.png) ### `EvoStoneEffect`: Mist Stone A Mist Stone is a rumored item from Gen 1 that evolves Pokémon into "PokéGods". A more realistic function would be to evolve Pokémon like Machoke or Haunter that otherwise require trading, which can be inconvenient. First, add the essential data. Replace `ITEM_64` with `MIST_STONE`; give it a name, description, and attributes (`2100, HELD_NONE, 0, CANT_SELECT, ITEM, ITEMMENU_PARTY, ITEMMENU_NOUSE`); give it the `EvoStoneEffect`; and remove `ITEM_64` from `TimeCapsule_CatchRateItems`. That's actually all you need to do for the item itself. Now as long as it's declared to evolve a Pokémon, it will do so correctly. Edit [data/pokemon/evos_attacks.asm](../blob/master/data/pokemon/evos_attacks.asm): ```diff KadabraEvosAttacks: + db EVOLVE_ITEM, MIST_STONE, ALAKAZAM db EVOLVE_TRADE, -1, ALAKAZAM db 0 ; no more evolutions ... MachokeEvosAttacks: + db EVOLVE_ITEM, MIST_STONE, MACHAMP db EVOLVE_TRADE, -1, MACHAMP db 0 ; no more evolutions ... GravelerEvosAttacks: + db EVOLVE_ITEM, MIST_STONE, GOLEM db EVOLVE_TRADE, -1, GOLEM db 0 ; no more evolutions ... HaunterEvosAttacks: + db EVOLVE_ITEM, MIST_STONE, GENGAR db EVOLVE_TRADE, -1, GENGAR db 0 ; no more evolutions ... ``` (Note that if a Pokémon has too many evolution methods, they'll say "NOT ABLE" to evolve with an item even if they are. This is a known bug with `PlacePartyMonEvoStoneCompatibility` and has [a simple solution](../blob/master/docs/bugs_and_glitches.md#only-the-first-three-evolution-entries-can-have-stone-compatibility-reported-correctly).) ![Screenshot](screenshots/mist-stone.png) ### `XItemEffect`: X Sp.Def X Sp.Def, from Gen 4, boosts Special Defense by one stage in battle. It can only be used during battle, and enemy trainer AI should know how to use one too. (In Gen 1, X Special boosted the single Special stat. Gen 2 split Special into Attack and Defense, but X Special only boosted Special Attack, and it took until Gen 4 to split the item as well into X Sp.Atk and X Sp.Def.) First, add the essential data. Replace `ITEM_78` with `X_SP_DEF`; give it a name, description, and attributes (`350, HELD_NONE, 0, CANT_SELECT, ITEM, ITEMMENU_NOUSE, ITEMMENU_CLOSE`); give it the `XItemEffect`; and remove `ITEM_78` from `TimeCapsule_CatchRateItems`. A piece of data specific to X items is which stat they boost. Edit [data/items/x_stats.asm](../blob/master/data/items/x_stats.asm): ```diff XItemStats: ; item, stat db X_ATTACK, ATTACK db X_DEFEND, DEFENSE db X_SPEED, SPEED db X_SPECIAL, SP_ATTACK + db X_SP_DEF, SP_DEFENSE ``` `XItemStats` is used by `XItemEffect`, so now it will successfully boost Special Defense when used by the player. Now edit [engine/battle/ai/items.asm](../blob/master/engine/battle/ai/items.asm): ```diff AI_Items: dbw FULL_RESTORE, .FullRestore ... dbw X_SPECIAL, .XSpecial + dbw X_SP_DEF, .XSpDef db -1 ; end ... .XSpecial: call .XItem jp c, .DontUse call EnemyUsedXSpecial jp .Use + +.XSpDef: + call .XItem + jp c, .DontUse + call EnemyUsedXSpDef + jp .Use ... +EnemyUsedXSpDef: + ld b, SP_DEFENSE + ld a, X_SP_DEF + jr EnemyUsedXItem EnemyUsedXSpecial: ld b, SP_ATTACK ld a, X_SPECIAL ; Parameter ; a = ITEM_CONSTANT ; b = BATTLE_CONSTANT (ATTACK, DEFENSE, SPEED, SP_ATTACK, SP_DEFENSE, ACCURACY, EVASION) EnemyUsedXItem: ... ``` Now if a trainer has an X Sp.Def (as defined in [data/trainers/attributes.asm](../blob/master/data/trainers/attributes.asm)) they'll be able to use it. The `.XItem` subroutine called by `.XSpDef` determines whether the healing item will be used, with different random chances depending on the enemy AI and the battle situation; and the `EnemyUsedXSpDef` routine does the whole process of boosting the stat, playing the sound effect, etc. ![Screenshot](screenshots/x-sp-def.png) Note that I named it "X SPCL.DEF", not "X SP.DEF", because that's the naming convention for stats in Gen 2. I also renamed "X SPECIAL" to "X SPCL.ATK" so they match. ### `TownMapEffect`: Town Map The Town Map was present in Gen 1 but replaced in Gen 2 by the Pokégear's Map Card; however, it still exists in the code. Its `TownMapEffect` implementation is buggy, but can be fixed. First, add the essential data. The `TOWN_MAP` item constant already exists, but it needs a proper name, description, and attributes (`0, HELD_NONE, 0, CANT_SELECT | CANT_TOSS, KEY_ITEM, ITEMMENU_CURRENT, ITEMMENU_NOUSE`). Now fix the effect. Edit [engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm): ```diff TownMapEffect: - farcall PokegearMap + call FadeToMenu + farcall _TownMap + call Call_ExitMenu + xor a + ldh [hBGMapMode], a + farcall Pack_InitGFX + farcall WaitBGMap_DrawPackGFX + farcall Pack_InitColors ret ``` This code is based on how items with `ITEMMENU_PARTY` work, as written in `UseItem.Party` in [engine/items/pack.asm](../blob/master/engine/items/pack.asm). ![Screenshot](screenshots/town-map.png) ### Held effect: Eviolite Eviolite, from Gen 5, boosts Defense and Special Defense by 50% if held by a Pokémon that is not fully evolved. First, add the essential data. Replace `ITEM_87` with `EVIOLITE`; give it a name, description, and attributes (`200, HELD_EVIOLITE, 0, CANT_SELECT, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE`); give it `NoEffect` (it has a *held* effect, but no *used* effect); and remove `ITEM_87` from `TimeCapsule_CatchRateItems`. `HELD_EVIOLITE` has not been defined yet, so we'll do that next. Edit [constants/item_data_constants.asm](../blob/master/constants/item_data_constants.asm): ```diff const_def 40 const HELD_40 const HELD_41 const HELD_METAL_POWDER + const HELD_EVIOLITE ``` Two things to note about these `HELD_*` constants. One, they're not a continuous sequence; Game Freak usually grouped related ones together, starting from round numbers like 40. This was probably just to make it easier to deal with the raw numeric values, using the less powerful development tools of the late 90s. Two, there's no data associated with these constants. They're just unique values that the battle engine can check for in any arbitrary circumstances. If one of them is unused, like `HELD_40` and `HELD_41`, you can always replace it with something useful. In other words, adding an effect for `HELD_EVIOLITE` won't involve updating any data tables; we'll just have to write some all-new assembly code. So if you want to design an original held item, you'll have to become familiar with how the battle engine works, and figure out which parts need updating to accomodate your item. Eviolite's effect is pretty similar to Metal Powder, which boosts Ditto's defenses. Searching through the battle engine code for references to `METAL_POWDER` finds that it's implemented as a `DittoMetalPowder` routine, which gets called in two places, one for the player and one for the enemy. (Note that it checks directly for whether the held item is `METAL_POWDER`, not whether the held item's effect is `HELD_METAL_POWDER`. Either check would be okay, though.) Anyway, edit [engine/battle/effect_commands.asm](../blob/master/engine/battle/effect_commands.asm): ```diff DittoMetalPowder: ... +UnevolvedEviolite: +; get the defender's species + ld a, MON_SPECIES + call BattlePartyAttr + ldh a, [hBattleTurn] + and a + ld a, [hl] + jr nz, .Unevolved + ld a, [wTempEnemyMonSpecies] + +.Unevolved: +; check if the defender has any evolutions +; hl := EvosAttacksPointers + (species - 1) * 2 + dec a + push hl + push bc + ld c, a + ld b, 0 + ld hl, EvosAttacksPointers + add hl, bc + add hl, bc +; hl := the species' entry from EvosAttacksPointers + ld a, BANK(EvosAttacksPointers) + call GetFarHalfword +; a := the first byte of the species' *EvosAttacks data + ld a, BANK("Evolutions and Attacks") + call GetFarByte +; if a == 0, there are no evolutions, so don't boost stats + and a + pop bc + pop hl + ret z + +; check if the defender's item is Eviolite + push bc + call GetOpponentItem + ld a, b + cp HELD_EVIOLITE + pop bc + ret nz + +; boost the relevant defense stat in bc by 50% + ld a, c + srl a + add c + ld c, a + ret nc + + srl b + ld a, b + and a + jr nz, .done + inc b +.done + scf + rr c + ret PlayerAttackDamage: ; Return move power d, player level e, enemy defense c and player attack b. ... ld a, [wBattleMonLevel] ld e, a call DittoMetalPowder + call UnevolvedEviolite ld a, 1 and a ret ... EnemyAttackDamage: ... ld a, [wEnemyMonLevel] ld e, a call DittoMetalPowder + call UnevolvedEviolite ld a, 1 and a ret ``` The implementation of `UnevolvedEviolite` is very similar to `DittoMetalPowder`, except the simple check for whether the species is `DITTO` has been replaced by a check for evolutions, similar to the check in `MoonBallMultiplier` in [engine/items/item_effects.asm](../blob/master/engine/items/item_effects.asm). (Also, instead of checking whether `[hl]` is `EVIOLITE`, we check whether `b` is `HELD_EVIOLITE`; either would be fine, since `GetOpponentItem` returns "the effect of the opponent's item in `bc`, and its id at `hl`", as explained in a comment.) `bc` gets repeatedly saved on the stack with `push` and `pop` because it contains the defense stat, and we don't want the various pre-boost checks to corrupt the original value. In general, if you're implementing a custom held item effect, think about which items have similar effects, and which other code might already do something like what you want. ![Screenshot](screenshots/eviolite.png) ## 4. Adding up to 254 items Like most IDs in pokecrystal, item IDs are one byte each, so they can go from 0 to 255. Item $00 is `NO_ITEM` and $FF (−1) is an end-of-list marker, which leaves 254 usable IDs. We've been replacing unused items with useful ones, but in principle you can also add new items (as long as you're careful to arrange regular items before TMs, then HMs last). Only 251 item constants are defined, from `NO_ITEM` to `ITEM_FA`, but the tables of `ItemNames`, `ItemDescriptions`, and `ItemAttributes` already have 256 entries each (and `ItemEffects` has entries for every regular item; the TMs and HMs don't use effects). So just be careful to keep the constants and all those tables in sync. Remember that adding a new constant in the middle of a sequence will shift all the ones after it. If `make` gives you the error "Expression must be 8-bit", you're probably using an ID constant greater than 255, which won't fit in one byte (eight bits). Double-check the constants and make sure they're all between $00 and $FF. It's easy to forget about the useless `ITEM_FA` at the very end, which can end up shifted beyond the 8-bit range if you add too many new items. Feel free to delete it, and remove its entry from `TimeCapsule_CatchRateItems` (the only place `ITEM_FA` is ever used).