-
Notifications
You must be signed in to change notification settings - Fork 817
Add a Move Reminder
This tutorial details the process of adding a Move Reminder NPC to Pokémon Crystal.
This provides a way to teach Pokémon moves that were either skipped over during level up or deleted to make room for another.
The code is extensively documented with comments that describe what each block of code is executing. Therefore, it is important to review the comments before making any changes to ensure functionality.
This tutorial provides compatibility code for all of the optional customisations, allowing them to be easily implemented in any order. It is designed to minimise confusion because the required modifications can vary significantly depending on the implementation order.
As such, when making changes to code blocks (including comments), it is important to update the compatibility code after making changes to the default Move Reminder's code. Failure to do so can lead to confusion for readers attempting to implement any of the optional customisations.
Note that care was taken to avoid excessive compatibility code. This was done by omitting some portions of the code above or below the relevant code block in some of the code block diffs. For example, in step 7 of the Pay for Each Move Learned section, the code below the relevant code block is included as it remains consistent, but the code above is omitted because it may vary.
- 1. Choose a name for the Move Reminder NPC
- 2. Define a New File to Be Imported
- 3. Create a Special Pointer
- 4. Create the Move Reminder NPC
- 5. Define a New WRAM Label
- 6. Move Reminder Routine
- 7. Customisations
- 8. Credits
There are a number of names (both official and unofficial) for this NPC such as:
- Move Relearner
- Move Tutor
- Move Maniac
- Move Teacher
- Pokémon Move Maniac
- Reminder Girl
- Madam Reminder
- Madam Memorial
For the purposes of this tutorial, Move Reminder
will be used as the name of the NPC. However, the reader is free to to decide on what name to give to this NPC.
In this first section we will be adding a file (which we will soon create) to the list of files that will be imported into the game.
We can add this to any section we like, but it is important to ensure that there is enough space. If there isn't enough space, we would encounter a Sections would extend past the end of ROMX
error while compiling. Dealing with this error is beyond the scope of this tutorial.
For this tutorial, we will be using bankB
.
Edit main.asm:
SECTION "bankB", ROMX
INCLUDE "engine/battle/trainer_huds.asm"
INCLUDE "data/trainers/class_names.asm"
INCLUDE "engine/battle/ai/redundant.asm"
INCLUDE "engine/events/move_deleter.asm"
+INCLUDE "engine/events/move_reminder.asm"
INCLUDE "engine/link/mystery_gift_2.asm"
INCLUDE "engine/items/tmhm.asm"
INCLUDE "engine/pokemon/print_move_description.asm"
INCLUDE "engine/events/pokerus/pokerus.asm"
INCLUDE "engine/battle/start_battle.asm"
INCLUDE "engine/gfx/place_graphic.asm"
In order to call the move reminder routine from a script, a special pointer will have to be created. This will allow the special MoveReminder
command to work.
Edit data/events/special_pointers.asm:
add_special InitialSetDSTFlag
add_special InitialClearDSTFlag
add_special UnusedDummySpecial ; unused
+
+ add_special MoveReminder
Now we need to create the Move Reminder NPC object, make it perform the MoveReminder
special routine when interacted with and place it in the game world.
Choose a map that the Move Reminder NPC will appear in and open the .asm file for that map. For the purposes of this tutorial, we will use the Move Deleter's House.
First we will add a new object constant for the Move Reminder NPC (this is not necessary for this tutorial, but it is essential for controlling them outside of this script).
Edit maps/MoveDeletersHouse.asm:
object_const_def
const MOVEDELETERSHOUSE_SUPER_NERD
+ const MOVEDELETERSHOUSE_GRAMPS
Keep this file open for the next step.
Now we will add an object script that will execute when the player interacts with an object (the Move Reminder NPC in this case).
Note: Scripts can also be executed via coordinate events, background events and other scripts but that is beyond the scope of this tutorial.
Within that script we will have it perform the following commands:
- Make the Move Reminder NPC face the player.
- Show a text box.
- Call the special routine that we created previously.
- Wait until a button is pressed to proceed.
- Close the text box.
- Call for an end to the script's routine.
This script can be placed anywhere in this file as long as it is not interrupting other code. For consistency, it should be placed where other NPC scripts are located.
We are going to place it below all the other NPC scripts.
Here is what it will look like:
MoveDeleter:
faceplayer
opentext
special MoveDeletion
waitbutton
closetext
end
+
+MoveReminder:
+ faceplayer
+ opentext
+ special MoveReminder
+ waitbutton
+ closetext
+ end
MoveDeletersHouseBookshelf:
jumpstd DifficultBookshelfScript
Keep this file open for the next step.
The last thing we have to do in respect to the NPC object, is to add it to the map. We will define its initial location, select its sprite, give it movement patterns (in this tutorial it is static and does not move), its colour palette and more.
Please view macros/scripts/maps.asm and search for the comments under MACRO object_event
for information regarding the options available for defining object events.
For the purposes of this tutorial, we will duplicate Move Deleter's sprite move data (SPRITEMOVEDATA_STANDING_DOWN
), use SPRITE_GRAMPS
for the NPC's appearance and use MoveReminder
as the object script and place it on the opposite end of the table.
def_object_events
object_event 2, 3, SPRITE_SUPER_NERD, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, MoveDeleter, -1
+ object_event 5, 3, SPRITE_GRAMPS, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, MoveReminder, -1
As we are placing the Move Reminder NPC in the Move Deleter's house, the sign outside the house in Blackthorn City should be updated to mention the Move Reminder NPC as well.
Edit maps/BlackthornCity.asm:
MoveDeletersHouseSignText:
- text "MOVE DELETER'S"
- line "HOUSE"
+ text "MOVE DELETER"
+ line "and REMINDER'S"
+ cont "HOUSE"
done
The move reminder routine utilizes various WRAM labels for their designated purposes. However, we also need a WRAM label to store the power points (PP) for each move and another to store the moves in the menu. However, there are no existing WRAM labels solely allocated for these tasks. Therefore, we must either repurpose an existing WRAM label while ensuring no conflicts arise or create a new one.
For the purposes of this tutorial, we will be both using an existing WRAM label (wd002
) and creating a new one (wBuffer1
).
Note: The existing wd002
WRAM label has been proven to not cause any conflicts by others who have used it while implementing their own Move Reminder NPC. If the reader would like to use another existing WRAM label instead of creating one, then ensure that WRAM label is not being used elsewhere during the execution of the move reminder routine.
Find an unused byte, delete it (or comment it out) and add the new WRAM label.
Tip: Look for unused bytes that have a line break both above and below it. These are safe to use.
Also, if the number is greater than one, then ensure that the leftover unused bytes are defined underneath. For example, if taking a byte from ds 7
, delete (or comment it out), add the new WRAM label and define ds 6
underneath it (preferably with a line break between them). This will keep all unused bytes visible for later use.
We will be inserting a new WRAM label in between the wBattleMenuCursorPosition
and wCurBattleMon
WRAM labels.
Edit ram/wram.asm:
wBattleMenuCursorPosition:: db
- ds 1
+wBuffer1:: db
wCurBattleMon::
This file contains the entire move reminder routine and all the text. It will need to be created and placed in the engine/events/
directory. Name it move_reminder.asm
.
Create engine/events/move_reminder.asm:
Click here to expand the code
MoveReminder:
; Loads and prints the "MoveReminderIntroText" text.
; Then prompts the player to select "YES" or "NO".
; Relative jump to the ".cancel" local jump
; if the player selected "NO" and continue
; if the player selected "YES".
ld hl, MoveReminderIntroText
call PrintText
call YesNoBox
jr c, .cancel
; Loads and prints the "MoveReminderWhichMonText" text.
ld hl, MoveReminderWhichMonText
call PrintText
; Loads the party menu to select a Pokémon. Relative jump
; to the ".cancel" local jump if the player leaves
; the party menu without selecting anything.
farcall SelectMonFromParty
jr c, .cancel
; Checks if the current selection is an egg. Relative jump to
; the ".is_an_egg" local jump if so and continue if not.
ld a, [wCurPartySpecies]
cp EGG
jr z, .is_an_egg
; Checks if the current selection is not a Pokémon. Relative jump to
; the ".not_a_pokemon" local jump if so and continue if not.
; Prevents continuing if glitched Pokémon are selected.
call IsAPokemon
jr c, .not_a_pokemon
; Checks for any moves that can be learned. Relative
; jump to the ".no_moves_to_learn" local jump if
; there are none and continue if there are.
call GetRemindableMoves
jr z, .no_moves_to_learn
; Loads and prints the "MoveReminderWhichMoveText" text.
ld hl, MoveReminderWhichMoveText
call PrintText
; Generates the Move Reminder's menu. Relative jump to the
; ".exit_menu" local jump if the player leaves
; the menu and continue if they do not.
call ChooseMoveToLearn
jr c, .exit_menu
; If the player selects a move, load the move's name and copy
; it for later. This is used for displaying the move's
; name in some of the text boxes while learning a move.
ld a, [wMenuSelection]
ld [wNamedObjectIndex], a
call GetMoveName
call CopyName1
; Begins the process of learning a move.
; The "LearnMove" label sets the value of the "b" register to "1"
; when a move is successfully learned and sets it to "0" if
; cancelled at any point in the move learning process.
predef LearnMove
; Relative jump to the ".move_learned" local jump if
; a move has been learned and continue if not.
ld a, b
dec a
jr z, .move_learned
; This code falls through into the ".exit_menu" local jump.
; Exits the menu and goes back to the
; map with a speech text box open.
.exit_menu
call ReturnToMapWithSpeechTextbox
; This code falls through into the ".cancel" local jump.
; Loads and prints the "MoveReminderCancelText" text.
; This ends the dialogue.
.cancel
ld hl, MoveReminderCancelText
jp PrintText
; Loads and prints the "MoveReminderEggText" text.
; This ends the dialogue.
.is_an_egg
ld hl, MoveReminderEggText
jp PrintText
; Loads and prints the "MoveReminderNotaMonText" text.
; This ends the dialogue.
.not_a_pokemon
ld hl, MoveReminderNotaMonText
jp PrintText
; Loads and prints the "MoveReminderNoMovesText" text.
; This ends the dialogue.
.no_moves_to_learn
ld hl, MoveReminderNoMovesText
jp PrintText
; Exits the menu and goes back to the map with a
; speech text box open and then loads and prints
; the "MoveReminderMoveLearnedText" text.
; This ends the dialogue.
.move_learned
call ReturnToMapWithSpeechTextbox
ld hl, MoveReminderMoveLearnedText
jp PrintText
; Checks for moves that can be learned and returns
; a zero flag if there are none.
GetRemindableMoves:
; The "wd002" wram label is being used to store
; the moves for placement in the move list.
ld hl, wd002
xor a
ld [hli], a
ld [hl], $ff
; Retrieves and stores the species of
; the currently selected Pokémon.
ld a, MON_SPECIES
call GetPartyParamLocation
ld a, [hl]
ld [wCurPartySpecies], a
; Retrieves and stores the level of the
; currently selected Pokémon.
push af
ld a, MON_LEVEL
call GetPartyParamLocation
ld a, [hl]
ld [wCurPartyLevel], a
; The "b" register will contain the number of
; moves in the move list and "wd002 + 1"
; is where the move list begins.
ld b, 0
ld de, wd002 + 1
; Retrieves the currently selected Pokémon's evolution
; and attack address from the "EvosAttacksPointers"
; table that is located in another bank. This is the
; list of evolutions and learnset of every Pokémon.
ld a, [wCurPartySpecies]
dec a
push bc
ld c, a
ld hl, EvosAttacksPointers
add hl, bc
add hl, bc
ld a, BANK(EvosAttacksPointers)
call GetFarWord
; Skips the evolution data to start at the learnset for the
; currently selected Pokémon in the "EvosAttacksPointers"
; table. This is "db 0 ; no more evolutions".
.skip_evos
ld a, BANK("Evolutions and Attacks")
call GetFarByte
inc hl
and a
jr nz, .skip_evos
; Loops through the move list until it reaches
; the end of the "EvosAttacksPointers" table
; for the currently selected Pokémon. This is
; "db 0 ; no more level-up moves".
; It then compares the currently selected Pokémon's
; level with the level the move is learned at and
; if the Pokémon's level is higher, it will
; attempt to add the move to the move list.
.loop_moves
ld a, BANK("Evolutions and Attacks")
call GetFarByte
inc hl
and a
jr z, .done
ld c, a
ld a, [wCurPartyLevel]
cp c
ld a, BANK("Evolutions and Attacks")
call GetFarByte
inc hl
jr c, .loop_moves
; Checks if the move is already in the
; move list or already learned by the
; Pokémon. If both are false, then the
; move will be added to the move list.
ld c, a
call CheckAlreadyInList
jr c, .loop_moves
call CheckPokemonAlreadyKnowsMove
jr c, .loop_moves
ld a, c
ld [de], a
inc de
ld a, $ff
ld [de], a
pop bc
inc b
push bc
jr .loop_moves
; Adds all the possible moves the currently
; selected Pokémon can learn into "wd002".
; Which is the move list.
.done
pop bc
pop af
ld [wCurPartySpecies], a
ld a, b
ld [wd002], a
and a
ret
; Checks if there is a move already placed
; in the move list. This prevents
; duplicate entries in the move list.
CheckAlreadyInList:
push hl
ld hl, wd002 + 1
.loop
ld a, [hli]
inc a
jr z, .nope
dec a
cp c
jr nz, .loop
pop hl
scf
ret
.nope
pop hl
and a
ret
; Checks if a Pokémon already knows a move. This
; prevents the player teaching the currently
; selected Pokémon a move it already knows.
CheckPokemonAlreadyKnowsMove:
push hl
push bc
ld a, MON_MOVES
call GetPartyParamLocation
ld b, 4
.loop
ld a, [hli]
cp c
jr z, .yes
dec b
jr nz, .loop
pop bc
pop hl
and a
ret
.yes
pop bc
pop hl
scf
ret
; Creates a scrolling menu and sets up the menu gui.
; The number of items is stored in "wd002"
; The list of items is stored in "wd002 + 1"
ChooseMoveToLearn:
farcall FadeOutToWhite
farcall BlankScreen
ld hl, .MenuHeader
call CopyMenuHeader
xor a
ld [wMenuCursorPosition], a
ld [wMenuScrollPosition], a
; This creates a border around the move list.
; "hlcoord" configures the position.
; "lb bc" configures the size.
hlcoord 0, 1
lb bc, 9, 18
call TextboxBorder
; This replaces the tile using the identifier
; of "$6e" with the fourteenth tile of the
; "FontBattleExtra gfx" font. Also, only 1
; tile will be loaded as loading the entire
; "FontBattleExtra gfx" font will overwrite
; the "UP" arrow in the menu.
ld de, FontBattleExtra + 14 tiles
ld hl, vTiles2 tile $6e
lb bc, BANK(FontBattleExtra), 1
call Get2bppViaHDMA
; This is used for displaying the symbol that
; appears before the Pokémon's level. Without
; it, an incorrect symbol will appear.
farcall LoadStatsScreenPageTilesGFX
; This displays the Pokémon's species
; name (not nickname) at the
; coordinates defined at "hlcoord".
; In this case that is the
; top left of the screen.
xor a
ld [wMonType], a
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
hlcoord 5, 1
call PlaceString
; This displays the Pokémon's level
; right after the Pokémon's name.
push bc
farcall CopyMonToTempMon
pop hl
call PrintLevel
; Creates the menu, sets the "B_BUTTON"
; to cancel and sets up each entry
; to behave like a tm/hm.
call ScrollingMenu
ld a, [wMenuJoypad]
cp B_BUTTON
jr z, .carry
ld a, [wMenuSelection]
ld [wPutativeTMHMMove], a
and a
ret
; Sets the carry flag and returns from
; this subroutine. Setting the carry
; flag being set will cause the
; menu to exit after returning.
.carry
scf
ret
; The menu header defines the menu's position and
; what will be included. The last two values
; of "menu_coords" will determine where the
; vertical scroll arrows will be located.
.MenuHeader:
db MENU_BACKUP_TILES
menu_coords 1, 2, SCREEN_WIDTH - 2, 10
dw .MenuData
db 1
; This sets up the menu's contents, including the amount
; of entries displayed before scrolling is required.
; Vertical scroll arrows and the move's
; details will be displayed.
; This menu is populated with an item and three functions.
; The item is "wd002".
; Function 1 is the ".print_move_name" local jump.
; Function 2 is the ".print_pp" local jump.
; Function 3 is the ".print_move_details" local jump.
.MenuData:
db SCROLLINGMENU_DISPLAY_ARROWS | SCROLLINGMENU_ENABLE_FUNCTION3
db 4, SCREEN_WIDTH + 2
db SCROLLINGMENU_ITEMS_NORMAL
dba wd002
dba .print_move_name
dba .print_pp
dba .print_move_details
; This prints the move's name in the menu.
; This is purely visual as the actual
; entry is stored in "wd002".
.print_move_name
push de
ld a, [wMenuSelection]
ld [wNamedObjectIndex], a
call GetMoveName
pop hl
jp PlaceString
; This prints the move's pp offset by one
; line with some spacing from the left.
.print_pp
ld hl, wStringBuffer1
ld bc, wStringBuffer2 - wStringBuffer1
ld a, " "
call ByteFill
ld a, [wMenuSelection]
inc a
ret z
dec a
push de
ld a, [wMenuSelection]
ld bc, MOVE_LENGTH
ld hl, (Moves + MOVE_PP) - MOVE_LENGTH
call AddNTimes
ld a, BANK(Moves)
call GetFarByte
ld [wBuffer1], a
ld hl, wStringBuffer1 + 9
ld de, wBuffer1
lb bc, 1, 2
call PrintNum
ld hl, wStringBuffer1 + 11
ld [hl], "/"
ld hl, wStringBuffer1 + 12
call PrintNum
ld hl, wStringBuffer1 + 14
ld [hl], "@"
pop hl
ld de, wStringBuffer1
call PlaceString
; This prints the pp gfx before the move's pp.
ld bc, 6
add hl, bc
ld a, $3e
ld [hli], a
ld [hl], a
ret
; This adds a text box border line to the description
; box that replaces a leftover piece of the notch
; that remains when the cancel option is highlighted.
.cancel_border_fix
hlcoord 0, 10
ld [hl], "│"
inc hl
ret
; This begins the printing of all of the move's details,
; including the border around the description.
.print_move_details
; This creates a border around the description.
hlcoord 0, 11
lb bc, 5, 18
call TextboxBorder
; This code will relative jump to the
; ".cancel_border_fix" local jump if
; the cancel entry is highlighted.
ld a, [wMenuSelection]
cp -1
jr z, .cancel_border_fix
; This code falls through into the ".print_move_desc" local jump.
; This prints the moves description.
.print_move_desc
push de
ld a, [wMenuSelection]
inc a
pop de
ret z
dec a
ld [wCurSpecies], a
hlcoord 1, 14
predef PrintMoveDescription
; This code falls through into the ".print_move_type" local jump.
; This prints the move's type.
.print_move_type
ld a, [wCurSpecies]
ld b, a
hlcoord 2, 12
predef PrintMoveType
; This code falls through into the ".print_move_stat_strings" local jump.
; This prints the notch in the description text box border
; and the "TYPE/" and "ATK/" strings.
.print_move_stat_strings
hlcoord 0, 10
ld de, MoveTypeTopString
call PlaceString
hlcoord 0, 11
ld de, MoveTypeString
call PlaceString
hlcoord 12, 12
ld de, MoveAttackString
call PlaceString
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
ld a, [wMenuSelection]
ld bc, MOVE_LENGTH
ld hl, (Moves + MOVE_POWER) - MOVE_LENGTH
call AddNTimes
ld a, BANK(Moves)
call GetFarByte
cp 2
jr c, .print_move_null_attack
ld [wBuffer1], a
ld de, wBuffer1
lb bc, 1, 3
hlcoord 16, 12
jp PrintNum
; This prints "---" if the move has an attack of "0".
; This means that the move does not initially cause
; damage or is a one hit knockout move.
.print_move_null_attack
hlcoord 16, 12
ld de, MoveNullValueString
ld bc, 3
jp PlaceString
; This is a notch that will be placed on
; the top left of the description box.
MoveTypeTopString:
db "┌─────┐@"
; This is the string that displays
; above the move's type.
MoveTypeString:
db "│TYPE/└@"
; This is the string that precedes
; the move's attack number.
MoveAttackString:
db "ATK/@"
; This displays when a move has
; a metric with a null value.
MoveNullValueString:
db "---@"
; This is the text that displays when the player
; first talks to the move reminder.
MoveReminderIntroText:
text "Hi, I'm the Move"
line "Reminder!"
para "I can make #MON"
line "remember moves."
para "Are you"
line "interested?"
done
; This is the text that displays just
; before the party menu opens.
MoveReminderWhichMonText:
text "Which #MON?"
prompt
; This is the text that displays after
; a Pokémon has been selected.
MoveReminderWhichMoveText:
text "Which move should"
line "it remember, then?"
prompt
; This is the text that displays just before
; the player ends the dialogue
; with the move reminder.
MoveReminderCancelText:
text "Come visit me"
line "again."
done
; This is the text that displays if the player
; selects an egg in the party menu.
MoveReminderEggText:
text "An EGG can't learn"
line "any moves!"
done
; This is the text that displays if the player
; selects an entry in the party menu that
; is neither a Pokémon or an egg.
MoveReminderNotaMonText:
text "What is that!?"
para "I'm sorry, but I"
line "can only teach"
cont "moves to #MON!"
done
; This is the text that displays if the player
; selects a Pokémon in the party menu that
; has no moves that can be learned.
MoveReminderNoMovesText:
text "There are no moves"
line "for this #MON"
cont "to learn."
done
; This is the text that displays after a
; Pokémon successfully learns a move.
MoveReminderMoveLearnedText:
text "Done! Your #MON"
line "remembered the"
cont "move."
done
Now the Move Reminder has been fully implemented.
There are a few optional customisations/modifications/upgrades that can be implemented if the reader chooses to.
Compatibility code is provided for all of the customisations, allowing them to be easily implemented in any order.
Note: Adding more Pokémon/move types, such as FAIRY
, will not require any additional modifications and will display as expected.
If the reader has implemented the Physical Special Split tutorial, the Move Reminder's menu can be modified to match the changes made to the move screen for consistency and to provide more information about each move.
Note: Implementing this section is optional as even if the reader has implemented the Physical Special Split tutorial, there will not be any functional issues with the Move Reminder's menu.
All edits will be made in engine/events/move_reminder.asm
for this entire section.
- Create the
.print_move_category
local jump to retrieve the move's category name and print it in the correct location.
This step will vary depending on whether the reader has already implemented the Show Move Accuracy and Status Effect Chance section. Click to expand the applicable code.
Show Move Accuracy and Status Effect Chance - Not Implemented
; This prints the notch in the description text box border
; and the "TYPE/" and "ATK/" strings.
.print_move_stat_strings
hlcoord 0, 10
ld de, MoveTypeTopString
call PlaceString
hlcoord 0, 11
ld de, MoveTypeString
call PlaceString
hlcoord 12, 12
ld de, MoveAttackString
call PlaceString
+; This code falls through into the ".print_move_category" local jump.
+
+; This prints the move's category ("PHYSICAL",
+; "SPECIAL" or "STATUS").
+.print_move_category
+ ld a, [wCurSpecies]
+ ld b, a
+ farcall GetMoveCategoryName
+ hlcoord 1, 11
+ ld de, wStringBuffer1
+ call PlaceString
+ hlcoord 1, 12
+ ld [hl], "/"
+ inc hl
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
Show Move Accuracy and Status Effect Chance - Implemented
Note: If the reader has made only one metric visible (either accuracy or status effect chance) then the following code will be slightly different.
; This prints the notch in the description text box border
; and the "TYPE/", "ATK/", "EFF/" and "ACC/" strings.
.print_move_stat_strings
hlcoord 0, 9
ld de, MoveTypeTopString
call PlaceString
hlcoord 0, 10
ld de, MoveTypeString
call PlaceString
hlcoord 12, 11
ld de, MoveAttackString
call PlaceString
hlcoord 4, 12
ld de, MoveChanceString
call PlaceString
hlcoord 12, 12
ld de, MoveAccuracyString
call PlaceString
+; This code falls through into the ".print_move_category" local jump.
+
+; This prints the move's category ("PHYSICAL",
+; "SPECIAL" or "STATUS").
+.print_move_category
+ ld a, [wCurSpecies]
+ ld b, a
+ farcall GetMoveCategoryName
+ hlcoord 1, 10
+ ld de, wStringBuffer1
+ call PlaceString
+ hlcoord 1, 11
+ ld [hl], "/"
+ inc hl
; This code falls through into the ".print_move_chance" local jump.
; This prints the move's status effect chance number.
.print_move_chance
- Expand the notch above the description box to accommodate the move's category as it will require more space. We will also remove the
TYPE/
string inside theMoveTypeString
string label as that will be replaced with the move's category.
; This is a notch that will be placed on
; the top left of the description box.
MoveTypeTopString:
- db "┌─────┐@"
+ db "┌────────┐@"
; This is the string that displays
; above the move's type.
MoveTypeString:
- db "│TYPE/└@"
+ db "│ └@"
Now the move's category will show when browsing through the Move Reminder's menu.
Accuracy and status effect chance are important metrics to consider when choosing moves. Unfortunately, they are not visible in game and require the player to look them up elsewhere. Fortunately, we can display these metrics on the Move Reminder's menu itself to make it more convenient for the player.
Note: Both metrics can be made visible independently of each other. As such, notes have been left in every step that could be different if the reader decides to only make one metric visible.
Currently, there is not enough room to place these metrics in the description box. So we must perform several modifications to the menu first.
All edits will be made in engine/events/move_reminder.asm
for this entire subsection.
- Raise the text box border around the move list by one tile.
; This creates a border around the move list.
; "hlcoord" configures the position.
; "lb bc" configures the size.
- hlcoord 0, 1
+ hlcoord 0, 0
lb bc, 9, 18
call TextboxBorder
- Raise the Pokémon's name and level by one tile.
This step will vary depending on whether the reader has already implemented the Space Out the Pokémon's Name and Level section. Click to expand the applicable code.
Space Out the Pokémon's Name and Level - Not Implemented
Note: The level is displayed directly after the Pokémon's name so it does not have to be handled separately.
; This displays the Pokémon's species
; name (not nickname) at the
; coordinates defined at "hlcoord".
; In this case that is the
; top left of the screen.
xor a
ld [wMonType], a
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
- hlcoord 5, 1
+ hlcoord 5, 0
call PlaceString
Space Out the Pokémon's Name and Level - Implemented
; This displays the Pokémon's species
; name (not nickname) at the
; coordinates defined at "hlcoord".
; In this case that is the
; top left of the screen.
xor a
ld [wMonType], a
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
- hlcoord 3, 1
+ hlcoord 3, 0
call PlaceString
; This displays the Pokémon's level
; at the coordinates defined at
; "hlcoord". In this case that is
; the top right of the screen.
farcall CopyMonToTempMon
- hlcoord 14, 1
+ hlcoord 14, 0
call PrintLevel
- Raise the move list and top arrow by one tile.
; The menu header defines the menu's position and
; what will be included. The last two values
; of "menu_coords" will determine where the
; vertical scroll arrows will be located.
.MenuHeader:
db MENU_BACKUP_TILES
- menu_coords 1, 2, SCREEN_WIDTH - 2, 10
+ menu_coords 1, 1, SCREEN_WIDTH - 2, 9
dw .MenuData
db 1
- Raise the text box border fix by one tile.
; This adds a text box border line to the description
; box that replaces a leftover piece of the notch
; that remains when the cancel option is highlighted.
.cancel_border_fix
- hlcoord 0, 10
+ hlcoord 0, 9
ld [hl], "│"
inc hl
ret
- Raise the description text box border up by one tile and also increase its height by one tile.
; This begins the printing of all of the move's details,
; including the border around the description.
.print_move_details
; This creates a border around the description.
- hlcoord 0, 11
+ hlcoord 0, 10
- lb bc, 5, 18
+ lb bc, 6, 18
call TextboxBorder
- Raise the existing metrics in the description box by one tile.
This step will vary depending on whether the reader has already implemented the Physical Special Split section. Click to expand the applicable code.
Physical Special Split - Not Implemented
; This prints the move's type.
.print_move_type
ld a, [wCurSpecies]
ld b, a
- hlcoord 2, 12
+ hlcoord 2, 11
predef PrintMoveType
; This code falls through into the ".print_move_stat_strings" local jump.
; This prints the notch in the description text box border
; and the "TYPE/" and "ATK/" strings.
.print_move_stat_strings
- hlcoord 0, 10
+ hlcoord 0, 9
ld de, MoveTypeTopString
call PlaceString
- hlcoord 0, 11
+ hlcoord 0, 10
ld de, MoveTypeString
call PlaceString
- hlcoord 12, 12
+ hlcoord 12, 11
ld de, MoveAttackString
call PlaceString
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
ld a, [wMenuSelection]
ld bc, MOVE_LENGTH
ld hl, (Moves + MOVE_POWER) - MOVE_LENGTH
call AddNTimes
ld a, BANK(Moves)
call GetFarByte
cp 2
jr c, .print_move_null_attack
ld [wBuffer1], a
ld de, wBuffer1
lb bc, 1, 3
- hlcoord 16, 12
+ hlcoord 16, 11
jp PrintNum
; This prints "---" if the move has an attack of "0".
; This means that the move does not initially cause
; damage or is a one hit knockout move.
.print_move_null_attack
- hlcoord 16, 12
+ hlcoord 16, 11
ld de, MoveNullValueString
ld bc, 3
jp PlaceString
Physical Special Split - Implemented
; This prints the move's type.
.print_move_type
ld a, [wCurSpecies]
ld b, a
- hlcoord 2, 12
+ hlcoord 2, 11
predef PrintMoveType
; This code falls through into the ".print_move_stat_strings" local jump.
; This prints the notch in the description text box border
; and the "TYPE/" and "ATK/" strings.
.print_move_stat_strings
- hlcoord 0, 10
+ hlcoord 0, 9
ld de, MoveTypeTopString
call PlaceString
- hlcoord 0, 11
+ hlcoord 0, 10
ld de, MoveTypeString
call PlaceString
- hlcoord 12, 12
+ hlcoord 12, 11
ld de, MoveAttackString
call PlaceString
; This code falls through into the ".print_move_category" local jump.
; This prints the move's category ("PHYSICAL",
; "SPECIAL" or "STATUS").
.print_move_category
ld a, [wCurSpecies]
ld b, a
farcall GetMoveCategoryName
- hlcoord 1, 11
+ hlcoord 1, 10
ld de, wStringBuffer1
call PlaceString
- hlcoord 1, 12
+ hlcoord 1, 11
ld [hl], "/"
inc hl
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
ld a, [wMenuSelection]
ld bc, MOVE_LENGTH
ld hl, (Moves + MOVE_POWER) - MOVE_LENGTH
call AddNTimes
ld a, BANK(Moves)
call GetFarByte
cp 2
jr c, .print_move_null_attack
ld [wBuffer1], a
ld de, wBuffer1
lb bc, 1, 3
- hlcoord 16, 12
+ hlcoord 16, 11
jp PrintNum
; This prints "---" if the move has an attack of "0".
; This means that the move does not initially cause
; damage or is a one hit knockout move.
.print_move_null_attack
- hlcoord 16, 12
+ hlcoord 16, 11
ld de, MoveNullValueString
ld bc, 3
jp PlaceString
- Raise the gap in the text box border that surrounds the move list by one tile (Compatibility with the Space Out the Pokémon's Name and Level section).
Note: This step is only necessary if the reader has implemented the Space Out the Pokémon's Name and Level section of this tutorial. Click to expand the code.
Space Out the Pokémon's Name and Level - Implemented
; Adds a gap in the move list's text box border
; that prevents clipping with some names.
- hlcoord 2, 1
+ hlcoord 2, 0
lb bc, 1, 16
call ClearBox
Now there is enough room to add both the accuracy and status effect chance metrics.
Now that there is enough room, we can proceed to add the accuracy and status effect chance metrics.
All edits will be made in engine/events/move_reminder.asm
for this entire subsection.
- Insert the string labels (we will create them later) that precede the accuracy and status effect chance numbers.
Note: If the reader wishes to only make one of the metrics visible, then only the code pertaining to that metric needs to be introduced and its positioning can be altered using its corresponding hlcoord
(the comment should also be altered to reflect the code but that is optional).
; This prints the notch in the description text box border
-; and the "TYPE/" and "ATK/" strings.
+; and the "TYPE/", "ATK/", "EFF/" and "ACC/" strings.
.print_move_stat_strings
hlcoord 0, 9
ld de, MoveTypeTopString
call PlaceString
hlcoord 0, 10
ld de, MoveTypeString
call PlaceString
hlcoord 12, 11
ld de, MoveAttackString
call PlaceString
+ hlcoord 4, 12
+ ld de, MoveChanceString
+ call PlaceString
+ hlcoord 12, 12
+ ld de, MoveAccuracyString
+ call PlaceString
- Add the code that processes and prints the move accuracy and status effect chance.
This step will vary depending on whether the reader has already implemented the Physical Special Split section. Click to expand the applicable code.
Note: If the reader wishes to only make one of the metrics visible, then only the local jumps pertaining to that metric need to be introduced. If making only the status effect chance visible, ensure that the relative jump at the end of the .print_move_chance
local jump points to the .print_move_attack
local jump (the comments should also be altered to reflect the code but that is optional).
Physical Special Split - Not Implemented
call PlaceString
+; This code falls through into the ".print_move_chance" local jump.
+
+; This prints the move's status effect chance number.
+.print_move_chance
+ ld a, [wMenuSelection]
+ ld bc, MOVE_LENGTH
+ ld hl, (Moves + MOVE_CHANCE) - MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ cp 1
+ jr c, .print_move_null_chance
+ Call ConvertPercentages
+ ld [wBuffer1], a
+ ld de, wBuffer1
+ lb bc, 1, 3
+ hlcoord 8, 12
+ call PrintNum
+ jr .print_move_accuracy
+
+; This prints "---" if the move has a status effect chance of "0".
+; This means one of three things:
+; It does not inflict a status effect.
+; It is always successful in inflicting a status
+; effect unless something blocks it.
+; Causes a weather effect.
+.print_move_null_chance
+ ld de, MoveNullValueString
+ ld bc, 3
+ hlcoord 8, 12
+ call PlaceString
+; This code falls through into the ".print_move_accuracy" local jump.
+
+; This prints the move's accuracy number.
+.print_move_accuracy
+ ld a, [wMenuSelection]
+ ld bc, MOVE_LENGTH
+ ld hl, (Moves + MOVE_ACC) - MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ Call ConvertPercentages
+ ld [wBuffer1], a
+ ld de, wBuffer1
+ lb bc, 1, 3
+ hlcoord 16, 12
+ call PrintNum
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
Physical Special Split - Implemented
ld [hl], "/"
inc hl
+; This code falls through into the ".print_move_chance" local jump.
+
+; This prints the move's status effect chance number.
+.print_move_chance
+ ld a, [wMenuSelection]
+ ld bc, MOVE_LENGTH
+ ld hl, (Moves + MOVE_CHANCE) - MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ cp 1
+ jr c, .print_move_null_chance
+ Call ConvertPercentages
+ ld [wBuffer1], a
+ ld de, wBuffer1
+ lb bc, 1, 3
+ hlcoord 8, 12
+ call PrintNum
+ jr .print_move_accuracy
+
+; This prints "---" if the move has a status effect chance of "0".
+; This means one of three things:
+; It does not inflict a status effect.
+; It is always successful in inflicting a status
+; effect unless something blocks it.
+; Causes a weather effect.
+.print_move_null_chance
+ ld de, MoveNullValueString
+ ld bc, 3
+ hlcoord 8, 12
+ call PlaceString
+; This code falls through into the ".print_move_accuracy" local jump.
+
+; This prints the move's accuracy number.
+.print_move_accuracy
+ ld a, [wMenuSelection]
+ ld bc, MOVE_LENGTH
+ ld hl, (Moves + MOVE_ACC) - MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
+ Call ConvertPercentages
+ ld [wBuffer1], a
+ ld de, wBuffer1
+ lb bc, 1, 3
+ hlcoord 16, 12
+ call PrintNum
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
- Convert the accuracy and status effect chance values from a number out of 256 to a number out of 100.
Note: This is necessary as percentage numbers produce a value out of 256. So we need to convert this value to a number out of 100 in order to print the correct value.
; This prints "---" if the move has an attack of "0".
; This means that the move does not initially cause
; damage or is a one hit knockout move.
.print_move_null_attack
hlcoord 16, 11
ld de, MoveNullValueString
ld bc, 3
jp PlaceString
+
+; This converts values out of 256 into a value
+; out of 100. It achieves this by multiplying
+; the value by 100 and dividing it by 256.
+ConvertPercentages:
+
+ ; Overwrite the "hl" register.
+ ld l, a
+ ld h, 0
+ push af
+
+ ; Multiplies the value of the "hl" register by 3.
+ add hl, hl
+ add a, l
+ ld l, a
+ adc h
+ sub l
+ ld h, a
+
+ ; Multiplies the value of the "hl" register
+ ; by 8. The value of the "hl" register
+ ; is now 24 times its original value.
+ add hl, hl
+ add hl, hl
+ add hl, hl
+
+ ; Add the original value of the "hl" value to itself,
+ ; making it 25 times its original value.
+ pop af
+ add a, l
+ ld l, a
+ adc h
+ sbc l
+ ld h, a
+
+ ; Multiply the value of the "hl" register by
+ ; 4, making it 100 times its original value.
+ add hl, hl
+ add hl, hl
+
+ ; Set the "l" register to 0.5, otherwise the rounded
+ ; value may be lower than expected. Round the
+ ; high byte to nearest and drop the low byte.
+ ld l, 0.5
+ sla l
+ sbc a
+ and 1
+ add a, h
+ ret
; This is a notch that will be placed on
; the top left of the description box.
MoveTypeTopString:
- Create the string labels that precede the accuracy and status effect chance numbers.
Note: If the reader wishes to only make one of the metrics visible, then only the string label pertaining to that metric needs to be introduced.
; This displays when a move has
; a metric with a null value.
MoveNullValueString:
db "---@"
+
+; This is the string that precedes
+; the move's accuracy number.
+MoveAccuracyString:
+ db "ACC/@"
+
+; This is the string that precedes the
+; move's status effect chance number.
+MoveChanceString:
+ db "EFF/@"
; This is the text that displays when the player
; first talks to the move reminder.
MoveReminderIntroText:
Now the accuracy and status effect chance metrics will appear when browsing through the Move Reminder's menu.
However, there is an additional modification that can be made to provide more accurate information to the player.
Note: This subsection is only necessary if the reader has made the accuracy metric visible, it is futile with just making the status effect chance metric visible alone.
Currently all moves will display a number for their accuracy, even those that bypass accuracy checks (perfect accuracy moves). Some of these perfect accuracy moves even display a number less than 100%. Perfect accuracy moves are:
- Moves that target the opponent and never miss (unless the target is in the semi-invulnerable turn of a move such as Dig or Fly) - Swift, Faint Attack and Vital Throw.
- Moves that target the user - All moves that target the user will never miss.
- Weather moves - Some of these moves have an accuracy of less than 100% despite never missing.
We will make modifications so that perfect accuracy moves will display ---
instead of a number.
We will achieve this by modifying the order of the move effects in move_effect_constants.asm and effects_pointers.asm so that all effects that have perfect accuracy will be listed after all that do not.
Then we will modify the Move Reminder's code to first check if a move's effect is listed at or below the first effect that has perfect accuracy. If so, ---
will be displayed instead of the number. If not, a number for the move's accuracy will display as normal.
Note: The entries in move_effect_constants.asm
have a corresponding relationship with the entries in effects_pointers.asm
. As such, any modification that is made in one file, must be made in the other. For example, if EFFECT_ALWAYS_HIT
is moved to just above EFFECT_CONVERSION
in move_effect_constants.asm
, then dw NormalHit
must be moved to just above dw Conversion
in effects_pointers.asm
.
This may become confusing as while the entries in move_effect_constants.asm
are unique, some entries in effects_pointers.asm
are used multiple times. For example, everything in the following list in move_effect_constants.asm
use NormalHit
in effects_pointers.asm
.
EFFECT_NORMAL_HIT
EFFECT_ALWAYS_HIT
EFFECT_JUMP_KICK
EFFECT_PRIORITY_HIT
- All
EFFECT_UNUSED_*
- Modify
move_effect_constants.asm
to list all effects that do not have perfect accuracy first, followed by those that do.
Note: If the reader has added/removed/modified any moves or move effects, then this file may have different contents. Please ensure that is taken into consideration before modifying this file.
Edit constants/move_effect_constants.asm:
Click here to expand the code
; MoveEffectsPointers indexes (see data/moves/effects_pointers.asm)
const_def
const EFFECT_NORMAL_HIT
const EFFECT_SLEEP
const EFFECT_POISON_HIT
const EFFECT_LEECH_HIT
const EFFECT_BURN_HIT
const EFFECT_FREEZE_HIT
const EFFECT_PARALYZE_HIT
const EFFECT_SELFDESTRUCT
const EFFECT_DREAM_EATER
- const EFFECT_MIRROR_MOVE
- const EFFECT_ATTACK_UP
- const EFFECT_DEFENSE_UP
- const EFFECT_SPEED_UP
- const EFFECT_SP_ATK_UP
- const EFFECT_SP_DEF_UP
- const EFFECT_ACCURACY_UP
- const EFFECT_EVASION_UP
- const EFFECT_ALWAYS_HIT
const EFFECT_ATTACK_DOWN
const EFFECT_DEFENSE_DOWN
const EFFECT_SPEED_DOWN
const EFFECT_SP_ATK_DOWN
const EFFECT_SP_DEF_DOWN
const EFFECT_ACCURACY_DOWN
const EFFECT_EVASION_DOWN
- const EFFECT_RESET_STATS
const EFFECT_BIDE
const EFFECT_RAMPAGE
const EFFECT_FORCE_SWITCH
const EFFECT_MULTI_HIT
- const EFFECT_CONVERSION
const EFFECT_FLINCH_HIT
- const EFFECT_HEAL
const EFFECT_TOXIC
const EFFECT_PAY_DAY
- const EFFECT_LIGHT_SCREEN
const EFFECT_TRI_ATTACK
const EFFECT_UNUSED_25
const EFFECT_OHKO
const EFFECT_RAZOR_WIND
const EFFECT_SUPER_FANG
const EFFECT_STATIC_DAMAGE
const EFFECT_TRAP_TARGET
const EFFECT_UNUSED_2B
const EFFECT_DOUBLE_HIT
const EFFECT_JUMP_KICK
- const EFFECT_MIST
- const EFFECT_FOCUS_ENERGY
const EFFECT_RECOIL_HIT
const EFFECT_CONFUSE
- const EFFECT_ATTACK_UP_2
- const EFFECT_DEFENSE_UP_2
- const EFFECT_SPEED_UP_2
- const EFFECT_SP_ATK_UP_2
- const EFFECT_SP_DEF_UP_2
- const EFFECT_ACCURACY_UP_2
- const EFFECT_EVASION_UP_2
- const EFFECT_TRANSFORM
const EFFECT_ATTACK_DOWN_2
const EFFECT_DEFENSE_DOWN_2
const EFFECT_SPEED_DOWN_2
const EFFECT_SP_ATK_DOWN_2
const EFFECT_SP_DEF_DOWN_2
const EFFECT_ACCURACY_DOWN_2
const EFFECT_EVASION_DOWN_2
- const EFFECT_REFLECT
const EFFECT_POISON
const EFFECT_PARALYZE
const EFFECT_ATTACK_DOWN_HIT
const EFFECT_DEFENSE_DOWN_HIT
const EFFECT_SPEED_DOWN_HIT
const EFFECT_SP_ATK_DOWN_HIT
const EFFECT_SP_DEF_DOWN_HIT
const EFFECT_ACCURACY_DOWN_HIT
const EFFECT_EVASION_DOWN_HIT
const EFFECT_SKY_ATTACK
const EFFECT_CONFUSE_HIT
const EFFECT_POISON_MULTI_HIT
const EFFECT_UNUSED_4E
- const EFFECT_SUBSTITUTE
const EFFECT_HYPER_BEAM
const EFFECT_RAGE
const EFFECT_MIMIC
- const EFFECT_METRONOME
const EFFECT_LEECH_SEED
- const EFFECT_SPLASH
const EFFECT_DISABLE
const EFFECT_LEVEL_DAMAGE
const EFFECT_PSYWAVE
const EFFECT_COUNTER
const EFFECT_ENCORE
const EFFECT_PAIN_SPLIT
const EFFECT_SNORE
- const EFFECT_CONVERSION2
const EFFECT_LOCK_ON
- const EFFECT_SKETCH
const EFFECT_DEFROST_OPPONENT
- const EFFECT_SLEEP_TALK
- const EFFECT_DESTINY_BOND
const EFFECT_REVERSAL
const EFFECT_SPITE
const EFFECT_FALSE_SWIPE
- const EFFECT_HEAL_BELL
const EFFECT_PRIORITY_HIT
const EFFECT_TRIPLE_KICK
const EFFECT_THIEF
- const EFFECT_MEAN_LOOK
- const EFFECT_NIGHTMARE
const EFFECT_FLAME_WHEEL
- const EFFECT_CURSE
const EFFECT_UNUSED_6E
- const EFFECT_PROTECT
- const EFFECT_SPIKES
const EFFECT_FORESIGHT
- const EFFECT_PERISH_SONG
- const EFFECT_SANDSTORM
- const EFFECT_ENDURE
const EFFECT_ROLLOUT
const EFFECT_SWAGGER
const EFFECT_FURY_CUTTER
const EFFECT_ATTRACT
const EFFECT_RETURN
const EFFECT_PRESENT
const EFFECT_FRUSTRATION
- const EFFECT_SAFEGUARD
const EFFECT_SACRED_FIRE
const EFFECT_MAGNITUDE
- const EFFECT_BATON_PASS
const EFFECT_PURSUIT
const EFFECT_RAPID_SPIN
const EFFECT_UNUSED_82
const EFFECT_UNUSED_83
- const EFFECT_MORNING_SUN
- const EFFECT_SYNTHESIS
- const EFFECT_MOONLIGHT
const EFFECT_HIDDEN_POWER
- const EFFECT_RAIN_DANCE
- const EFFECT_SUNNY_DAY
const EFFECT_DEFENSE_UP_HIT
const EFFECT_ATTACK_UP_HIT
const EFFECT_ALL_UP_HIT
const EFFECT_FAKE_OUT
- const EFFECT_BELLY_DRUM
- const EFFECT_PSYCH_UP
const EFFECT_MIRROR_COAT
const EFFECT_SKULL_BASH
const EFFECT_TWISTER
const EFFECT_EARTHQUAKE
const EFFECT_FUTURE_SIGHT
const EFFECT_GUST
const EFFECT_STOMP
const EFFECT_SOLARBEAM
const EFFECT_THUNDER
- const EFFECT_TELEPORT
const EFFECT_BEAT_UP
const EFFECT_FLY
+ const EFFECT_MIRROR_MOVE
+ const EFFECT_ATTACK_UP
+ const EFFECT_DEFENSE_UP
+ const EFFECT_SPEED_UP
+ const EFFECT_SP_ATK_UP
+ const EFFECT_SP_DEF_UP
+ const EFFECT_ACCURACY_UP
+ const EFFECT_EVASION_UP
+ const EFFECT_ALWAYS_HIT
+ const EFFECT_RESET_STATS
+ const EFFECT_CONVERSION
+ const EFFECT_HEAL
+ const EFFECT_LIGHT_SCREEN
+ const EFFECT_MIST
+ const EFFECT_FOCUS_ENERGY
+ const EFFECT_ATTACK_UP_2
+ const EFFECT_DEFENSE_UP_2
+ const EFFECT_SPEED_UP_2
+ const EFFECT_SP_ATK_UP_2
+ const EFFECT_SP_DEF_UP_2
+ const EFFECT_ACCURACY_UP_2
+ const EFFECT_EVASION_UP_2
+ const EFFECT_TRANSFORM
+ const EFFECT_REFLECT
+ const EFFECT_SUBSTITUTE
+ const EFFECT_METRONOME
+ const EFFECT_SPLASH
+ const EFFECT_CONVERSION2
+ const EFFECT_SKETCH
+ const EFFECT_SLEEP_TALK
+ const EFFECT_DESTINY_BOND
+ const EFFECT_HEAL_BELL
+ const EFFECT_MEAN_LOOK
+ const EFFECT_NIGHTMARE
+ const EFFECT_CURSE
+ const EFFECT_PROTECT
+ const EFFECT_SPIKES
+ const EFFECT_PERISH_SONG
+ const EFFECT_SANDSTORM
+ const EFFECT_ENDURE
+ const EFFECT_SAFEGUARD
+ const EFFECT_BATON_PASS
+ const EFFECT_MORNING_SUN
+ const EFFECT_SYNTHESIS
+ const EFFECT_MOONLIGHT
+ const EFFECT_RAIN_DANCE
+ const EFFECT_SUNNY_DAY
+ const EFFECT_BELLY_DRUM
+ const EFFECT_PSYCH_UP
+ const EFFECT_TELEPORT
const EFFECT_DEFENSE_CURL
DEF NUM_MOVE_EFFECTS EQU const_value
- Modify
effects_pointers.asm
to list all effects that do not have perfect accuracy first, followed by those that do.
Note: If the reader has added/removed/modified any moves or move effects, then this file may have different contents. Please ensure that is taken into consideration before modifying this file.
Edit data/moves/effects_pointers.asm:
Click here to expand the code
MoveEffectsPointers:
; entries correspond to EFFECT_* constants
table_width 2, MoveEffectsPointers
dw NormalHit
dw DoSleep
dw PoisonHit
dw LeechHit
dw BurnHit
dw FreezeHit
dw ParalyzeHit
dw Selfdestruct
dw DreamEater
- dw MirrorMove
- dw AttackUp
- dw DefenseUp
- dw SpeedUp
- dw SpecialAttackUp
- dw SpecialDefenseUp
- dw AccuracyUp
- dw EvasionUp
- dw NormalHit
dw AttackDown
dw DefenseDown
dw SpeedDown
dw SpecialAttackDown
dw SpecialDefenseDown
dw AccuracyDown
dw EvasionDown
- dw ResetStats
dw Bide
dw Rampage
dw ForceSwitch
dw MultiHit
- dw Conversion
dw FlinchHit
- dw Heal
dw Toxic
dw PayDay
- dw LightScreen
dw TriAttack
dw NormalHit
dw OHKOHit
dw RazorWind
dw SuperFang
dw StaticDamage
dw TrapTarget
dw NormalHit
dw MultiHit
dw NormalHit
- dw Mist
- dw FocusEnergy
dw RecoilHit
dw DoConfuse
- dw AttackUp2
- dw DefenseUp2
- dw SpeedUp2
- dw SpecialAttackUp2
- dw SpecialDefenseUp2
- dw AccuracyUp2
- dw EvasionUp2
- dw Transform
dw AttackDown2
dw DefenseDown2
dw SpeedDown2
dw SpecialAttackDown2
dw SpecialDefenseDown2
dw AccuracyDown2
dw EvasionDown2
- dw Reflect
dw DoPoison
dw DoParalyze
dw AttackDownHit
dw DefenseDownHit
dw SpeedDownHit
dw SpecialAttackDownHit
dw SpecialDefenseDownHit
dw AccuracyDownHit
dw EvasionDownHit
dw SkyAttack
dw ConfuseHit
dw PoisonMultiHit
dw NormalHit
- dw Substitute
dw HyperBeam
dw Rage
dw Mimic
- dw Metronome
dw LeechSeed
- dw Splash
dw Disable
dw StaticDamage
dw Psywave
dw Counter
dw Encore
dw PainSplit
dw Snore
- dw Conversion2
dw LockOn
- dw Sketch
dw DefrostOpponent
- dw SleepTalk
- dw DestinyBond
dw Reversal
dw Spite
dw FalseSwipe
- dw HealBell
dw NormalHit
dw TripleKick
dw Thief
- dw MeanLook
- dw Nightmare
dw FlameWheel
- dw Curse
dw NormalHit
- dw Protect
- dw Spikes
dw Foresight
- dw PerishSong
- dw Sandstorm
- dw Endure
dw Rollout
dw Swagger
dw FuryCutter
dw Attract
dw Return
dw Present
dw Frustration
- dw Safeguard
dw SacredFire
dw Magnitude
- dw BatonPass
dw Pursuit
dw RapidSpin
dw NormalHit
dw NormalHit
- dw MorningSun
- dw Synthesis
- dw Moonlight
dw HiddenPower
- dw RainDance
- dw SunnyDay
dw DefenseUpHit
dw AttackUpHit
dw AllUpHit
dw FakeOut
- dw BellyDrum
- dw PsychUp
dw MirrorCoat
dw SkullBash
dw Twister
dw Earthquake
dw FutureSight
dw Gust
dw Stomp
dw Solarbeam
dw Thunder
- dw Teleport
dw BeatUp
dw Fly
+ dw MirrorMove
+ dw AttackUp
+ dw DefenseUp
+ dw SpeedUp
+ dw SpecialAttackUp
+ dw SpecialDefenseUp
+ dw AccuracyUp
+ dw EvasionUp
+ dw NormalHit
+ dw ResetStats
+ dw Conversion
+ dw Heal
+ dw LightScreen
+ dw Mist
+ dw FocusEnergy
+ dw AttackUp2
+ dw DefenseUp2
+ dw SpeedUp2
+ dw SpecialAttackUp2
+ dw SpecialDefenseUp2
+ dw AccuracyUp2
+ dw EvasionUp2
+ dw Transform
+ dw Reflect
+ dw Substitute
+ dw Metronome
+ dw Splash
+ dw Conversion2
+ dw Sketch
+ dw SleepTalk
+ dw DestinyBond
+ dw HealBell
+ dw MeanLook
+ dw Nightmare
+ dw Curse
+ dw Protect
+ dw Spikes
+ dw PerishSong
+ dw Sandstorm
+ dw Endure
+ dw Safeguard
+ dw BatonPass
+ dw MorningSun
+ dw Synthesis
+ dw Moonlight
+ dw RainDance
+ dw SunnyDay
+ dw BellyDrum
+ dw PsychUp
+ dw Teleport
dw DefenseCurl
assert_table_length NUM_MOVE_EFFECTS
- Modify the
.print_move_accuracy
and add the.perfect_accuracy
local jumps in the Move Reminder's code so that---
is printed instead of a number if the move effect has perfect accuracy.
Edit engine/events/move_reminder.asm:
; This prints the move's accuracy number.
.print_move_accuracy
ld a, [wMenuSelection]
ld bc, MOVE_LENGTH
- ld hl, (Moves + MOVE_ACC) - MOVE_LENGTH
+ ld hl, (Moves + MOVE_EFFECT) - MOVE_LENGTH
call AddNTimes
ld a, BANK(Moves)
call GetFarByte
+ cp EFFECT_MIRROR_MOVE
+ jr nc, .perfect_accuracy
+ ld a, [wMenuSelection]
+ ld bc, MOVE_LENGTH
+ ld hl, (Moves + MOVE_ACC) - MOVE_LENGTH
+ call AddNTimes
+ ld a, BANK(Moves)
+ call GetFarByte
Call ConvertPercentages
ld [wBuffer1], a
ld de, wBuffer1
lb bc, 1, 3
hlcoord 16, 12
call PrintNum
+ jr .print_move_attack
+
+; This prints "---" if the move
+; has perfect accuracy.
+.perfect_accuracy
+ ld de, MoveNullValueString
+ ld bc, 3
+ hlcoord 16, 12
+ call PlaceString
; This code falls through into the ".print_move_attack" local jump.
; This prints the move's attack number.
.print_move_attack
Now every move that has perfect accuracy will display ---
instead of a number.
Considering how powerful the ability to have Pokémon relearn moves is, the reader may choose to make it a paid service.
We will make modifications so that each move learned will cost ¥500.
All edits will be made in engine/events/move_reminder.asm
for this entire section.
- Place the player's current money total at the top right of the screen to indicate that the Move Reminder is a paid service and compare the player's current money against the cost of learning a move (the code that executes if the player does not have enough money will be created at a later point).
MoveReminder:
- ; Loads and prints the "MoveReminderIntroText" text.
- ; Then prompts the player to select "YES" or "NO".
+ ; Loads and prints the "MoveReminderIntroText" text and places
+ ; the player's current money at the top right corner of the
+ ; screen. Then prompts the player to select "YES" or "NO".
; Relative jump to the ".cancel" local jump
; if the player selected "NO" and continue
; if the player selected "YES".
ld hl, MoveReminderIntroText
call PrintText
+ farcall PlaceMoneyTopRight
call YesNoBox
jr c, .cancel
+
+ ; Calls the "CheckCostAgainstPlayerMoney" label. Relative jump
+ ; to the ".not_enough_money" local jump if the player does
+ ; not have enough money and continue if they do.
+ call CheckCostAgainstPlayerMoney
+ jr c, .not_enough_money
; Loads and prints the "MoveReminderWhichMonText" text.
ld hl, MoveReminderWhichMonText
call PrintText
- Create the
.not_enough_money
local jump for when the player does not have enough money.
This step will vary depending on whether the reader has already implemented the Add Party Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Party Menu Loop - Not Implemented
Note: This will print text that will be created at a later point.
; Loads and prints the "MoveReminderNoMovesText" text.
; This ends the dialogue.
.no_moves_to_learn
ld hl, MoveReminderNoMovesText
jp PrintText
+
+; Loads and prints the "MoveReminderNotEnoughMoneyText" text.
+; This will end the dialogue.
+.not_enough_money
+ ld hl, MoveReminderNotEnoughMoneyText
+ jp PrintText
Add Party Menu Loop - Implemented
Note: This will print text that will be created at a later point.
; Loads and prints the "MoveReminderNoMovesText" text and then waits
; for the player to press a button for the text to progress. Then
; relative jump to the ".loop_party_menu" local jump.
.no_moves_to_learn
ld hl, MoveReminderNoMovesText
call PrintText
jr .loop_party_menu
+
+; Loads and prints the "MoveReminderNotEnoughMoneyText" text.
+; This will end the dialogue.
+.not_enough_money
+ ld hl, MoveReminderNotEnoughMoneyText
+ jp PrintText
- Create the
.pay_for_move
local jump to processes the payment after a move is learned.
This step will vary depending on whether the reader has already implemented the Add Move Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Move Menu Loop - Not Implemented
The .move_learned
local jump will also need to be modified so that it falls through into the .pay_for_move
local jump.
Note: The .pay_for_move
local jump will not be jumped to directly. It only needs to execute via fall through.
; Exits the menu and goes back to the map with a
; speech text box open and then loads and prints
; the "MoveReminderMoveLearnedText" text.
-; This ends the dialogue.
.move_learned
call ReturnToMapWithSpeechTextbox
ld hl, MoveReminderMoveLearnedText
- jp PrintText
+ call PrintText
+; This code falls through into the ".pay_for_move" local jump.
+
+; Places the player's current money at the top right corner of
+; the screen, retrieves the amount of money defined in the
+; "MoveCost" label, removes the defined amount of money from
+; the player, plays the "SFX_TRANSACTION" sound effect,
+; prints the "MoveReminderPaymentReceivedText"text and
+; finally relative jump to the ".cancel" local jump.
+.pay_for_move
+ farcall PlaceMoneyTopRight
+ ld hl, MoveCost
+ ld de, hMoneyTemp
+ ld bc, 3
+ call CopyBytes
+ call ApplyTilemap
+ call PromptButton
+ call WaitSFX
+ ld bc, hMoneyTemp
+ ld de, wMoney
+ farcall TakeMoney
+ farcall PlaceMoneyTopRight
+ ld de, SFX_TRANSACTION
+ call PlaySFX
+ call WaitSFX
+ ld hl, MoveReminderPaymentReceivedText
+ call PrintText
+ jr .cancel
Add Move Menu Loop - Implemented
Note: This local jump will never be directly jumped to. It will only execute when the .move_learned
local jump falls through into it.
; Exits the menu and goes back to the map with a
-; speech text box open, loads and prints
-; the "MoveReminderMoveLearnedText"
-; text and relative jump to the
-; ".recheck_for_moves" local jump.
+; speech text box open and then loads and prints
+; the "MoveReminderMoveLearnedText" text.
.move_learned
call ReturnToMapWithSpeechTextbox
ld hl, MoveReminderMoveLearnedText
call PrintText
+; This code falls through into the ".pay_for_move" local jump.
+
+; Places the player's current money at the top right corner of
+; the screen, retrieves the amount of money defined in the
+; "MoveCost" label, removes the defined amount of money from
+; the player, plays the "SFX_TRANSACTION" sound effect and
+; finally prints the "MoveReminderPaymentReceivedText" text.
+.pay_for_move
+ farcall PlaceMoneyTopRight
+ ld hl, MoveCost
+ ld de, hMoneyTemp
+ ld bc, 3
+ call CopyBytes
+ call ApplyTilemap
+ call PromptButton
+ call WaitSFX
+ ld bc, hMoneyTemp
+ ld de, wMoney
+ farcall TakeMoney
+ farcall PlaceMoneyTopRight
+ ld de, SFX_TRANSACTION
+ call PlaySFX
+ call WaitSFX
+ ld hl, MoveReminderPaymentReceivedText
+ call PrintText
+
+ ; Calls the "CheckCostAgainstPlayerMoney" label. Relative
+ ; jump to the ".not_enough_money" local jump if the
+ ; player does not have enough money and relative jump
+ ; to the ".recheck_for_moves" local jump if they do.
+ call CheckCostAgainstPlayerMoney
+ jr c, .not_enough_money
jr .recheck_for_moves
- Create the
CheckCostAgainstPlayerMoney
label that will compare the player's money against the cost of learning a move.
This step will vary depending on whether the reader has already implemented the Add Move Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Move Menu Loop - Not Implemented
.pay_for_move
farcall PlaceMoneyTopRight
ld hl, MoveCost
ld de, hMoneyTemp
ld bc, 3
call CopyBytes
call ApplyTilemap
call PromptButton
call WaitSFX
ld bc, hMoneyTemp
ld de, wMoney
farcall TakeMoney
farcall PlaceMoneyTopRight
ld de, SFX_TRANSACTION
call PlaySFX
call WaitSFX
ld hl, MoveReminderPaymentReceivedText
call PrintText
jr .cancel
+
+; Compares the value of "MoveCost" to
+; the amount of money the player has.
+CheckCostAgainstPlayerMoney:
+ ld hl, MoveCost
+ ld de, hMoneyTemp
+ ld bc, 3
+ call CopyBytes
+ ld bc, hMoneyTemp
+ ld de, wMoney
+ farcall CompareMoney
+ ret
Add Move Menu Loop - Implemented
; Calls the "CheckCostAgainstPlayerMoney" label. Relative
; jump to the ".not_enough_money" local jump if the
; player does not have enough money and relative jump
; to the ".recheck_for_moves" local jump if they do.
call CheckCostAgainstPlayerMoney
jr c, .not_enough_money
jr .recheck_for_moves
+
+; Compares the value of "MoveCost" to
+; the amount of money the player has.
+CheckCostAgainstPlayerMoney:
+ ld hl, MoveCost
+ ld de, hMoneyTemp
+ ld bc, 3
+ call CopyBytes
+ ld bc, hMoneyTemp
+ ld de, wMoney
+ farcall CompareMoney
+ ret
- Define the cost of learning a move.
Note: The reader is free to define their own cost of learning a move.
; Compares the value of "MoveCost" to
; the amount of money the player has.
CheckCostAgainstPlayerMoney:
ld hl, MoveCost
ld de, hMoneyTemp
ld bc, 3
call CopyBytes
ld bc, hMoneyTemp
ld de, wMoney
farcall CompareMoney
ret
+
+; The cost for learning a move.
+MoveCost:
+ dt 500
- Modify the Move Reminder's intro text to mention the cost to learn a move.
Note: If the reader has defined their own cost for learning a move, then remember to modify this text entry to reflect that.
; This is the text that displays when the player
; first talks to the move reminder.
MoveReminderIntroText:
text "Hi, I'm the Move"
line "Reminder!"
- para "I can make #MON"
- line "remember moves."
+ para "For ¥500, I can"
+ line "make #MON"
+ cont "remember a move."
para "Are you"
line "interested?"
done
- Create a label that contains the text that will display when the player does not have enough money.
+
+; This is the text that displays if the player
+; does not have enough money to learn a move.
+MoveReminderNotEnoughMoneyText:
+ text "Hm… You don't have"
+ line "enough money."
+
+ para "Please come back"
+ line "when you do."
+ done
; This is the text that displays after a
; Pokémon successfully learns a move.
MoveReminderMoveLearnedText:
- Add a label that contains the text that will be printed after a payment has been accepted by the Move Reminder.
This step will vary depending on whether the reader has already implemented the Add Move Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Move Menu Loop - Not Implemented
; This is the text that displays after a
; Pokémon successfully learns a move.
MoveReminderMoveLearnedText:
text "Done! Your #MON"
line "remembered the"
cont "move."
done
+
+; This is the text that displays after the
+; Move Reminder accepts payment.
+MoveReminderPaymentReceivedText:
+ text "Pleasure doing"
+ line "business with"
+ cont "you!"
+ prompt
Add Move Menu Loop - Implemented
Note: The prompt in the MoveReminderMoveLearnedText
label will also be removed to prevent a double prompt after the text is printed.
; This is the text that displays after a
; Pokémon successfully learns a move.
MoveReminderMoveLearnedText:
text "Done! Your #MON"
line "remembered the"
cont "move."
- prompt
+ done
+
+; This is the text that displays after the
+; Move Reminder accepts payment.
+MoveReminderPaymentReceivedText:
+ text "Pleasure doing"
+ line "business with"
+ cont "you!"
+ prompt
Now each move learned via the Move Reminder will cost the player ¥500 (unless the reader has opted to change this value).
Currently, the Pokémon's name and level are attached together, longer names appear less centred on the screen and the move list's text box border clips with the Pokémon's name.
We will separate the Pokémon's name and level, make them more centred on the screen and create an opening in the move list's text box border.
All edits will be made in engine/events/move_reminder.asm
for this entire section.
- Create an opening in the move list's text box border.
This step will vary depending on whether the reader has already implemented the Show Move Accuracy and Status Effect Chance section. Click to expand the applicable code.
Show Move Accuracy and Status Effect Chance - Not Implemented
lb bc, 9, 18
call TextboxBorder
+
+ ; Adds a gap in the move list's text box border
+ ; that prevents clipping with some names.
+ hlcoord 2, 1
+ lb bc, 1, 16
+ call ClearBox
; This replaces the tile using the identifier
; of "$6e" with the fourteenth tile of the
; "FontBattleExtra gfx" font. Also, only 1
; tile will be loaded as loading the entire
; "FontBattleExtra gfx" font will overwrite
; the "UP" arrow in the menu.
Show Move Accuracy and Status Effect Chance - Implemented
lb bc, 9, 18
call TextboxBorder
+
+ ; Adds a gap in the move list's text box border
+ ; that prevents clipping with some names.
+ hlcoord 2, 0
+ lb bc, 1, 16
+ call ClearBox
; This replaces the tile using the identifier
; of "$6e" with the fourteenth tile of the
; "FontBattleExtra gfx" font. Also, only 1
; tile will be loaded as loading the entire
; "FontBattleExtra gfx" font will overwrite
; the "UP" arrow in the menu.
- Move the Pokémon's name slightly to the left and separate the Pokémon's level from its name.
This step will vary depending on whether the reader has already implemented the Show Move Accuracy and Status Effect Chance section. Click to expand the applicable code.
Show Move Accuracy and Status Effect Chance - Not Implemented
; This displays the Pokémon's species
; name (not nickname) at the
; coordinates defined at "hlcoord".
; In this case that is the
; top left of the screen.
xor a
ld [wMonType], a
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
- hlcoord 5, 1
+ hlcoord 3, 1
call PlaceString
; This displays the Pokémon's level
- ; right after the Pokémon's name.
- push bc
+ ; at the coordinates defined at
+ ; "hlcoord". In this case that is
+ ; the top right of the screen.
farcall CopyMonToTempMon
- pop hl
+ hlcoord 14, 1
call PrintLevel
Show Move Accuracy and Status Effect Chance - Implemented
; This displays the Pokémon's species
; name (not nickname) at the
; coordinates defined at "hlcoord".
; In this case that is the
; top left of the screen.
xor a
ld [wMonType], a
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
- hlcoord 5, 0
+ hlcoord 3, 0
call PlaceString
; This displays the Pokémon's level
- ; right after the Pokémon's name.
- push bc
+ ; at the coordinates defined at
+ ; "hlcoord". In this case that is
+ ; the top right of the screen.
farcall CopyMonToTempMon
- pop hl
+ hlcoord 14, 0
call PrintLevel
Now the Pokémon's name and level will be centred on the screen and the text box border will not clip with the Pokémon's name.
Currently, the Move Reminder will end dialogue with the player in the following situations:
- When they select a Pokémon without any moves to learn.
- When they select an egg or a glitched Pokémon.
- When a Pokémon learns a move.
- When a player selects a move to teach to a Pokémon but then decides against it.
This is quite inconvenient if the player would like to select another Pokémon or move.
We will introduce two loops in order to make the Move Reminder's service more convenient for the player. The two loops are:
- Party Menu Loop - Loops the party menu when the player selects a Pokémon with no moves to learn, an egg, a glitched Pokémon or leaves the Move Reminder's move menu.
- Move Menu Loop - Loops the move menu when a Pokémon learns a move or the player selects a move to teach to a Pokémon but then decides against it.
Note: The reader does not have to implement both of the loops. They can be implemented independently.
All edits will be made in engine/events/move_reminder.asm
for this entire section.
- Create the
.loop_party_menu
local jump after theMoveReminderWhichMonText
text as this is where the party menu loop will begin.
; Loads and prints the "MoveReminderWhichMonText" text.
ld hl, MoveReminderWhichMonText
call PrintText
+; This code falls through into the ".loop_party_menu" local jump.
+
+; This is where the party menu loop begins.
- ; Loads the party menu to select a Pokémon. Relative jump
- ; to the ".cancel" local jump if the player leaves
- ; the party menu without selecting anything.
+; Loads the party menu to select a Pokémon. Relative jump
+; to the ".cancel" local jump if the player leaves
+; the party menu without selecting anything.
+.loop_party_menu
farcall SelectMonFromParty
jr c, .cancel
- Replace the relative jump that exits the menu when there are no moves to learn with a relative jump that loops back to the party menu.
This step will vary depending on whether the reader has already implemented the Add Move Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Move Menu Loop - Not Implemented
; Generates the Move Reminder's menu. Relative jump to the
- ; ".exit_menu" local jump if the player leaves
+ ; ".loop_party_menu" local jump if the player leaves
; the menu and continue if they do not.
call ChooseMoveToLearn
- jr c, .exit_menu
+ jr c, .loop_party_menu
Add Move Menu Loop - Implemented
; Generates the Move Reminder's menu. Relative jump to the
-; ".exit_menu" local jump if the player leaves
+; ".loop_party_menu" local jump if the player leaves
; the menu and continue if they do not.
.loop_move_menu
call ChooseMoveToLearn
- jr c, .exit_menu
+ jr c, .loop_party_menu
- Remove the now redundant
.exit_menu
local jump.
This step will vary depending on whether the reader has already implemented the Add Move Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Move Menu Loop - Not Implemented
Note: The reason for removing only the .exit_menu
local jump and not its code block is that it is still needed to return to the map with the speech text box open, ensuring that the subsequent cancel text is displayed correctly.
; Relative jump to the ".move_learned" local jump if
; a move has been learned and continue if not.
ld a, b
dec a
jr z, .move_learned
-; This code falls through into the ".exit_menu" local jump.
-; Exits the menu and goes back to the
-; map with a speech text box open.
-.exit_menu
+ ; Exits the menu and goes back to the
+ ; map with a speech text box open.
call ReturnToMapWithSpeechTextbox
; This code falls through into the ".cancel" local jump.
; Loads and prints the "MoveReminderCancelText" text.
; This ends the dialogue.
.cancel
Add Move Menu Loop - Implemented
Note: The reason that the entire .exit_menu
local jump is being removed, is that it will no longer be executed by anything (neither via jumping or fall through).
; Rechecks for any moves that can be learned. Relative
; jump to the ".no_moves_to_learn" local jump if
; there are none and relative jump to the
; ".loop_move_menu" local jump if there are.
.recheck_for_moves
call GetRemindableMoves
jr z, .no_moves_to_learn
jr .loop_move_menu
-
-; Exits the menu and goes back to the
-; map with a speech text box open.
-.exit_menu
- call ReturnToMapWithSpeechTextbox
-; This code falls through into the ".cancel" local jump.
; Loads and prints the "MoveReminderCancelText" text.
; This ends the dialogue.
.cancel
- Make the party menu loop if the currently selected Pokémon has no moves to learn or if the player selects an egg or a glitched Pokémon.
-; Loads and prints the "MoveReminderEggText" text.
-; This ends the dialogue.
+; Loads and prints the "MoveReminderEggText" text and then waits for
+; the player to press a button for the text to progress. Then
+; relative jump to the ".loop_party_menu" local jump.
.is_an_egg
ld hl, MoveReminderEggText
- jp PrintText
+ call PrintText
+ jr .loop_party_menu
-; Loads and prints the "MoveReminderNotaMonText" text.
-; This ends the dialogue.
+; Loads and prints the "MoveReminderNotaMonText" text and then waits
+; for the player to press a button for the text to progress. Then
+; relative jump to the ".loop_party_menu" local jump.
.not_a_pokemon
ld hl, MoveReminderNotaMonText
- jp PrintText
+ call PrintText
+ jr .loop_party_menu
-; Loads and prints the "MoveReminderNoMovesText" text.
-; This ends the dialogue.
+; Loads and prints the "MoveReminderNoMovesText" text and then waits
+; for the player to press a button for the text to progress. Then
+; relative jump to the ".loop_party_menu" local jump.
.no_moves_to_learn
ld hl, MoveReminderNoMovesText
- jp PrintText
+ call PrintText
+ jr .loop_party_menu
- Prompt the player to press a button after the text that appears when the currently selected Pokémon has no moves to learn or if the player selects an egg or a glitched Pokémon.
Note: This prevents the text from disappearing as soon as it is printed.
; This is the text that displays if the player
; selects an egg in the party menu.
MoveReminderEggText:
text "An EGG can't learn"
line "any moves!"
- done
+ prompt
; This is the text that displays if the player
; selects an entry in the party menu that
; is neither a Pokémon or an egg.
MoveReminderNotaMonText:
text "What is that!?"
para "I'm sorry, but I"
line "can only teach"
cont "moves to #MON!"
- done
+ prompt
; This is the text that displays if the player
; selects a Pokémon in the party menu that
; has no moves that can be learned.
MoveReminderNoMovesText:
text "There are no moves"
line "for this #MON"
cont "to learn."
- done
+ prompt
The party menu loop has now been implemented.
- Create the
.loop_move_menu
local jump afterMoveReminderWhichMoveText
text as this is where the move menu loop will begin.
This step will vary depending on whether the reader has already implemented the Add Party Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Party Menu Loop - Not Implemented
; Loads and prints the "MoveReminderWhichMoveText" text.
ld hl, MoveReminderWhichMoveText
call PrintText
+; This code falls through into the ".loop_move_menu" local jump.
+
+; This is where the move menu loop begins.
- ; Generates the Move Reminder's menu. Relative jump to the
- ; ".exit_menu" local jump if the player leaves
- ; the menu and continue if they do not.
+; Generates the Move Reminder's menu. Relative jump to the
+; ".exit_menu" local jump if the player leaves
+; the menu and continue if they do not.
+.loop_move_menu
call ChooseMoveToLearn
jr c, .exit_menu
Add Party Menu Loop - Implemented
; Loads and prints the "MoveReminderWhichMoveText" text.
ld hl, MoveReminderWhichMoveText
call PrintText
+; This code falls through into the ".loop_move_menu" local jump.
+
+; This is where the move menu loop begins.
- ; Generates the Move Reminder's menu. Relative jump to the
- ; ".loop_party_menu" local jump if the player leaves
- ; the menu and continue if they do not.
+; Generates the Move Reminder's menu. Relative jump to the
+; ".loop_party_menu" local jump if the player leaves
+; the menu and continue if they do not.
+.loop_move_menu
call ChooseMoveToLearn
jr c, .loop_party_menu
- Create the
.recheck_for_moves
local jump that will execute if a move has not been learned.
This is what allows the move menu to loop if there are any further moves to learn.
This step will vary depending on whether the reader has already implemented the Add Party Menu Loop subsection of the Loop menus for Convenience. Click to expand the applicable code.
Add Party Menu Loop - Not Implemented
Note: Here the .recheck_for_moves
local jump is executed via fall through when a move is not learned. However, it is also jumped to when a move is learned in code that will be introduced at a later point.
; Relative jump to the ".move_learned" local jump if
; a move has been learned and continue if not.
ld a, b
dec a
jr z, .move_learned
-; This code falls through into the ".exit_menu" local jump.
+; This code falls through into the ".recheck_for_moves" local jump.
+
+; Rechecks for any moves that can be learned. Relative
+; jump to the ".no_moves_to_learn" local jump if
+; there are none and relative jump to the
+; ".loop_move_menu" local jump if there are.
+.recheck_for_moves
+ call GetRemindableMoves
+ jr z, .no_moves_to_learn
+ jr .loop_move_menu
Add Party Menu Loop - Implemented
Note: Here the .recheck_for_moves
local jump is executed via fall through when a move is not learned. However, it is also jumped to when a move is learned in code that will be introduced at a later point.
; Relative jump to the ".move_learned" local jump if
; a move has been learned and continue if not.
ld a, b
dec a
jr z, .move_learned
+; This code falls through into the ".recheck_for_moves" local jump.
+
+; Rechecks for any moves that can be learned. Relative
+; jump to the ".no_moves_to_learn" local jump if
+; there are none and relative jump to the
+; ".loop_move_menu" local jump if there are.
+.recheck_for_moves
+ call GetRemindableMoves
+ jr z, .no_moves_to_learn
+ jr .loop_move_menu
- Remove redundant code (Compatibility with the Add Party Menu Loop section).
Note: This step is only relevant if the reader has implemented the Add Party Menu Loop subsection of the Loop menus for Convenience of this tutorial. Click to expand the code.
Add Party Menu Loop - Implemented
Note: This code is being removed as it will no longer be executed via fall through. The two relative jumps above it prevent that.
; Rechecks for any moves that can be learned. Relative
; jump to the ".no_moves_to_learn" local jump if
; there are none and relative jump to the
; ".loop_move_menu" local jump if there are.
.recheck_for_moves
call GetRemindableMoves
jr z, .no_moves_to_learn
jr .loop_move_menu
-
- ; Exits the menu and goes back to the
- ; map with a speech text box open.
- call ReturnToMapWithSpeechTextbox
-; This code falls through into the ".cancel" local jump.
; Loads and prints the "MoveReminderCancelText" text.
; This ends the dialogue.
.cancel
- Recheck for moves once a move has been learned.
This step will vary depending on whether the reader has already implemented the Pay for Each Move Learned section. Click to expand the applicable code.
Pay for Each Move Learned - Not Implemented
; Exits the menu and goes back to the map with a
-; speech text box open and then loads and prints
-; the "MoveReminderMoveLearnedText" text.
-; This ends the dialogue.
+; speech text box open, loads and prints
+; the "MoveReminderMoveLearnedText"
+; text and relative jump to the
+; ".recheck_for_moves" local jump.
.move_learned
call ReturnToMapWithSpeechTextbox
ld hl, MoveReminderMoveLearnedText
- jp PrintText
+ call PrintText
+ jr .recheck_for_moves
Pay for Each Move Learned - Implemented
; Places the player's current money at the top right corner of
; the screen, retrieves the amount of money defined in the
; "MoveCost" label, removes the defined amount of money from
-; the player, plays the "SFX_TRANSACTION" sound effect,
-; prints the "MoveReminderPaymentReceivedText"text and
-; finally relative jump to the ".cancel" local jump.
+; the player, plays the "SFX_TRANSACTION" sound effect and
+; finally prints the "MoveReminderPaymentReceivedText" text.
.pay_for_move
farcall PlaceMoneyTopRight
ld hl, MoveCost
ld de, hMoneyTemp
ld bc, 3
call CopyBytes
call ApplyTilemap
call PromptButton
call WaitSFX
ld bc, hMoneyTemp
ld de, wMoney
farcall TakeMoney
farcall PlaceMoneyTopRight
ld de, SFX_TRANSACTION
call PlaySFX
call WaitSFX
ld hl, MoveReminderPaymentReceivedText
call PrintText
- jr .cancel
+
+ ; Calls the "CheckCostAgainstPlayerMoney" label. Relative
+ ; jump to the ".not_enough_money" local jump if the
+ ; player does not have enough money and relative jump
+ ; to the ".recheck_for_moves" local jump if they do.
+ call CheckCostAgainstPlayerMoney
+ jr c, .not_enough_money
+ jr .recheck_for_moves
- Prompt the player to press a button after the text that appears when a move has been learned (Compatibility with the Pay for Each Move Learned section).
This prevents the text from disappearing as soon as it is printed.
Note: This step is only necessary if the reader has not implemented the Pay for Each Move Learned section of this tutorial. Click to expand the code.
Pay for Each Move Learned - Not Implemented
; This is the text that displays after a
; Pokémon successfully learns a move.
MoveReminderMoveLearnedText:
text "Done! Your #MON"
line "remembered the"
cont "move."
- done
+ prompt
The move menu loop has now been implemented.
TwitchPlaysPokemon
-
Original Move Reminder code.
-
https://github.com/TwitchPlaysPokemon/tppcrystal251pub/blob/public/event/move_relearner.asm
Polished Crystal
-
Modified Move Reminder code based on TwitchPlaysPokemon's implementation.
Idain
-
Updated move reminder based on Polished Crystal's implementation (used as a base for this tutorial).
-
https://github.com/Idain/Another-PKMN-Crystal-Remaster/blob/master/engine/events/move_reminder.asm
-
Explanation for how moves are retrieved from the EvosAttacksPointers table.
Damien
-
Payment code.
-
Show perfect accuracy moves as
---
code.
Nayru62
-
Original percentage conversion code.
-
Explainations of updated percentage conversion code and ASM.
Ax6
- Updated percentage conversion code.
SourApple/SoupPotato
-
BuggingMotivating the writer of this tutorial to complete it. -
Implemented this Move Reminder into Sour Crystal which allowed for more extensive testing.
-
Testing
Vulcandth
- Explanation of why some missing code was necessary.