mirror of
https://github.com/thornAvery/jep-hack.git
synced 2026-02-06 16:15:24 +13:00
First Commit
Upload literally everything from the pokecrystal16 expand-move-ID branch
This commit is contained in:
commit
2f8a41f833
4618 changed files with 480386 additions and 0 deletions
1
docs/_config.yml
Normal file
1
docs/_config.yml
Normal file
|
|
@ -0,0 +1 @@
|
|||
markdown: gfm
|
||||
112
docs/assets/css/style.scss
Normal file
112
docs/assets/css/style.scss
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
---
|
||||
|
||||
@import "{{ site.theme }}";
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
body { color: #a9bacb; background-color: #14171a; }
|
||||
|
||||
a,
|
||||
.markdown-body h1 .octicon-link,
|
||||
.markdown-body h2 .octicon-link,
|
||||
.markdown-body h3 .octicon-link,
|
||||
.markdown-body h4 .octicon-link,
|
||||
.markdown-body h5 .octicon-link,
|
||||
.markdown-body h6 .octicon-link { color: #3689b2; }
|
||||
|
||||
.markdown-body hr { background-color: #64757f; }
|
||||
.markdown-body blockquote { color: #667380; border-left-color: #3d454b; }
|
||||
.markdown-body kbd { color: #8896a4; background-color: #181d20; border-color: #393f46; border-bottom-color: #4e565f; box-shadow: inset 0 -1px 0 #4e565f; }
|
||||
.markdown-body h1,
|
||||
.markdown-body h2 { border-bottom: 1px solid #64757f; }
|
||||
.markdown-body h6 { color: #717d89; } /* ok */
|
||||
.markdown-body table th,
|
||||
.markdown-body table td { border-color: #30373c; }
|
||||
.markdown-body table tr { background-color: #14171a; border-top-color: #393f46; }
|
||||
.markdown-body table tr:nth-child(2n) { background-color: #23292d; }
|
||||
.markdown-body img { background-color: #14171a; }
|
||||
.markdown-body span.frame > span { border-color: #30373c; }
|
||||
.markdown-body span.frame span span { color: #a9bacb; }
|
||||
.markdown-body code,
|
||||
.markdown-body tt { background-color: rgba(229,225,221,0.05); }
|
||||
.markdown-body .highlight pre,
|
||||
.markdown-body pre { background-color: #23292d; }
|
||||
.markdown-body .csv-data .blob-num { background-color: #14171a; }
|
||||
.markdown-body .csv-data th { background-color: #23292d; }
|
||||
|
||||
.highlight { background-color: #181d20; }
|
||||
|
||||
.highlight .w { color: #242424; } /* Text.Whitespace */
|
||||
|
||||
.highlight .err { color: #f61717; background-color: #330000; } /* Error */
|
||||
|
||||
.highlight .gi { color: #ffffff; background-color: #225522; } /* Generic.Inserted */
|
||||
.highlight .gd { color: #ffffff; background-color: #662222; } /* Generic.Deleted */
|
||||
.highlight .ge { color: #ffffff; } /* Generic.Emph */
|
||||
.highlight .gr { color: #b22518; } /* Generic.Error */
|
||||
.highlight .gh { color: #253b22; } /* Generic.Heading */
|
||||
.highlight .go { color: #777777; } /* Generic.Output */
|
||||
.highlight .gp { color: #cccccc; } /* Generic.Prompt */
|
||||
.highlight .gu { color: #555555; } /* Generic.Subheading */
|
||||
.highlight .gt { color: #aa0000; } /* Generic.Traceback */
|
||||
|
||||
.highlight .c { color: #5f5a60; } /* Comment */
|
||||
.highlight .cm { color: #5f5a60; } /* Comment.Multiline */
|
||||
.highlight .cp { color: #5f5a60; } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #5f5a60; } /* Comment.Single */
|
||||
.highlight .cs { color: #5f5a60; } /* Comment.Special */
|
||||
.highlight .cd { color: #5f5a60; }
|
||||
|
||||
.highlight .k { color: #ffffff; } /* Keyword */
|
||||
.highlight .kc { color: #ffffff; } /* Keyword.Constant */
|
||||
.highlight .kd { color: #ffffff; } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #ffffff; } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #ffffff; } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #ffffff; } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #ffffff; } /* Keyword.Type */
|
||||
.highlight .kv { color: #ffffff; }
|
||||
|
||||
.highlight .o { color: #ffffff; } /* Operator */
|
||||
.highlight .ow { color: #aa22ff; } /* Operator.Word */
|
||||
|
||||
.highlight .m { color: #cf6a4c; } /* Literal.Number */
|
||||
.highlight .mb { color: #cf6a4c; } /* Literal.Number.Bin */
|
||||
.highlight .mf { color: #cf6a4c; } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #cf6a4c; } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #cf6a4c; } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #cf6a4c; } /* Literal.Number.Oct */
|
||||
.highlight .mx { color: #cf6a4c; }
|
||||
.highlight .il { color: #cf6a4c; } /* Literal.Number.Integer.Long */
|
||||
|
||||
.highlight .s { color: #8f9d6a; } /* Literal.String */
|
||||
.highlight .sb { color: #8f9d6a; } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #8f9d6a; } /* Literal.String.Char */
|
||||
.highlight .sd { color: #8f9d6a; } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #8f9d6a; } /* Literal.String.Double */
|
||||
.highlight .se { color: #8f9d6a; } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #8f9d6a; } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #8f9d6a; } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #8f9d6a; } /* Literal.String.Other */
|
||||
.highlight .sr { color: #e9c062; } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #8f9d6a; } /* Literal.String.Single */
|
||||
.highlight .ss { color: #daefa3; } /* Literal.String.Symbol */
|
||||
|
||||
.highlight .vc { color: #7587a6; } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #7587a6; } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #7587a6; } /* Name.Variable.Instance */
|
||||
.highlight .na { color: #f9ee98; } /* Name.Attribute */
|
||||
.highlight .nb { color: #cda869; } /* Name.Builtin */
|
||||
.highlight .nc { color: #9b859d; } /* Name.Class */
|
||||
.highlight .no { color: #9b859d; } /* Name.Constant */
|
||||
.highlight .nd { color: #7587a6; } /* Name.Decorator */
|
||||
.highlight .ni { color: #cf6a4c; } /* Name.Entity */
|
||||
.highlight .ne { color: #9b703f; } /* Name.Exception */
|
||||
.highlight .nf { color: #9b703f; } /* Name.Function */
|
||||
.highlight .nl { color: #9b703f; } /* Name.Label */
|
||||
.highlight .nn { color: #9b859d; } /* Name.Namespace */
|
||||
.highlight .nt { color: #cda869; } /* Name.Tag */
|
||||
.highlight .nv { color: #7587a6; } /* Name.Variable */
|
||||
.highlight .bp { color: #00aaaa; } /* Name.Builtin.Pseudo */
|
||||
|
||||
}
|
||||
261
docs/battle_anim_commands.md
Normal file
261
docs/battle_anim_commands.md
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
# Battle Animation Commands
|
||||
|
||||
Defined in [macros/scripts/battle_anims.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/battle_anims.asm) and [engine/battle_anims/anim_commands.asm:BattleAnimCommands](https://github.com/pret/pokecrystal/blob/master/engine/battle_anims/anim_commands.asm).
|
||||
|
||||
|
||||
## `$00`−`$CF`: <code>anim_wait <i>length</i></code>
|
||||
|
||||
- *length*: duration in frames
|
||||
|
||||
|
||||
## `$D0`: <code>anim_obj <i>object</i>, <i>x</i>, <i>y</i>, <i>param</i></code>
|
||||
|
||||
***Alternate*: <code>anim_obj <i>object</i>, <i>x_tile</i>, <i>x</i>, <i>y_tile</i>, <i>y</i>, <i>param</i></code>**
|
||||
|
||||
Spawns an *object* at coordinate (*x*, *y*).
|
||||
|
||||
- *object*: `ANIM_OBJ` constants (see [constants/battle_anim_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/battle_anim_constants.asm))
|
||||
- *x*: the x position in pixels
|
||||
- *y*: the y position in pixels
|
||||
- *x_tile*: an added x position in tiles (8 pixels)
|
||||
- *y_tile*: an added y position in tiles (8 pixels)
|
||||
- *param*: modifies the behavior of *object*. The meaning differs for each object.
|
||||
|
||||
The y position also depends on the y offset defined by the object.
|
||||
|
||||
- *TODO: what happens for x/y values greater than 160/144 respectively? Is it 1:1 with screen coordinates?*
|
||||
- *TODO: how are the x/y values mirrored when the opponent is attacking?*
|
||||
- *TODO: useful positions*
|
||||
- *TODO: document each object*
|
||||
|
||||
|
||||
## `$D1`: <code>anim_1gfx <i>gfx</i></code>
|
||||
|
||||
|
||||
## `$D2`: <code>anim_2gfx <i>gfx1</i>, <i>gfx2</i></code>
|
||||
|
||||
|
||||
## `$D3`: <code>anim_3gfx <i>gfx1</i>, <i>gfx2</i>, <i>gfx3</i></code>
|
||||
|
||||
|
||||
## `$D4`: <code>anim_4gfx <i>gfx1</i>, <i>gfx2</i>, <i>gfx3</i>, <i>gfx4</i></code>
|
||||
|
||||
|
||||
## `$D5`: <code>anim_5gfx <i>gfx1</i>, <i>gfx2</i>, <i>gfx3</i>, <i>gfx4</i>, <i>gfx5</i></code>
|
||||
|
||||
Loads 1-5 sets of graphics. Will overwrite any previously loaded sets.
|
||||
|
||||
- *gfx*: `ANIM_GFX` constants (see [constants/battle_anim_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/battle_anim_constants.asm))
|
||||
|
||||
Caveats:
|
||||
- These will override any currently-loaded GFX.
|
||||
|
||||
|
||||
## `$D6`: <code>anim_incobj <i>object_id</i></code>
|
||||
|
||||
Increments an object's state.
|
||||
|
||||
- *object_id*: the nth object in order of creation
|
||||
|
||||
Objects are state machines. `anim_incobj` progresses the state of an object.
|
||||
|
||||
|
||||
## `$D7`: <code>anim_setobj <i>object_id</i>, <i>state</i></code>
|
||||
|
||||
Sets an object's state to a specific value.
|
||||
|
||||
- *object_id*: the nth object in order of creation
|
||||
- *state*: the state index
|
||||
|
||||
Objects are state machines. `anim_setobj` changes the state of an object.
|
||||
|
||||
|
||||
## `$D8`: <code>anim_incbgeffect <i>bg_effect</i></code>
|
||||
|
||||
Increments a bg effect's state.
|
||||
|
||||
- *bg_effect*: `ANIM_BG` constants (see [constants/battle_anim_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/battle_anim_constants.asm))
|
||||
|
||||
Since there can't be two of the same bg effect, the effect type is used. This is distinct from `anim_incobj`.
|
||||
|
||||
|
||||
## `$D9`: `anim_battlergfx_2row`
|
||||
|
||||
|
||||
## `$DA`: `anim_battlergfx_1row`
|
||||
|
||||
Loads animation graphics for the bottom one or two rows of the enemy pokemon and the top one or two rows of the player's.
|
||||
These graphics are identified through `ANIM_GFX_ENEMYFEET` and `ANIM_GFX_PLAYERHEAD`.
|
||||
|
||||
Caveats:
|
||||
- Doesn't work with `anim_4gfx` and `anim_5gfx`.
|
||||
- This overwrites previously loaded animation graphics if you've loaded more than 53 tiles (2row) or 66 tiles (1row).
|
||||
|
||||
|
||||
## `$DB`: `anim_checkpokeball`
|
||||
|
||||
Sets `BattleAnimVar` to the result of [GetPokeBallWobble](https://github.com/pret/pokecrystal/blob/master/engine/battle_anims/pokeball_wobble.asm).
|
||||
|
||||
|
||||
## `$DC`: `anim_transform`
|
||||
|
||||
|
||||
## `$DD`: `anim_raisesub`
|
||||
|
||||
|
||||
## `$DE`: `anim_dropsub`
|
||||
|
||||
|
||||
## `$DF`: `anim_resetobp0`
|
||||
|
||||
Resets rOBP0 to the default (`q0123` or `%00011011`).
|
||||
|
||||
|
||||
## `$E0`: <code>anim_sound <i>duration</i>, <i>tracks</i>, <i>sound_id</i></code>
|
||||
|
||||
Plays a sound.
|
||||
|
||||
|
||||
## `$E1`: <code>anim_cry <i>pitch</i></code>
|
||||
|
||||
Plays the user's cry.
|
||||
|
||||
|
||||
## `$E2`: `anim_minimizeopp`
|
||||
|
||||
|
||||
## `$E3`: `anim_oamon`
|
||||
|
||||
|
||||
## `$E4`: `anim_oamoff`
|
||||
|
||||
|
||||
## `$E5`: `anim_clearobjs`
|
||||
|
||||
Removes all active objects.
|
||||
|
||||
|
||||
## `$E6`: `anim_beatup`
|
||||
|
||||
|
||||
## `$E7`: `anim_0xe7`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$E8`: `anim_updateactorpic`
|
||||
|
||||
|
||||
## `$E9`: `anim_minimize`
|
||||
|
||||
|
||||
## `$EA`: `anim_0xea`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$EB`: `anim_0xeb`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$EC`: `anim_0xec`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$ED`: `anim_0xed`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$EE`: <code>anim_if_param_and <i>value</i>, <i>address</i></code>
|
||||
|
||||
|
||||
## `$EF`: <code>anim_jumpuntil <i>address</i></code>
|
||||
|
||||
Jumps to another script and decrements `param` until it reaches 0. Similar to `anim_loop`.
|
||||
|
||||
|
||||
## `$F0`: <code>anim_bgeffect <i>bg_effect</i>, <i>unknown1</i>, <i>unknown2</i>, <i>unknown3</i></code>
|
||||
|
||||
- *bg_effect*: `ANIM_BG` constants (see [constants/battle_anim_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/battle_anim_constants.asm))
|
||||
|
||||
|
||||
## `$F1`: <code>anim_bgp <i>colors</i></code>
|
||||
|
||||
Sets `rBGP` to *colors*.
|
||||
|
||||
|
||||
## `$F2`: <code>anim_obp0 <i>colors</i></code>
|
||||
|
||||
Sets `rOBP0` to *colors*.
|
||||
|
||||
|
||||
## `$F3`: <code>anim_obp1 <i>colors</i></code>
|
||||
|
||||
Sets `rOBP1` to *colors*.
|
||||
|
||||
|
||||
## `$F4`: `anim_keepsprites`
|
||||
|
||||
Causes only the palettes to be cleared from the OAM memory when the animation ends, instead of clearing all of the OAM memory. This causes all objects to start using palette 0 (monochrome) when the animation script ends, and whatever objects were on the screen before the last `anim_ret` will stay on the screen.
|
||||
|
||||
This is only used for the Poke Ball animation.
|
||||
|
||||
|
||||
## `$F5`: `anim_0xf5`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$F6`: `anim_0xf6`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$F7`: `anim_0xf7`
|
||||
|
||||
Does nothing. Unused.
|
||||
|
||||
|
||||
## `$F8`: <code>anim_if_param_equal <i>value</i>, <i>address</i></code>
|
||||
|
||||
Jumps to another script if `wBattleAnimParam` is equal to *value*.
|
||||
|
||||
|
||||
## `$F9`: <code>anim_setvar <i>value</i></code>
|
||||
|
||||
Sets `BattleAnimVar` to *value*.
|
||||
|
||||
|
||||
## `$FA`: `anim_incvar`
|
||||
|
||||
Increments `BattleAnimVar` by 1.
|
||||
|
||||
|
||||
## `$FB`: <code>anim_if_var_equal <i>value</i>, <i>address</i></code>
|
||||
|
||||
Jumps to another script if `BattleAnimVar` is equal to *value*.
|
||||
|
||||
|
||||
## `$FC`: <code>anim_jump <i>address</i></code>
|
||||
|
||||
Jumps to another script.
|
||||
|
||||
|
||||
## `$FD`: <code>anim_loop <i>count</i>, <i>address</i></code>
|
||||
|
||||
Jumps to another script up to *count* times. Then does nothing, allowing execution to continue.
|
||||
|
||||
|
||||
## `$FE`: <code>anim_call <i>address</i></code>
|
||||
|
||||
Calls a script.
|
||||
|
||||
There is no call stack. The return address is overwritten, so the maximum call depth is 1.
|
||||
|
||||
|
||||
## `$FF`: `anim_ret`
|
||||
|
||||
Ends the script and returns to where it was called from. If there was no caller, the animation ends.
|
||||
2700
docs/bugs_and_glitches.md
Normal file
2700
docs/bugs_and_glitches.md
Normal file
File diff suppressed because it is too large
Load diff
852
docs/design_flaws.md
Normal file
852
docs/design_flaws.md
Normal file
|
|
@ -0,0 +1,852 @@
|
|||
# Design Flaws
|
||||
|
||||
These are parts of the code that do not work *incorrectly*, like [bugs and glitches](https://github.com/pret/pokecrystal/blob/master/docs/bugs_and_glitches.md), but that clearly exist just to work around a problem. In other words, with a slightly different design, the code would not need to exist at all. Design flaws may be exceptions to a usual rule, such as "tables of pointers in different banks use `dba`" ([one exception](#pic-banks-are-offset-by-pics_fix), [and another](#pok%C3%A9dex-entry-banks-are-derived-from-their-species-ids)) or "graphics used as a unit are stored and loaded contiguously" ([a notable exception](#footprints-are-split-into-top-and-bottom-halves)).
|
||||
|
||||
|
||||
## Contents
|
||||
|
||||
- [Pic banks are offset by `PICS_FIX`](#pic-banks-are-offset-by-pics_fix)
|
||||
- [`PokemonPicPointers` and `UnownPicPointers` are assumed to start at the same address](#pokemonpicpointers-and-unownpicpointers-are-assumed-to-start-at-the-same-address)
|
||||
- [Footprints are split into top and bottom halves](#footprints-are-split-into-top-and-bottom-halves)
|
||||
- [Music IDs $64 and $80 or above have special behavior](#music-ids-64-and-80-or-above-have-special-behavior)
|
||||
- [`ITEM_C3` and `ITEM_DC` break up the continuous sequence of TM items](#item_c3-and-item_dc-break-up-the-continuous-sequence-of-tm-items)
|
||||
- [Pokédex entry banks are derived from their species IDs](#pok%C3%A9dex-entry-banks-are-derived-from-their-species-ids)
|
||||
- [The 6-bit caught level can only record up to level 63](#the-6-bit-caught-level-can-only-record-up-to-level-63)
|
||||
- [Identical sine wave code and data is repeated five times](#identical-sine-wave-code-and-data-is-repeated-five-times)
|
||||
- [`GetForestTreeFrame` works, but it's still bad](#getforesttreeframe-works-but-its-still-bad)
|
||||
- [The overworld scripting engine assumes no more than 127 banks](#the-overworld-scripting-engine-assumes-no-more-than-127-banks)
|
||||
|
||||
|
||||
## Pic banks are offset by `PICS_FIX`
|
||||
|
||||
[data/pokemon/pic_pointers.asm](https://github.com/pret/pokecrystal/blob/master/data/pokemon/pic_pointers.asm), [data/pokemon/unown_pic_pointers.asm](https://github.com/pret/pokecrystal/blob/master/data/pokemon/unown_pic_pointers.asm), and [data/trainers/pic_pointers.asm](https://github.com/pret/pokecrystal/blob/master/data/trainers/pic_pointers.asm) all have to use `dba_pic` instead of `dba`. This is a macro in [macros/data.asm](https://github.com/pret/pokecrystal/blob/master/macros/data.asm) that offsets banks by `PICS_FIX`:
|
||||
|
||||
```asm
|
||||
MACRO dba_pic ; dbw bank, address
|
||||
db BANK(\1) - PICS_FIX
|
||||
dw \1
|
||||
ENDM
|
||||
```
|
||||
|
||||
The offset is translated into a correct bank by `FixPicBank` in [engine/gfx/load_pics.asm](https://github.com/pret/pokecrystal/blob/master/engine/gfx/load_pics.asm):
|
||||
|
||||
```asm
|
||||
FixPicBank:
|
||||
; This is a thing for some reason.
|
||||
|
||||
DEF PICS_FIX EQU $36
|
||||
GLOBAL PICS_FIX
|
||||
|
||||
push hl
|
||||
push bc
|
||||
sub BANK("Pics 1") - PICS_FIX
|
||||
ld c, a
|
||||
ld b, 0
|
||||
ld hl, .PicsBanks
|
||||
add hl, bc
|
||||
ld a, [hl]
|
||||
pop bc
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.PicsBanks:
|
||||
db BANK("Pics 1") ; BANK("Pics 1") + 0
|
||||
...
|
||||
db BANK("Pics 24") ; BANK("Pics 1") + 23
|
||||
```
|
||||
|
||||
**Fix:** Delete `FixPicBank` and remove all four calls to `FixPicBank` in [engine/gfx/load_pics.asm](https://github.com/pret/pokecrystal/blob/master/engine/gfx/load_pics.asm). Then use `dba` instead of `dba_pic` everywhere.
|
||||
|
||||
|
||||
## `PokemonPicPointers` and `UnownPicPointers` are assumed to start at the same address
|
||||
|
||||
`GetFrontpicPointer` and `GetMonBackpic` in [engine/gfx/load_pics.asm](https://github.com/pret/pokecrystal/blob/master/engine/gfx/load_pics.asm) make this assumption, which has to be accounted for in the data files.
|
||||
|
||||
In [gfx/pics.asm](https://github.com/pret/pokecrystal/blob/master/gfx/pics.asm):
|
||||
|
||||
```asm
|
||||
; PokemonPicPointers and UnownPicPointers are assumed to start at the same
|
||||
; address, but in different banks. This is enforced in layout.link.
|
||||
|
||||
|
||||
SECTION "Pic Pointers", ROMX
|
||||
|
||||
INCLUDE "data/pokemon/pic_pointers.asm"
|
||||
|
||||
|
||||
SECTION "Unown Pic Pointers", ROMX
|
||||
|
||||
INCLUDE "data/pokemon/unown_pic_pointers.asm"
|
||||
```
|
||||
|
||||
In [layout.link](https://github.com/pret/pokecrystal/blob/master/layout.link):
|
||||
|
||||
```
|
||||
ROMX $48
|
||||
org $4000
|
||||
"Pic Pointers"
|
||||
"Pics 1"
|
||||
ROMX $49
|
||||
org $4000
|
||||
"Unown Pic Pointers"
|
||||
"Pics 2"
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
|
||||
Don't enforce `org $4000` in [layout.link](https://github.com/pret/pokecrystal/blob/master/layout.link).
|
||||
|
||||
Edit `GetFrontpicPointer`:
|
||||
|
||||
```diff
|
||||
ld a, [wCurPartySpecies]
|
||||
cp UNOWN
|
||||
jr z, .unown
|
||||
+ ld hl, PokemonPicPointers
|
||||
ld a, [wCurPartySpecies]
|
||||
ld d, BANK(PokemonPicPointers)
|
||||
jr .ok
|
||||
.unown
|
||||
+ ld hl, UnownPicPointers
|
||||
ld a, [wUnownLetter]
|
||||
ld d, BANK(UnownPicPointers)
|
||||
.ok
|
||||
- ; These are assumed to be at the same address in their respective banks.
|
||||
- assert PokemonPicPointers == UnownPicPointers
|
||||
- ld hl, PokemonPicPointers
|
||||
dec a
|
||||
ld bc, 6
|
||||
call AddNTimes
|
||||
```
|
||||
|
||||
And `GetMonBackpic`:
|
||||
|
||||
```diff
|
||||
- ; These are assumed to be at the same address in their respective banks.
|
||||
- assert PokemonPicPointers == UnownPicPointers
|
||||
ld hl, PokemonPicPointers
|
||||
ld a, b
|
||||
ld d, BANK(PokemonPicPointers)
|
||||
cp UNOWN
|
||||
jr nz, .ok
|
||||
+ ld hl, UnownPicPointers
|
||||
ld a, c
|
||||
ld d, BANK(UnownPicPointers)
|
||||
.ok
|
||||
dec a
|
||||
ld bc, 6
|
||||
call AddNTimes
|
||||
```
|
||||
|
||||
|
||||
## Footprints are split into top and bottom halves
|
||||
|
||||
In [gfx/footprints.asm](https://github.com/pret/pokecrystal/blob/master/gfx/footprints.asm):
|
||||
|
||||
```asm
|
||||
; Footprints are 2x2 tiles each, but are stored as a 16x64-tile image
|
||||
; (32 rows of 8 footprints per row).
|
||||
; That means there's a row of the top two tiles for eight footprints,
|
||||
; then a row of the bottom two tiles for those eight footprints.
|
||||
|
||||
; These macros help extract the first and the last two tiles, respectively.
|
||||
DEF footprint_top EQUS "0, 2 * LEN_1BPP_TILE"
|
||||
DEF footprint_bottom EQUS "2 * LEN_1BPP_TILE, 2 * LEN_1BPP_TILE"
|
||||
|
||||
Footprints:
|
||||
; Entries correspond to Pokémon species, two apiece, 8 tops then 8 bottoms
|
||||
table_width LEN_1BPP_TILE * 4, Footprints
|
||||
|
||||
; 001-008 top halves
|
||||
INCBIN "gfx/footprints/bulbasaur.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/ivysaur.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/venusaur.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/charmander.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/charmeleon.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/charizard.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/squirtle.1bpp", footprint_top
|
||||
INCBIN "gfx/footprints/wartortle.1bpp", footprint_top
|
||||
; 001-008 bottom halves
|
||||
INCBIN "gfx/footprints/bulbasaur.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/ivysaur.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/venusaur.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/charmander.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/charmeleon.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/charizard.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/squirtle.1bpp", footprint_bottom
|
||||
INCBIN "gfx/footprints/wartortle.1bpp", footprint_bottom
|
||||
...
|
||||
```
|
||||
|
||||
`Pokedex_LoadAnyFootprint` in [engine/pokedex/pokedex.asm](https://github.com/pret/pokecrystal/blob/master/engine/pokedex/pokedex.asm) has to load the halves separately.
|
||||
|
||||
**Fix:**
|
||||
|
||||
Store footprints contiguously:
|
||||
|
||||
```asm
|
||||
|
||||
Footprints:
|
||||
table_width LEN_1BPP_TILE * 4, Footprints
|
||||
|
||||
INCBIN "gfx/footprints/bulbasaur.1bpp"
|
||||
INCBIN "gfx/footprints/ivysaur.1bpp"
|
||||
INCBIN "gfx/footprints/venusaur.1bpp"
|
||||
INCBIN "gfx/footprints/charmander.1bpp"
|
||||
INCBIN "gfx/footprints/charmeleon.1bpp"
|
||||
INCBIN "gfx/footprints/charizard.1bpp"
|
||||
INCBIN "gfx/footprints/squirtle.1bpp"
|
||||
INCBIN "gfx/footprints/wartortle.1bpp"
|
||||
...
|
||||
```
|
||||
|
||||
Edit `Pokedex_LoadAnyFootprint`:
|
||||
|
||||
```diff
|
||||
ld a, [wTempSpecies]
|
||||
dec a
|
||||
and %111
|
||||
swap a ; * $10
|
||||
+ add a, a
|
||||
ld l, a
|
||||
ld h, 0
|
||||
add hl, de
|
||||
ld de, Footprints
|
||||
add hl, de
|
||||
|
||||
- push hl
|
||||
ld e, l
|
||||
ld d, h
|
||||
ld hl, vTiles2 tile $62
|
||||
- lb bc, BANK(Footprints), 2
|
||||
+ lb bc, BANK(Footprints), 4
|
||||
call Request1bpp
|
||||
- pop hl
|
||||
-
|
||||
- ; Whoever was editing footprints forgot to fix their
|
||||
- ; tile editor. Now each bottom half is 8 tiles off.
|
||||
- ld de, 8 tiles
|
||||
- add hl, de
|
||||
-
|
||||
- ld e, l
|
||||
- ld d, h
|
||||
- ld hl, vTiles2 tile $64
|
||||
- lb bc, BANK(Footprints), 2
|
||||
- call Request1bpp
|
||||
```
|
||||
|
||||
|
||||
## Music IDs $64 and $80 or above have special behavior
|
||||
|
||||
If a map's music ID in [data/maps/maps.asm](https://github.com/pret/pokecrystal/blob/master/master/data/maps/maps.asm) is $64 (the value of `MUSIC_MAHOGANY_MART` or `MUSIC_SUICUNE_BATTLE`) it will play either `MUSIC_ROCKET_HIDEOUT` or `MUSIC_CHERRYGROVE_CITY`. Moreover, if a map's music ID is $80 or above (the value of `RADIO_TOWER_MUSIC`) it might play `MUSIC_ROCKET_OVERTURE` or something else. This is caused by `GetMapMusic` in [home/map.asm](https://github.com/pret/pokecrystal/blob/master/master/home/map.asm).
|
||||
|
||||
**Fix:**
|
||||
|
||||
Replace `RADIO_TOWER_MUSIC | MUSIC_GOLDENROD_CITY` with `MUSIC_RADIO_TOWER` in [data/maps/maps.asm](https://github.com/pret/pokecrystal/blob/master/master/data/maps/maps.asm).
|
||||
|
||||
Redefine the special music constants in [constants/music_constants.asm](https://github.com/pret/pokecrystal/blob/master/master/constants/music_constants.asm):
|
||||
|
||||
```diff
|
||||
-; GetMapMusic picks music for this value (see home/map.asm)
|
||||
-DEF MUSIC_MAHOGANY_MART EQU $64
|
||||
+; GetMapMusic picks music for these values (see home/map.asm)
|
||||
+DEF MUSIC_MAHOGANY_MART EQU $fc
|
||||
+DEF MUSIC_RADIO_TOWER EQU $fd
|
||||
|
||||
; ExitPokegearRadio_HandleMusic uses these values
|
||||
DEF RESTART_MAP_MUSIC EQU $fe
|
||||
DEF ENTER_MAP_MUSIC EQU $ff
|
||||
-
|
||||
-; GetMapMusic picks music for this bit flag
|
||||
-DEF RADIO_TOWER_MUSIC_F EQU 7
|
||||
-DEF RADIO_TOWER_MUSIC EQU 1 << RADIO_TOWER_MUSIC_F
|
||||
```
|
||||
|
||||
Edit `GetMapMusic`:
|
||||
|
||||
```diff
|
||||
GetMapMusic::
|
||||
push hl
|
||||
push bc
|
||||
ld de, MAP_MUSIC
|
||||
call GetMapField
|
||||
ld a, c
|
||||
cp MUSIC_MAHOGANY_MART
|
||||
jr z, .mahoganymart
|
||||
- bit RADIO_TOWER_MUSIC_F, c
|
||||
- jr nz, .radiotower
|
||||
+ cp MUSIC_RADIO_TOWER
|
||||
+ jr z, .radiotower
|
||||
farcall Function8b342
|
||||
ld e, c
|
||||
ld d, 0
|
||||
.done
|
||||
pop bc
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.radiotower
|
||||
ld a, [wStatusFlags2]
|
||||
bit STATUSFLAGS2_ROCKETS_IN_RADIO_TOWER_F, a
|
||||
jr z, .clearedradiotower
|
||||
ld de, MUSIC_ROCKET_OVERTURE
|
||||
jr .done
|
||||
|
||||
.clearedradiotower
|
||||
- ; the rest of the byte
|
||||
- ld a, c
|
||||
- and RADIO_TOWER_MUSIC - 1
|
||||
- ld e, a
|
||||
- ld d, 0
|
||||
+ ld de, MUSIC_GOLDENROD_CITY
|
||||
jr .done
|
||||
|
||||
.mahoganymart
|
||||
ld a, [wStatusFlags2]
|
||||
bit STATUSFLAGS2_ROCKETS_IN_MAHOGANY_F, a
|
||||
jr z, .clearedmahogany
|
||||
ld de, MUSIC_ROCKET_HIDEOUT
|
||||
jr .done
|
||||
|
||||
.clearedmahogany
|
||||
ld de, MUSIC_CHERRYGROVE_CITY
|
||||
jr .done
|
||||
```
|
||||
|
||||
|
||||
## `ITEM_C3` and `ITEM_DC` break up the continuous sequence of TM items
|
||||
|
||||
[constants/item_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/item_constants.asm) defined the 50 TMs in order with `add_tm`, but `ITEM_C3` and `ITEM_DC` break up that sequence.
|
||||
|
||||
```asm
|
||||
add_tm DYNAMICPUNCH ; bf
|
||||
...
|
||||
add_tm ROLLOUT ; c2
|
||||
const ITEM_C3 ; c3
|
||||
add_tm ROAR ; c4
|
||||
...
|
||||
add_tm DIG ; db
|
||||
const ITEM_DC ; dc
|
||||
add_tm PSYCHIC_M ; dd
|
||||
...
|
||||
add_tm NIGHTMARE ; f2
|
||||
DEF NUM_TMS EQU const_value - TM01 - 2 ; discount ITEM_C3 and ITEM_DC
|
||||
```
|
||||
|
||||
`GetTMHMNumber` and `GetNumberedTMHM` in [engine/items/items.asm](https://github.com/pret/pokecrystal/blob/master/engine/items/items.asm) have to compensate for this.
|
||||
|
||||
> There was originally a good reason for these two gaps!
|
||||
>
|
||||
> Pokémon traded from RBY to GSC have their catch rate interpreted as their new held item. This was planned early on in development, so some items were given indexes corresponding to appropriate Gen 1 catch rates:
|
||||
>
|
||||
> - $03 = 3: `BRIGHTPOWDER` is for Articuno, Zapdos, Moltres, and Mewtwo
|
||||
> - $1E = 30: `LUCKY_PUNCH` is for Chansey
|
||||
> - $23 = 35: `METAL_POWDER` is for Ditto
|
||||
> - $3C = 60: `SILVER_LEAF` is for 10 Pokémon
|
||||
> - $4B = 75: `GOLD_LEAF` is for 13 Pokémon
|
||||
> - $96 = 150: `MYSTERYBERRY` is for Clefairy
|
||||
> - $AA = 170: `POLKADOT_BOW` is for Jigglypuff
|
||||
> - $B4 = 180: `BRICK_PIECE` is for Machop
|
||||
>
|
||||
> Yellow was also being developed then, and it did the reverse, altering some Pokémon's data after they're caught to correspond to appropriate Gen 2 items:
|
||||
>
|
||||
> - Starter Pikachu's catch rate byte is overwritten with 163 = $A3 for `LIGHT_BALL`
|
||||
> - Wild-caught Kadabra's catch rate byte is overwritten with 96 = $60 for `TWISTEDSPOON`
|
||||
>
|
||||
> (Yellow also directly changed Dragonair's catch rate to 27 and Dragonite's to 9, but this seems to have been only for adjusting their difficulty, since those meaninglessly correspond to `PROTEIN` and `ANTIDOTE`.)
|
||||
>
|
||||
> Most catch rates were left as gaps in the item list, and transformed into held items via the `TimeCapsule_CatchRateItems` table in [data/items/catch_rate_items.asm](https://github.com/pret/pokecrystal/blob/master/data/items/catch_rate_items.asm). For example, the 52 Pokémon with catch rate 45 would hold the gap `ITEM_2D`, except that gets transformed into `BITTER_BERRY`.
|
||||
>
|
||||
> But a few Pokémon end up with weird items. Abra has a catch rate of 200, or $C8; and Krabby, Horsea, Goldeen, and Staryu have a catch rate of 225, or $E1. Those indexes correspond to the items `TM_PSYCH_UP` and `TM_ICE_PUNCH`, which seem like random choices—because they are.
|
||||
>
|
||||
> The TMs and HMs span from indexes $BF to $F9. However, as we can see in [pokegold-spaceworld](https://github.com/pret/pokegold-spaceworld/blob/master/constants/item_constants.asm), they *originally* spanned $C4 to $FF. For some reason they were shifted down by 5 during development.
|
||||
>
|
||||
> Before the index shift, the gap `ITEM_C3` would have been at index $C8, and `ITEM_DC` at $E1. In other words, they would have neatly corresponded to the catch rates for those five Pokémon! Then they would have held `BERRY` when traded through the Time Capsule (since the gap items get transformed via `TimeCapsule_CatchRateItems`).
|
||||
|
||||
**Fix:**
|
||||
|
||||
Move `ITEM_C3` and `ITEM_DC` above all the TMs in every table of item data.
|
||||
|
||||
Edit [engine/items/items.asm](https://github.com/pret/pokecrystal/blob/master/engine/items/items.asm):
|
||||
|
||||
```diff
|
||||
GetTMHMNumber::
|
||||
; Return the number of a TM/HM by item id c.
|
||||
ld a, c
|
||||
-; Skip any dummy items.
|
||||
- cp ITEM_C3 ; TM04-05
|
||||
- jr c, .done
|
||||
- cp ITEM_DC ; TM28-29
|
||||
- jr c, .skip
|
||||
- dec a
|
||||
-.skip
|
||||
- dec a
|
||||
-.done
|
||||
sub TM01
|
||||
inc a
|
||||
ld c, a
|
||||
ret
|
||||
|
||||
GetNumberedTMHM:
|
||||
; Return the item id of a TM/HM by number c.
|
||||
ld a, c
|
||||
-; Skip any gaps.
|
||||
- cp ITEM_C3 - (TM01 - 1)
|
||||
- jr c, .done
|
||||
- cp ITEM_DC - (TM01 - 1) - 1
|
||||
- jr c, .skip_one
|
||||
-.skip_two
|
||||
- inc a
|
||||
-.skip_one
|
||||
- inc a
|
||||
-.done
|
||||
add TM01
|
||||
dec a
|
||||
ld c, a
|
||||
ret
|
||||
```
|
||||
|
||||
|
||||
## Pokédex entry banks are derived from their species IDs
|
||||
|
||||
`PokedexDataPointerTable` in [data/pokemon/dex_entry_pointers.asm](https://github.com/pret/pokecrystal/blob/master/data/pokemon/dex_entry_pointers.asm) is a table of `dw`, not `dba`, yet there are four banks used for Pokédex entries. The correct bank is derived from the species ID at the beginning of each Pokémon's base stats. (This is the only use the base stat species ID has.)
|
||||
|
||||
Three separate routines do the same derivation: `GetDexEntryPointer` in [engine/pokedex/pokedex_2.asm](https://github.com/pret/pokecrystal/blob/master/engine/pokedex/pokedex_2.asm):
|
||||
|
||||
```asm
|
||||
GetDexEntryPointer:
|
||||
; return dex entry pointer b:de
|
||||
push hl
|
||||
ld hl, PokedexDataPointerTable
|
||||
ld a, b
|
||||
dec a
|
||||
ld d, 0
|
||||
ld e, a
|
||||
add hl, de
|
||||
add hl, de
|
||||
ld e, [hl]
|
||||
inc hl
|
||||
ld d, [hl]
|
||||
push de
|
||||
rlca
|
||||
rlca
|
||||
maskbits NUM_DEX_ENTRY_BANKS
|
||||
ld hl, .PokedexEntryBanks
|
||||
ld d, 0
|
||||
ld e, a
|
||||
add hl, de
|
||||
ld b, [hl]
|
||||
pop de
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.PokedexEntryBanks:
|
||||
db BANK("Pokedex Entries 001-064")
|
||||
db BANK("Pokedex Entries 065-128")
|
||||
db BANK("Pokedex Entries 129-192")
|
||||
db BANK("Pokedex Entries 193-251")
|
||||
```
|
||||
|
||||
`HeavyBall_GetDexEntryBank` in [engine/items/item_effects.asm](https://github.com/pret/pokecrystal/blob/master/engine/items/item_effects.asm):
|
||||
|
||||
```asm
|
||||
HeavyBall_GetDexEntryBank:
|
||||
push hl
|
||||
push de
|
||||
ld a, [wEnemyMonSpecies]
|
||||
rlca
|
||||
rlca
|
||||
maskbits NUM_DEX_ENTRY_BANKS
|
||||
ld hl, .PokedexEntryBanks
|
||||
ld d, 0
|
||||
ld e, a
|
||||
add hl, de
|
||||
ld a, [hl]
|
||||
pop de
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.PokedexEntryBanks:
|
||||
db BANK("Pokedex Entries 001-064")
|
||||
db BANK("Pokedex Entries 065-128")
|
||||
db BANK("Pokedex Entries 129-192")
|
||||
db BANK("Pokedex Entries 193-251")
|
||||
```
|
||||
|
||||
And `PokedexShow_GetDexEntryBank` in [engine/pokegear/radio.asm](https://github.com/pret/pokecrystal/blob/master/engine/pokegear/radio.asm):
|
||||
|
||||
```asm
|
||||
PokedexShow_GetDexEntryBank:
|
||||
push hl
|
||||
push de
|
||||
ld a, [wCurPartySpecies]
|
||||
dec a
|
||||
rlca
|
||||
rlca
|
||||
maskbits NUM_DEX_ENTRY_BANKS
|
||||
ld hl, .PokedexEntryBanks
|
||||
ld d, 0
|
||||
ld e, a
|
||||
add hl, de
|
||||
ld a, [hl]
|
||||
pop de
|
||||
pop hl
|
||||
ret
|
||||
|
||||
.PokedexEntryBanks:
|
||||
db BANK("Pokedex Entries 001-064")
|
||||
db BANK("Pokedex Entries 065-128")
|
||||
db BANK("Pokedex Entries 129-192")
|
||||
db BANK("Pokedex Entries 193-251")
|
||||
```
|
||||
|
||||
**Fix:**
|
||||
|
||||
Use `dba` instead of `dw` in `PokedexDataPointerTable`. Make sure to edit the `table_width` line to specify a width of 3 instead of 2.
|
||||
|
||||
Delete `HeavyBall_GetDexEntryBank` and `PokedexShow_GetDexEntryBank`. You can also delete `NUM_DEX_ENTRY_BANKS` from [constants/pokemon_data_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/pokemon_data_constants.asm).
|
||||
|
||||
Edit [engine/pokedex/pokedex_2.asm](https://github.com/pret/pokecrystal/blob/master/engine/pokedex/pokedex_2.asm):
|
||||
|
||||
```diff
|
||||
GetDexEntryPointer:
|
||||
; return dex entry pointer b:de
|
||||
push hl
|
||||
ld hl, PokedexDataPointerTable
|
||||
ld a, b
|
||||
dec a
|
||||
ld d, 0
|
||||
ld e, a
|
||||
add hl, de
|
||||
add hl, de
|
||||
- ld e, [hl]
|
||||
- inc hl
|
||||
- ld d, [hl]
|
||||
- push de
|
||||
- rlca
|
||||
- rlca
|
||||
- maskbits NUM_DEX_ENTRY_BANKS
|
||||
- ld hl, .PokedexEntryBanks
|
||||
- ld d, 0
|
||||
- ld e, a
|
||||
- add hl, de
|
||||
- ld b, [hl]
|
||||
- pop de
|
||||
+ add hl, de
|
||||
+ ; b = bank
|
||||
+ ld a, [hli]
|
||||
+ ld b, a
|
||||
+ ; de = address
|
||||
+ ld a, [hli]
|
||||
+ ld e, a
|
||||
+ ld d, [hl]
|
||||
pop hl
|
||||
ret
|
||||
-
|
||||
-.PokedexEntryBanks:
|
||||
- db BANK("Pokedex Entries 001-064")
|
||||
- db BANK("Pokedex Entries 065-128")
|
||||
- db BANK("Pokedex Entries 129-192")
|
||||
- db BANK("Pokedex Entries 193-251")
|
||||
```
|
||||
|
||||
Edit [engine/items/item_effects.asm](https://github.com/pret/pokecrystal/blob/master/engine/items/item_effects.asm):
|
||||
|
||||
```diff
|
||||
HeavyBallMultiplier:
|
||||
; subtract 20 from catch rate if weight < 102.4 kg
|
||||
; else add 0 to catch rate if weight < 204.8 kg
|
||||
; else add 20 to catch rate if weight < 307.2 kg
|
||||
; else add 30 to catch rate if weight < 409.6 kg
|
||||
; else add 40 to catch rate
|
||||
ld a, [wEnemyMonSpecies]
|
||||
ld hl, PokedexDataPointerTable
|
||||
dec a
|
||||
ld e, a
|
||||
ld d, 0
|
||||
add hl, de
|
||||
add hl, de
|
||||
+ add hl, de
|
||||
+ ; d = bank, hl = address
|
||||
+ ld a, BANK(PokedexDataPointerTable)
|
||||
+ call GetFarByte
|
||||
+ push af
|
||||
+ inc hl
|
||||
ld a, BANK(PokedexDataPointerTable)
|
||||
call GetFarWord
|
||||
+ pop de
|
||||
|
||||
.SkipText:
|
||||
- call HeavyBall_GetDexEntryBank
|
||||
+ ld a, d
|
||||
call GetFarByte
|
||||
inc hl
|
||||
cp "@"
|
||||
jr nz, .SkipText
|
||||
|
||||
- call HeavyBall_GetDexEntryBank
|
||||
+ ld a, d
|
||||
push bc
|
||||
inc hl
|
||||
inc hl
|
||||
call GetFarWord
|
||||
```
|
||||
|
||||
And edit [engine/pokegear/radio.asm](https://github.com/pret/pokecrystal/blob/master/engine/pokegear/radio.asm):
|
||||
|
||||
```diff
|
||||
PokedexShow2:
|
||||
ld a, [wCurPartySpecies]
|
||||
dec a
|
||||
ld hl, PokedexDataPointerTable
|
||||
ld c, a
|
||||
ld b, 0
|
||||
add hl, bc
|
||||
add hl, bc
|
||||
+ add hl, bc
|
||||
+ ; b = bank
|
||||
+ ld a, BANK(PokedexDataPointerTable)
|
||||
+ call GetFarByte
|
||||
+ ld b, a
|
||||
+ inc hl
|
||||
+ ; hl = address
|
||||
ld a, BANK(PokedexDataPointerTable)
|
||||
call GetFarWord
|
||||
- call PokedexShow_GetDexEntryBank
|
||||
+ ld a, b
|
||||
push af
|
||||
push hl
|
||||
call CopyDexEntryPart1
|
||||
```
|
||||
|
||||
|
||||
## The 6-bit caught level can only record up to level 63
|
||||
|
||||
Crystal added the Poké Seer, who tells you your Pokémon's caught data: where it was caught, what time, and at what level. The status screen also displays the gender of its Original Trainer, since Crystal added player genders. This data is packed into two previously-unused bytes in the `box_struct`; from [macros/ram.asm](https://github.com/pret/pokecrystal/blob/master/macros/ram.asm):
|
||||
|
||||
```asm
|
||||
MACRO box_struct
|
||||
\1Species:: db
|
||||
...
|
||||
\1CaughtData::
|
||||
\1CaughtTime::
|
||||
\1CaughtLevel:: db
|
||||
\1CaughtGender::
|
||||
\1CaughtLocation:: db
|
||||
\1Level:: db
|
||||
\1BoxEnd::
|
||||
ENDM
|
||||
```
|
||||
|
||||
These four pieces of data are packed into two bytes using the bitmasks in [constants/pokemon_data_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/pokemon_data_constants.asm):
|
||||
|
||||
```asm
|
||||
DEF CAUGHT_TIME_MASK EQU %11000000
|
||||
DEF CAUGHT_LEVEL_MASK EQU %00111111
|
||||
|
||||
DEF CAUGHT_GENDER_MASK EQU %10000000
|
||||
DEF CAUGHT_LOCATION_MASK EQU %01111111
|
||||
```
|
||||
|
||||
The caught level only uses six bits, so it can only record levels as high as 2^6 − 1 = 63. If a Pokémon is caught at level 64 or higher, its level overflows into the two bits used for the caught time, before the actual caught time is stored in the same byte with a bitwise `or` operation. For example, a Pokémon caught at level 70 (`%01000110`) in the morning (`%00000000`) would be reported as caught at level 6 (`%000110` in the low six bits) during the day (`%01` in the high two bits).
|
||||
|
||||
This limitation is probably why Lugia and Ho-Oh are both encountered at level 60 in Crystal, instead of level 70 in GS.
|
||||
|
||||
**Possible fixes:**
|
||||
|
||||
- Record any level higher than 63 as level 0, and have the Poké Seer report 0 as "very high".
|
||||
- Use seven bits for the level (which can store up to level 2^7 − 1 = 127) and one for the time, simply recording 0 for morning or day and 1 for night.
|
||||
- Move some data around into unused bits elsewhere in the `box_struct`, such as the high bit of `MON_LEVEL`, or the three high bits of `MON_EXP`.
|
||||
- Add another byte for more caught data, making the `box_struct` larger; this would affect PC Box storage.
|
||||
- Free up some other bytes in the `box_struct` (e.g. by [replacing](https://github.com/pret/pokecrystal/wiki/Replace-stat-experience-with-EVs) 2-byte stat experience with 1-byte EVs).
|
||||
|
||||
|
||||
## Identical sine wave code and data is repeated five times
|
||||
|
||||
`_Sine` in [engine/math/sine.asm](https://github.com/pret/pokecrystal/blob/master/engine/math/sine.asm):
|
||||
|
||||
```asm
|
||||
_Sine::
|
||||
; a = d * sin(e * pi/32)
|
||||
ld a, e
|
||||
calc_sine_wave
|
||||
```
|
||||
|
||||
`Sprites_Cosine` and `Sprites_Sine` in [engine/gfx/sprites.asm](https://github.com/pret/pokecrystal/blob/master/engine/gfx/sprites.asm):
|
||||
|
||||
```asm
|
||||
Sprites_Cosine:
|
||||
; a = d * cos(a * pi/32)
|
||||
add %010000 ; cos(x) = sin(x + pi/2)
|
||||
; fallthrough
|
||||
Sprites_Sine:
|
||||
; a = d * sin(a * pi/32)
|
||||
calc_sine_wave
|
||||
```
|
||||
|
||||
`BattleAnim_Cosine` and `BattleAnim_Sine` in [engine/battle_anims/functions.asm](https://github.com/pret/pokecrystal/blob/master/engine/battle_anims/functions.asm):
|
||||
|
||||
```asm
|
||||
BattleAnim_Cosine:
|
||||
; a = d * cos(a * pi/32)
|
||||
add %010000 ; cos(x) = sin(x + pi/2)
|
||||
; fallthrough
|
||||
BattleAnim_Sine:
|
||||
; a = d * sin(a * pi/32)
|
||||
calc_sine_wave BattleAnimSineWave
|
||||
|
||||
...
|
||||
|
||||
BattleAnimSineWave:
|
||||
sine_table 32
|
||||
```
|
||||
|
||||
`StartTrainerBattle_DrawSineWave` in [engine/battle/battle_transition.asm](https://github.com/pret/pokecrystal/blob/master/engine/battle/battle_transition.asm):
|
||||
|
||||
```asm
|
||||
StartTrainerBattle_DrawSineWave:
|
||||
calc_sine_wave
|
||||
```
|
||||
|
||||
And `CelebiEvent_Cosine` in [engine/events/celebi.asm](https://github.com/pret/pokecrystal/blob/master/engine/events/celebi.asm):
|
||||
|
||||
```asm
|
||||
CelebiEvent_Cosine:
|
||||
; a = d * cos(a * pi/32)
|
||||
add %010000 ; cos(x) = sin(x + pi/2)
|
||||
calc_sine_wave
|
||||
```
|
||||
|
||||
They all rely on `calc_sine_wave` in [macros/code.asm](https://github.com/pret/pokecrystal/blob/master/macros/code.asm):
|
||||
|
||||
```asm
|
||||
MACRO calc_sine_wave
|
||||
; input: a = a signed 6-bit value
|
||||
; output: a = d * sin(a * pi/32)
|
||||
and %111111
|
||||
cp %100000
|
||||
jr nc, .negative\@
|
||||
call .apply\@
|
||||
ld a, h
|
||||
ret
|
||||
.negative\@
|
||||
and %011111
|
||||
call .apply\@
|
||||
ld a, h
|
||||
xor $ff
|
||||
inc a
|
||||
ret
|
||||
.apply\@
|
||||
ld e, a
|
||||
ld a, d
|
||||
ld d, 0
|
||||
if _NARG == 1
|
||||
ld hl, \1
|
||||
else
|
||||
ld hl, .sinetable\@
|
||||
endc
|
||||
add hl, de
|
||||
add hl, de
|
||||
ld e, [hl]
|
||||
inc hl
|
||||
ld d, [hl]
|
||||
ld hl, 0
|
||||
.multiply\@ ; factor amplitude
|
||||
srl a
|
||||
jr nc, .even\@
|
||||
add hl, de
|
||||
.even\@
|
||||
sla e
|
||||
rl d
|
||||
and a
|
||||
jr nz, .multiply\@
|
||||
ret
|
||||
if _NARG == 0
|
||||
.sinetable\@
|
||||
sine_table 32
|
||||
endc
|
||||
ENDM
|
||||
```
|
||||
|
||||
And on `sine_table` in [macros/data.asm](https://github.com/pret/pokecrystal/blob/master/macros/data.asm):
|
||||
|
||||
```asm
|
||||
MACRO sine_table
|
||||
; \1 samples of sin(x) from x=0 to x<0.5 turns (pi radians)
|
||||
for x, \1
|
||||
dw sin(x * 0.5 / (\1))
|
||||
endr
|
||||
ENDM
|
||||
```
|
||||
|
||||
**Fix:** Edit [home/sine.asm](https://github.com/pret/pokecrystal/blob/master/home/sine.asm) to contain a single copy of the (co)sine code in bank 0, and call it from those five sites.
|
||||
|
||||
|
||||
## `GetForestTreeFrame` works, but it's still bad
|
||||
|
||||
The routine `GetForestTreeFrame` in [engine/tilesets/tileset_anims.asm](https://github.com/pret/pokecrystal/blob/master/engine/tilesets/tileset_anims.asm) is hilariously inefficient.
|
||||
|
||||
**Fix:**
|
||||
|
||||
Edit `GetForestTreeFrame`:
|
||||
|
||||
```diff
|
||||
GetForestTreeFrame:
|
||||
; Return 0 if a is even, or 2 if odd.
|
||||
- and a
|
||||
- jr z, .even
|
||||
- cp 1
|
||||
- jr z, .odd
|
||||
- cp 2
|
||||
- jr z, .even
|
||||
- cp 3
|
||||
- jr z, .odd
|
||||
- cp 4
|
||||
- jr z, .even
|
||||
- cp 5
|
||||
- jr z, .odd
|
||||
- cp 6
|
||||
- jr z, .even
|
||||
-.odd
|
||||
- ld a, 2
|
||||
- scf
|
||||
- ret
|
||||
-.even
|
||||
- xor a
|
||||
+ and 1
|
||||
+ add a
|
||||
ret
|
||||
```
|
||||
|
||||
|
||||
## The overworld scripting engine assumes no more than 127 banks
|
||||
|
||||
The `CallCallback` and `ExitScriptSubroutine` functions in [engine/overworld/scripting.asm](https://github.com/pret/pokecrystal/blob/master/engine/overworld/scripting.asm) use the highest bit of the bank value, to store whether a certain script stack position should be treated as a return from a callback. However, it seems it was opted to explicitly use the `endcallback` command for this purpose, instead.
|
||||
|
||||
As such, this bit serves no purpose but to make map scripts living in the higher banks of mappers such as Japanese Crystal's MBC30 crash for weird reasons.
|
||||
|
||||
**Fix:**
|
||||
|
||||
Remove the bit mask for the bank value in `ExitScriptSubroutine`:
|
||||
|
||||
```diff
|
||||
ExitScriptSubroutine:
|
||||
...
|
||||
add hl, de
|
||||
ld a, [hli]
|
||||
ld b, a
|
||||
- and $7f
|
||||
ld [wScriptBank], a
|
||||
ld a, [hli]
|
||||
ld e, a
|
||||
```
|
||||
|
||||
And in `CallCallback`:
|
||||
|
||||
```diff
|
||||
CallCallback::
|
||||
- ld a, [wScriptBank]
|
||||
- or $80
|
||||
- ld [wScriptBank], a
|
||||
jp ScriptCall
|
||||
```
|
||||
563
docs/event_commands.md
Normal file
563
docs/event_commands.md
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
# Event Commands
|
||||
|
||||
Defined in [macros/scripts/events.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/events.asm) and [engine/overworld/scripting.asm:ScriptCommandTable](https://github.com/pret/pokecrystal/blob/master/engine/overworld/scripting.asm).
|
||||
|
||||
Until this document is filled out, the [G/S Scripting Compendium](https://hax.iimarckus.org/files/scriptingcodes_eng.htm) has descriptions for most of these commands. It was written for G/S binary hacking and not Crystal assembly hacking, so it's not 100% accurate for pokecrystal.
|
||||
|
||||
|
||||
## `$00`: <code>scall <i>script</i></code>
|
||||
|
||||
|
||||
## `$01`: <code>farscall <i>script</i></code>
|
||||
|
||||
|
||||
## `$02`: <code>memcall <i>script</i></code>
|
||||
|
||||
|
||||
## `$03`: <code>sjump <i>script</i></code>
|
||||
|
||||
|
||||
## `$04`: <code>farsjump <i>script</i></code>
|
||||
|
||||
|
||||
## `$05`: <code>memjump <i>script</i></code>
|
||||
|
||||
|
||||
## `$06`: <code>ifequal <i>byte</i>, <i>script</i></code>
|
||||
|
||||
|
||||
## `$07`: <code>ifnotequal <i>byte</i>, <i>script</i></code>
|
||||
|
||||
|
||||
## `$08`: <code>iffalse <i>script</i></code>
|
||||
|
||||
|
||||
## `$09`: <code>iftrue <i>script</i></code>
|
||||
|
||||
|
||||
## `$0A`: <code>ifgreater <i>byte</i>, <i>script</i></code>
|
||||
|
||||
|
||||
## `$0B`: <code>ifless <i>byte</i>, <i>script</i></code>
|
||||
|
||||
|
||||
## `$0C`: <code>jumpstd <i>std_script</i></code>
|
||||
|
||||
|
||||
## `$0D`: <code>callstd <i>std_script</i></code>
|
||||
|
||||
|
||||
## `$0E`: <code>callasm <i>asm</i></code>
|
||||
|
||||
|
||||
## `$0F`: <code>special <i>special_pointer</i></code>
|
||||
|
||||
|
||||
## `$10`: <code>memcallasm <i>asm</i></code>
|
||||
|
||||
|
||||
## `$11`: <code>checkmapscene <i>map</i></code>
|
||||
|
||||
|
||||
## `$12`: <code>setmapscene <i>map</i>, <i>scene_id</i></code>
|
||||
|
||||
|
||||
## `$13`: `checkscene`
|
||||
|
||||
|
||||
## `$14`: <code>setscene <i>scene_id</i></code>
|
||||
|
||||
|
||||
## `$15`: <code>setval <i>value</i></code>
|
||||
|
||||
<code>[wScriptVar] = <i>value</i></code>
|
||||
|
||||
|
||||
## `$16`: <code>addval <i>value</i></code>
|
||||
|
||||
<code>[wScriptVar] += <i>value</i></code>
|
||||
|
||||
|
||||
## `$17`: <code>random <i>value</i></code>
|
||||
|
||||
|
||||
## `$18`: `checkver`
|
||||
|
||||
|
||||
## `$19`: <code>readmem <i>address</i></code>
|
||||
|
||||
<code>[wScriptVar] = [<i>address</i>]</code>
|
||||
|
||||
|
||||
## `$1A`: <code>writemem <i>address</i></code>
|
||||
|
||||
<code>[<i>address</i>] = [wScriptVar]</code>
|
||||
|
||||
|
||||
## `$1B`: <code>loadmem <i>address</i>, <i>value</i></code>
|
||||
|
||||
<code>[<i>address</i>] = <i>value</i></code>
|
||||
|
||||
|
||||
## `$1C`: <code>readvar <i>variable</i></code>
|
||||
|
||||
<code>[wScriptVar] = GetVarAction(<i>variable</i>)</code>
|
||||
|
||||
|
||||
## `$1D`: <code>writevar <i>variable</i></code>
|
||||
|
||||
<code>GetVarAction(<i>variable</i>) = [wScriptVar]</code>
|
||||
|
||||
|
||||
## `$1E`: <code>loadvar <i>variable</i>, <i>value</i></code>
|
||||
|
||||
<code>GetVarAction(<i>variable</i>) = <i>value</i></code>
|
||||
|
||||
|
||||
## `$1F`: <code>giveitem <i>item_id</i>[, <i>quantity</i>=1]</code>
|
||||
|
||||
|
||||
## `$20`: <code>takeitem <i>item_id</i>[, <i>quantity</i>=1]</code>
|
||||
|
||||
|
||||
## `$21`: <code>checkitem <i>item_id</i></code>
|
||||
|
||||
|
||||
## `$22`: <code>givemoney <i>account</i>, <i>value</i></code>
|
||||
|
||||
|
||||
## `$23`: <code>takemoney <i>account</i>, <i>value</i></code>
|
||||
|
||||
|
||||
## `$24`: <code>checkmoney <i>account</i>, <i>value</i></code>
|
||||
|
||||
|
||||
## `$25`: <code>givecoins <i>value</i></code>
|
||||
|
||||
|
||||
## `$26`: <code>takecoins <i>value</i></code>
|
||||
|
||||
|
||||
## `$27`: <code>checkcoins <i>value</i></code>
|
||||
|
||||
|
||||
## `$28`: <code>addcellnum <i>contact_id</i></code>
|
||||
|
||||
|
||||
## `$29`: <code>delcellnum <i>contact_id</i></code>
|
||||
|
||||
|
||||
## `$2A`: <code>checkcellnum <i>contact_id</i></code>
|
||||
|
||||
|
||||
## `$2B`: <code>checktime <i>time</i></code>
|
||||
|
||||
|
||||
## `$2C`: <code>checkpoke <i>mon_id</i></code>
|
||||
|
||||
|
||||
## `$2D`: <code>givepoke <i>mon_id</i>, <i>level</i>[, <i>item</i>=0[, <i>ot_name</i>, <i>nickname</i>]]</code>
|
||||
|
||||
|
||||
## `$2E`: <code>giveegg <i>mon_id</i>, <i>level</i></code>
|
||||
|
||||
|
||||
## `$2F`: <code>givepokemail <i>pointer</i></code>
|
||||
|
||||
|
||||
## `$30`: <code>checkpokemail <i>pointer</i></code>
|
||||
|
||||
|
||||
## `$31`: <code>checkevent <i>event_flag</i></code>
|
||||
|
||||
|
||||
## `$32`: <code>clearevent <i>event_flag</i></code>
|
||||
|
||||
|
||||
## `$33`: <code>setevent <i>event_flag</i></code>
|
||||
|
||||
|
||||
## `$34`: <code>checkflag <i>engine_flag</i></code>
|
||||
|
||||
|
||||
## `$35`: <code>clearflag <i>engine_flag</i></code>
|
||||
|
||||
|
||||
## `$36`: <code>setflag <i>engine_flag</i></code>
|
||||
|
||||
|
||||
## `$37`: `wildon`
|
||||
|
||||
|
||||
## `$38`: `wildoff`
|
||||
|
||||
|
||||
## `$39`: <code>xycompare <i>pointer</i></code>
|
||||
|
||||
|
||||
## `$3A`: <code>warpmod <i>warp_id</i>, <i>map</i></code>
|
||||
|
||||
|
||||
## `$3B`: <code>blackoutmod <i>map</i></code>
|
||||
|
||||
|
||||
## `$3C`: <code>warp <i>map</i>, <i>x</i>, <i>y</i></code>
|
||||
|
||||
|
||||
## `$3D`: <code>getmoney <i>string_buffer</i>, <i>account</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = PrintNum(GetMoneyAccount(<i>account</i>))</code>
|
||||
|
||||
|
||||
## `$3E`: <code>getcoins <i>string_buffer</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = PrintNum([wCoins])</code>
|
||||
|
||||
|
||||
## `$3F`: <code>getnum <i>string_buffer</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = PrintNum([wScriptVar])</code>
|
||||
|
||||
|
||||
## `$40`: <code>getmonname <i>string_buffer</i>, <i>mon_id</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetPokemonName(<i>mon_id</i>)</code>
|
||||
|
||||
If <code><i>mon_id</i></code> = `USE_SCRIPT_VAR`, then it uses `[wScriptVar]` instead.
|
||||
|
||||
|
||||
## `$41`: <code>getitemname <i>string_buffer</i>, <i>item_id</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetItemName(<i>item_id</i>)</code>
|
||||
|
||||
If <code><i>item_id</i></code> = `USE_SCRIPT_VAR`, then it uses `[wScriptVar]` instead.
|
||||
|
||||
|
||||
## `$42`: <code>getcurlandmarkname <i>string_buffer</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetLandmarkName(GetWorldMapLocation())</code>
|
||||
|
||||
|
||||
## `$43`: <code>gettrainername <i>string_buffer</i>, <i>trainer_group</i>, <i>trainer_id</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetTrainerName(<i>trainer_group</i>, <i>trainer_id</i>)</code>
|
||||
|
||||
|
||||
## `$44`: <code>getstring <i>string_buffer</i>, <i>text_pointer</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = CopyName1([wScriptBank], <i>text_pointer</i>)</code>
|
||||
|
||||
|
||||
## `$45`: `itemnotify`
|
||||
|
||||
|
||||
## `$46`: `pocketisfull`
|
||||
|
||||
|
||||
## `$47`: `opentext`
|
||||
|
||||
|
||||
## `$48`: <code>refreshscreen [<i>dummy</i>=0]</code>
|
||||
|
||||
|
||||
## `$49`: `closetext`
|
||||
|
||||
|
||||
## `$4A`: <code>writeunusedbyte <i>byte</i></code>
|
||||
|
||||
<code>[<i>wUnusedScriptByte</i>] = <i>byte</i></code>
|
||||
|
||||
|
||||
## `$4B`: <code>farwritetext <i>text_pointer</i></code>
|
||||
|
||||
|
||||
## `$4C`: <code>writetext <i>text_pointer</i></code>
|
||||
|
||||
|
||||
## `$4D`: <code>repeattext <i>byte1</i>, <i>byte2</i></code>
|
||||
|
||||
|
||||
## `$4E`: `yesorno`
|
||||
|
||||
|
||||
## `$4F`: <code>loadmenu <i>menu_header</i></code>
|
||||
|
||||
|
||||
## `$50`: `closewindow`
|
||||
|
||||
|
||||
## `$51`: <code>jumptextfaceplayer <i>text_pointer</i></code>
|
||||
|
||||
|
||||
## `$52`: <code>farjumptext <i>text_pointer</i></code>
|
||||
|
||||
|
||||
## `$53`: <code>jumptext <i>text_pointer</i></code>
|
||||
|
||||
|
||||
## `$54`: `waitbutton`
|
||||
|
||||
|
||||
## `$55`: `promptbutton`
|
||||
|
||||
|
||||
## `$56`: <code>pokepic <i>mon_id</i></code>
|
||||
|
||||
|
||||
## `$57`: `closepokepic`
|
||||
|
||||
|
||||
## `$58`: `_2dmenu`
|
||||
|
||||
|
||||
## `$59`: `verticalmenu`
|
||||
|
||||
|
||||
## `$5A`: `loadpikachudata`
|
||||
|
||||
|
||||
## `$5B`: `randomwildmon`
|
||||
|
||||
|
||||
## `$5C`: `loadtemptrainer`
|
||||
|
||||
`[wOtherTrainer] = [wTempTrainer]`
|
||||
|
||||
|
||||
## `$5D`: <code>loadwildmon <i>mon_id</i>, <i>level</i></code>
|
||||
|
||||
|
||||
## `$5E`: <code>loadtrainer <i>trainer_group</i>, <i>trainer_id</i></code>
|
||||
|
||||
|
||||
## `$5F`: `startbattle`
|
||||
|
||||
|
||||
## `$60`: `reloadmapafterbattle`
|
||||
|
||||
|
||||
## `$61`: <code>catchtutorial <i>byte</i></code>
|
||||
|
||||
|
||||
## `$62`: <code>trainertext <i>text_id</i></code>
|
||||
|
||||
|
||||
## `$63`: <code>trainerflagaction <i>action</i></code>
|
||||
|
||||
|
||||
## `$64`: <code>winlosstext <i>win_text_pointer</i>, <i>loss_text_pointer</i></code>
|
||||
|
||||
|
||||
## `$65`: `scripttalkafter`
|
||||
|
||||
|
||||
## `$66`: `endifjustbattled`
|
||||
|
||||
|
||||
## `$67`: `checkjustbattled`
|
||||
|
||||
|
||||
## `$68`: <code>setlasttalked <i>object_id</i></code>
|
||||
|
||||
|
||||
## `$69`: <code>applymovement <i>object_id</i>, <i>data_pointer</i></code>
|
||||
|
||||
|
||||
## `$6A`: <code>applymovementlasttalked <i>data_pointer</i></code>
|
||||
|
||||
|
||||
## `$6B`: `faceplayer`
|
||||
|
||||
|
||||
## `$6C`: <code>faceobject <i>object1</i>, <i>object2</i></code>
|
||||
|
||||
|
||||
## `$6D`: <code>variablesprite <i>variable_sprite_id</i>, <i>sprite_id</i></code>
|
||||
|
||||
|
||||
## `$6E`: <code>disappear <i>object_id</i></code>
|
||||
|
||||
|
||||
## `$6F`: <code>appear <i>object_id</i></code>
|
||||
|
||||
|
||||
## `$70`: <code>follow <i>object2</i>, <i>object1</i></code>
|
||||
|
||||
|
||||
## `$71`: `stopfollow`
|
||||
|
||||
|
||||
## `$72`: <code>moveobject <i>object_id</i>, <i>x</i>, <i>y</i></code>
|
||||
|
||||
|
||||
## `$73`: <code>writeobjectxy <i>object_id</i></code>
|
||||
|
||||
|
||||
## `$74`: <code>loademote <i>emote_id</i></code>
|
||||
|
||||
|
||||
## `$75`: <code>showemote <i>emote_id</i>, <i>object_id</i>, <i>length</i></code>
|
||||
|
||||
|
||||
## `$76`: <code>turnobject <i>object_id</i>, <i>facing</i></code>
|
||||
|
||||
|
||||
## `$77`: <code>follownotexact <i>object2</i>, <i>object1</i></code>
|
||||
|
||||
|
||||
## `$78`: <code>earthquake <i>param</i></code>
|
||||
|
||||
|
||||
## `$79`: <code>changemapblocks <i>blockdata_pointer</i></code>
|
||||
|
||||
<code>ChangeMap(<i>blockdata_pointer</i>)</code>
|
||||
|
||||
|
||||
## `$7A`: <code>changeblock <i>x</i>, <i>y</i>, <i>block</i></code>
|
||||
|
||||
|
||||
## `$7B`: `reloadmap`
|
||||
|
||||
|
||||
## `$7C`: `reloadmappart`
|
||||
|
||||
|
||||
## `$7D`: <code>writecmdqueue <i>queue_pointer</i></code>
|
||||
|
||||
|
||||
## `$7E`: <code>delcmdqueue <i>byte</i></code>
|
||||
|
||||
|
||||
## `$7F`: <code>playmusic <i>music_id</i></code>
|
||||
|
||||
|
||||
## `$80`: `encountermusic`
|
||||
|
||||
|
||||
## `$81`: <code>musicfadeout <i>music_id</i>, <i>length</i></code>
|
||||
|
||||
|
||||
## `$82`: `playmapmusic`
|
||||
|
||||
|
||||
## `$83`: `dontrestartmapmusic`
|
||||
|
||||
|
||||
## `$84`: <code>cry <i>mon_id</i></code>
|
||||
|
||||
|
||||
## `$85`: <code>playsound <i>sfx_id</i></code>
|
||||
|
||||
|
||||
## `$86`: `waitsfx`
|
||||
|
||||
|
||||
## `$87`: `warpsound`
|
||||
|
||||
|
||||
## `$88`: `specialsound`
|
||||
|
||||
|
||||
## `$89`: <code>autoinput <i>input_pointer</i></code>
|
||||
|
||||
|
||||
## `$8A`: <code>newloadmap <i>which_method</i></code>
|
||||
|
||||
|
||||
## `$8B`: <code>pause <i>length</i></code>
|
||||
|
||||
|
||||
## `$8C`: <code>deactivatefacing <i>length</i></code>
|
||||
|
||||
|
||||
## `$8D`: <code>sdefer <i>script</i></code>
|
||||
|
||||
|
||||
## `$8E`: `warpcheck`
|
||||
|
||||
|
||||
## `$8F`: <code>stopandsjump <i>script</i></code>
|
||||
|
||||
|
||||
## `$90`: `endcallback`
|
||||
|
||||
|
||||
## `$91`: `end`
|
||||
|
||||
|
||||
## `$92`: <code>reloadend <i>which_method</i></code>
|
||||
|
||||
|
||||
## `$93`: `endall`
|
||||
|
||||
|
||||
## `$94`: <code>pokemart <i>mart_type</i>, <i>mart_id</i></code>
|
||||
|
||||
|
||||
## `$95`: <code>elevator <i>floor_list</i></code>
|
||||
|
||||
|
||||
## `$96`: <code>trade <i>trade_id</i></code>
|
||||
|
||||
|
||||
## `$97`: <code>askforphonenumber <i>contact_id</i></code>
|
||||
|
||||
|
||||
## `$98`: <code>phonecall <i>call_id</i></code>
|
||||
|
||||
|
||||
## `$99`: `hangup`
|
||||
|
||||
|
||||
## `$9A`: <code>describedecoration <i>byte</i></code>
|
||||
|
||||
|
||||
## `$9B`: <code>fruittree <i>tree_id</i></code>
|
||||
|
||||
|
||||
## `$9C`: <code>specialphonecall <i>call_id</i></code>
|
||||
|
||||
|
||||
## `$9D`: `checkphonecall`
|
||||
|
||||
|
||||
## `$9E`: <code>verbosegiveitem <i>item_id</i>[, <i>quantity</i>=1]</code>
|
||||
|
||||
|
||||
## `$9F`: <code>verbosegiveitemvar <i>item_id</i>, <i>variable</i></code>
|
||||
|
||||
|
||||
## `$A0`: <code>swarm <i>swarm_id</i>, <i>map</i></code>
|
||||
|
||||
|
||||
## `$A1`: `halloffame`
|
||||
|
||||
|
||||
## `$A2`: `credits`
|
||||
|
||||
|
||||
## `$A3`: <code>warpfacing <i>facing</i>, <i>map</i>, <i>x</i>, <i>y</i></code>
|
||||
|
||||
|
||||
## `$A4`: <code>battletowertext <i>bttext_id</i></code>
|
||||
|
||||
|
||||
## `$A5`: <code>getlandmarkname <i>string_buffer</i>, <i>landmark_id</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetLandmarkName(<i>landmark_id</i>)</code>
|
||||
|
||||
|
||||
## `$A6`: <code>gettrainerclassname <i>string_buffer</i>, <i>trainer_group</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetName(TRAINER_NAME, <i>trainer_group</i>)</code>
|
||||
|
||||
|
||||
## `$A7`: <code>getname <i>string_buffer</i>, <i>type</i>, <i>id</i></code>
|
||||
|
||||
<code>GetStringBuffer(<i>string_buffer</i>) = GetName(<i>type</i>, <i>id</i>)</code>
|
||||
|
||||
|
||||
## `$A8`: <code>wait <i>duration</i></code>
|
||||
|
||||
|
||||
## `$A9`: `checksave`
|
||||
BIN
docs/images/hp_exp_bar_border.png
Normal file
BIN
docs/images/hp_exp_bar_border.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 166 B |
BIN
docs/images/port.png
Normal file
BIN
docs/images/port.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
docs/images/ruins_of_alph_outside.png
Normal file
BIN
docs/images/ruins_of_alph_outside.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 494 B |
BIN
docs/images/ruins_of_alph_outside_cinnabar.png
Normal file
BIN
docs/images/ruins_of_alph_outside_cinnabar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 485 B |
30
docs/index.md
Normal file
30
docs/index.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
These pages are for documenting pieces of the [pokecrystal](https://github.com/pret/pokecrystal) disassembly project. For more information, please see its [README.md](https://github.com/pret/pokecrystal/blob/master/README.md) and [wiki](https://github.com/pret/pokecrystal/wiki).
|
||||
|
||||
|
||||
## Issues with the source code
|
||||
|
||||
- [bugs_and_glitches.md](bugs_and_glitches.md)
|
||||
- [design_flaws.md](design_flaws.md)
|
||||
|
||||
|
||||
## Map event scripts
|
||||
|
||||
- [map_event_scripts.md](map_event_scripts.md)
|
||||
- [event_commands.md](event_commands.md)
|
||||
- [movement_commands.md](movement_commands.md)
|
||||
- [text_commands.md](text_commands.md)
|
||||
- [map_setup_scripts.md](map_setup_scripts.md)
|
||||
|
||||
|
||||
## Other types of scripts
|
||||
|
||||
- [battle_anim_commands.md](battle_anim_commands.md)
|
||||
- [move_effect_commands.md](move_effect_commands.md)
|
||||
- [music_commands.md](music_commands.md)
|
||||
- [vc_patch.md](vc_patch.md)
|
||||
|
||||
|
||||
## Other subsystems
|
||||
|
||||
- [pic_animations.md](pic_animations.md)
|
||||
- [menus.md](menus.md)
|
||||
236
docs/map_event_scripts.md
Normal file
236
docs/map_event_scripts.md
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
# Map Event Scripts
|
||||
|
||||
|
||||
## Contents
|
||||
|
||||
- [Object constants](#object-constants)
|
||||
- [Map scripts](#map-scripts)
|
||||
- [Scene scripts](#scene-scripts)
|
||||
- [Callbacks](#callbacks)
|
||||
- [Callback types](#callback-types)
|
||||
- [Event scripts](#event-scripts)
|
||||
- [Text](#text)
|
||||
- [Movement data](#movement-data)
|
||||
- [Map events](#map-events)
|
||||
- [Warp events](#warp-events)
|
||||
- [Coord events](#coord-events)
|
||||
- [BG events](#bg-events)
|
||||
- [BG event types](#bg-event-types)
|
||||
- [Object events](#object-events)
|
||||
- [Movement types](#movement-types)
|
||||
- [Object types](#object-types)
|
||||
- [Template](#template)
|
||||
|
||||
|
||||
## Object constants
|
||||
|
||||
<pre>
|
||||
object_const_def
|
||||
const <i>MAPNAME</i>_<i>OBJECTNAME</i>
|
||||
</pre>
|
||||
|
||||
|
||||
## Map scripts
|
||||
|
||||
<pre>
|
||||
<i>MapName</i>_MapScripts:
|
||||
</pre>
|
||||
|
||||
|
||||
### Scene scripts
|
||||
|
||||
<pre>
|
||||
def_scene_scripts
|
||||
scene_script <i>script</i>, SCENE_<i>MAPNAME</i>_<i>SCENE_NAME</i>
|
||||
</pre>
|
||||
|
||||
|
||||
### Callbacks
|
||||
|
||||
<pre>
|
||||
def_callbacks
|
||||
callback <i>type</i>, <i>script</i>
|
||||
</pre>
|
||||
|
||||
#### Callback types
|
||||
|
||||
- `MAPCALLBACK_NEWMAP`
|
||||
|
||||
- `MAPCALLBACK_TILES`
|
||||
|
||||
- `MAPCALLBACK_OBJECTS`
|
||||
|
||||
- `MAPCALLBACK_SPRITES`
|
||||
|
||||
- `MAPCALLBACK_CMDQUEUE`
|
||||
|
||||
<pre>
|
||||
callback MAPCALLBACK_CMDQUEUE, <i>MapName</i>BouldersCallback
|
||||
|
||||
<i>MapName</i>BouldersCallback:
|
||||
writecmdqueue .BoulderCmdQueue
|
||||
endcallback
|
||||
|
||||
.BoulderCmdQueue:
|
||||
cmdqueue CMDQUEUE_STONETABLE, .BoulderTable
|
||||
|
||||
.BoulderTable:
|
||||
stonetable <i>warp_id</i>, <i>person</i>, <i>script</i>
|
||||
db -1 ; end
|
||||
</pre>
|
||||
|
||||
|
||||
## Event scripts
|
||||
|
||||
[Event commands](event_commands.md)
|
||||
|
||||
|
||||
## Text
|
||||
|
||||
[Text commands](text_commands.md)
|
||||
|
||||
|
||||
## Movement data
|
||||
|
||||
[Movement commands](movement_commands.md)
|
||||
|
||||
|
||||
## Map events
|
||||
|
||||
<pre>
|
||||
<i>MapName</i>_MapEvents:
|
||||
db 0, 0 ; filler
|
||||
</pre>
|
||||
|
||||
|
||||
### Warp events
|
||||
|
||||
<pre>
|
||||
def_warp_events
|
||||
warp_event <i>x</i>, <i>y</i>, <i>map</i>, <i>warp_id</i>
|
||||
</pre>
|
||||
|
||||
|
||||
### Coord events
|
||||
|
||||
<pre>
|
||||
def_coord_events
|
||||
coord_event <i>x</i>, <i>y</i>, <i>scene_id</i>, <i>script</i>
|
||||
</pre>
|
||||
|
||||
|
||||
### BG events
|
||||
|
||||
<pre>
|
||||
def_bg_events
|
||||
bg_event <i>x</i>, <i>y</i>, <i>type</i>, <i>script</i>
|
||||
</pre>
|
||||
|
||||
#### BG event types
|
||||
|
||||
- `BGEVENT_READ`
|
||||
|
||||
- `BGEVENT_UP/DOWN/LEFT/RIGHT`
|
||||
|
||||
- `BGEVENT_IFSET/IFNOTSET`
|
||||
|
||||
<pre>
|
||||
conditional_event <i>event_flag</i>, <i>script</i>
|
||||
</pre>
|
||||
|
||||
- `BGEVENT_ITEM`
|
||||
|
||||
<pre>
|
||||
hiddenitem <i>item_id</i>, <i>event_flag</i>
|
||||
</pre>
|
||||
|
||||
- `BGEVENT_COPY`
|
||||
|
||||
### Object events
|
||||
|
||||
<pre>
|
||||
def_object_events
|
||||
object_event <i>x</i>, <i>y</i>, <i>sprite</i>, <i>movement</i>, <i>rx</i>, <i>ry</i>, <i>h1</i>, <i>h2</i>, <i>palette</i>, <i>type</i>, <i>range</i>, <i>script</i>, <i>event_flag</i>
|
||||
</pre>
|
||||
|
||||
#### Movement types
|
||||
|
||||
- `SPRITEMOVEDATA_STILL`
|
||||
|
||||
- `SPRITEMOVEDATA_WANDER`
|
||||
|
||||
- `SPRITEMOVEDATA_SPINRANDOM_SLOW`
|
||||
|
||||
- `SPRITEMOVEDATA_WALK_UP_DOWN`
|
||||
|
||||
- `SPRITEMOVEDATA_WALK_LEFT_RIGHT`
|
||||
|
||||
- `SPRITEMOVEDATA_STANDING_UP/DOWN/LEFT/RIGHT`
|
||||
|
||||
- `SPRITEMOVEDATA_SPINRANDOM_FAST`
|
||||
|
||||
- `SPRITEMOVEDATA_BIGDOLLSYM`
|
||||
|
||||
- `SPRITEMOVEDATA_POKEMON`
|
||||
|
||||
- `SPRITEMOVEDATA_SUDOWOODO`
|
||||
|
||||
- `SPRITEMOVEDATA_SMASHABLE_ROCK`
|
||||
|
||||
- `SPRITEMOVEDATA_STRENGTH_BOULDER`
|
||||
|
||||
- `SPRITEMOVEDATA_SPINCOUNTERCLOCKWISE`
|
||||
|
||||
- `SPRITEMOVEDATA_SPINCLOCKWISE`
|
||||
|
||||
- `SPRITEMOVEDATA_BIGDOLLASYM`
|
||||
|
||||
- `SPRITEMOVEDATA_BIGDOLL`
|
||||
|
||||
- `SPRITEMOVEDATA_SWIM_WANDER`
|
||||
|
||||
#### Object types
|
||||
|
||||
- `OBJECTTYPE_SCRIPT`
|
||||
|
||||
- `OBJECTTYPE_ITEMBALL`
|
||||
|
||||
<pre>
|
||||
itemball <i>item_id</i>[, <i>quantity</i>=1]
|
||||
</pre>
|
||||
|
||||
- `OBJECTTYPE_TRAINER`
|
||||
|
||||
<pre>
|
||||
trainer <i>group_id</i>, <i>trainer_id</i>, <i>event_flag</i>, <i>seen_text</i>, <i>beaten_text</i>, <i>loss_text</i>, <i>script</i>
|
||||
</pre>
|
||||
|
||||
|
||||
## Template
|
||||
|
||||
<pre>
|
||||
object_const_def
|
||||
; const <i>MAPNAME</i>_<i>OBJECTNAME</i>
|
||||
|
||||
<i>MapName</i>_MapScripts:
|
||||
def_scene_scripts
|
||||
; scene_script <i>script</i>, SCENE_<i>MAPNAME</i>_<i>SCENE_NAME</i>
|
||||
|
||||
def_callbacks
|
||||
; callback <i>type</i>, <i>script</i>
|
||||
|
||||
<i>MapName</i>_MapEvents:
|
||||
db 0, 0 ; filler
|
||||
|
||||
def_warp_events
|
||||
; warp_event <i>x</i>, <i>y</i>, <i>map</i>, <i>warp_id</i>
|
||||
|
||||
def_coord_events
|
||||
; coord_event <i>x</i>, <i>y</i>, <i>scene_id</i>, <i>script</i>
|
||||
|
||||
def_bg_events
|
||||
; bg_event <i>x</i>, <i>y</i>, <i>type</i>, <i>script</i>
|
||||
|
||||
def_object_events
|
||||
; object_event <i>x</i>, <i>y</i>, <i>sprite</i>, <i>movement</i>, <i>rx</i>, <i>ry</i>, <i>h1</i>, <i>h2</i>, <i>palette</i>, <i>type</i>, <i>range</i>, <i>script</i>, <i>event_flag</i>
|
||||
</pre>
|
||||
144
docs/map_setup_scripts.md
Normal file
144
docs/map_setup_scripts.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# Map Setup Commands
|
||||
|
||||
Defined in [macros/scripts/map_setup.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/map_setup.asm) and [data/maps/setup_script_pointers.asm:MapSetupCommands](https://github.com/pret/pokecrystal/blob/master/data/maps/setup_script_pointers.asm).
|
||||
|
||||
|
||||
## `$00`: `map_enable_lcd`
|
||||
|
||||
|
||||
## `$01`: `map_disable_lcd`
|
||||
|
||||
|
||||
## `$02`: `map_init_sound`
|
||||
|
||||
|
||||
## `$03`: `map_play_music`
|
||||
|
||||
|
||||
## `$04`: `map_restart_music`
|
||||
|
||||
|
||||
## `$05`: `map_fade_to_music`
|
||||
|
||||
|
||||
## `$06`: `map_fade_music_and_palettes`
|
||||
|
||||
|
||||
## `$07`: `map_play_music_bike`
|
||||
|
||||
|
||||
## `$08`: `map_force_music`
|
||||
|
||||
|
||||
## `$09`: `map_fade_in_to_music`
|
||||
|
||||
|
||||
## `$0A`: `map_load_block_data`
|
||||
|
||||
|
||||
## `$0B`: `map_load_connection_block_data`
|
||||
|
||||
|
||||
## `$0C`: `map_save_screen`
|
||||
|
||||
|
||||
## `$0D`: `map_buffer_screen`
|
||||
|
||||
|
||||
## `$0E`: `map_load_graphics`
|
||||
|
||||
|
||||
## `$0F`: `map_load_tileset`
|
||||
|
||||
|
||||
## `$10`: `map_load_time_of_day`
|
||||
|
||||
|
||||
## `$11`: `map_load_palettes`
|
||||
|
||||
|
||||
## `$12`: `map_load_wild_mon_data`
|
||||
|
||||
|
||||
## `$13`: `map_refresh_sprites`
|
||||
|
||||
|
||||
## `$14`: `map_handle_new`
|
||||
|
||||
|
||||
## `$15`: `map_handle_continue`
|
||||
|
||||
|
||||
## `$16`: `map_load_objects`
|
||||
|
||||
|
||||
## `$17`: `map_enter_spawn_point`
|
||||
|
||||
|
||||
## `$18`: `map_enter_connection`
|
||||
|
||||
|
||||
## `$19`: `map_enter_warp`
|
||||
|
||||
|
||||
## `$1A`: `map_load_attributes`
|
||||
|
||||
|
||||
## `$1B`: `map_load_attributes_no_objects`
|
||||
|
||||
|
||||
## `$1C`: `map_clear_bg_palettes`
|
||||
|
||||
|
||||
## `$1D`: `map_fade_out_palettes`
|
||||
|
||||
|
||||
## `$1E`: `map_fade_in_palettes`
|
||||
|
||||
|
||||
## `$1F`: `map_get_screen_coords`
|
||||
|
||||
|
||||
## `$20`: `map_get_warp_dest_coords`
|
||||
|
||||
|
||||
## `$21`: `map_spawn_in_facing_down`
|
||||
|
||||
|
||||
## `$22`: `map_spawn_player`
|
||||
|
||||
|
||||
## `$23`: `map_refresh_player_coords`
|
||||
|
||||
|
||||
## `$24`: `map_reset_player_object_action`
|
||||
|
||||
|
||||
## `$25`: `map_skip_update_sprites`
|
||||
|
||||
|
||||
## `$26`: `map_update_roam_mons`
|
||||
|
||||
|
||||
## `$27`: `map_jump_roam_mons`
|
||||
|
||||
|
||||
## `$28`: `map_fade_out_music`
|
||||
|
||||
|
||||
## `$29`: `map_activate_anims`
|
||||
|
||||
|
||||
## `$2A`: `map_suspend_anims`
|
||||
|
||||
|
||||
## `$2B`: `map_apply_palettes`
|
||||
|
||||
|
||||
## `$2C`: `map_enable_text_acceleration`
|
||||
|
||||
|
||||
## `$2D`: `map_init_name_sign`
|
||||
|
||||
|
||||
## `$FF`: `map_end`
|
||||
297
docs/menus.md
Normal file
297
docs/menus.md
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
# Menu Data
|
||||
|
||||
|
||||
## Contents
|
||||
|
||||
- [ScrollingMenu](#scrollingmenu)
|
||||
- [\_2DMenu](#_2dmenu)
|
||||
- [DoNthMenu/SetUpMenu](#donthmenusetupmenu)
|
||||
- [VerticalMenu](#verticalmenu)
|
||||
- [Misc/Generic](#miscgeneric)
|
||||
|
||||
|
||||
## `ScrollingMenu`
|
||||
|
||||
This is the only menu that does scrolling. It doesn't draw any `Textbox` around the menu.
|
||||
|
||||
Structure:
|
||||
|
||||
```asm
|
||||
.MenuHeader:
|
||||
db MENU_BACKUP_TILES ; flags
|
||||
menu_coords 2, 4, SCREEN_WIDTH - 1, 13
|
||||
dw .MenuData
|
||||
db 1 ; default option
|
||||
|
||||
.MenuData:
|
||||
db 0 ; flags
|
||||
db 5, 0 ; rows, columns
|
||||
db SCROLLINGMENU_ITEMS_NORMAL ; item format
|
||||
dba Items
|
||||
dba Function1
|
||||
dba Function2
|
||||
dba Function3
|
||||
```
|
||||
|
||||
`wMenuDataFlags`:
|
||||
|
||||
```
|
||||
7: Select is functional
|
||||
6: Start is functional
|
||||
5: Call Function3
|
||||
4: Show arrows on the right-hand side
|
||||
3: D-Left is functional
|
||||
2: D-Right is functional
|
||||
1: Call Function3 only if [wSwitchItem] is 0
|
||||
0: Call Function1 to display the cancel entry
|
||||
```
|
||||
|
||||
If the columns entry in `MenuData` of a scrolling menu is 0, `Function2` isn't called either. It doesn't affect the position of the arrows.
|
||||
|
||||
Call state for functions in `MenuData` of `ScrollingMenu`:
|
||||
|
||||
```
|
||||
All of them:
|
||||
[wMenuSelection] = Current item. -1 is the CANCEL item.
|
||||
[wMenuSelectionQuantity] = Quantity of the current item.
|
||||
|
||||
Function1: Called to display a menu entry.
|
||||
de = Cursor position in TileMap
|
||||
|
||||
Function2: Called to display the quantity of a menu entry.
|
||||
de = Cursor position in TileMap + columns
|
||||
|
||||
Function3: Called to display anything else, whenever the cursor is moved.
|
||||
```
|
||||
|
||||
There is no register of importance that should be preserved in any of these functions.
|
||||
|
||||
The `; item format` entry in each `MenuData` changes how the `Items` struct looks.
|
||||
|
||||
If it's `SCROLLINGMENU_ITEMS_NORMAL` (1):
|
||||
|
||||
```
|
||||
db entries not including cancel
|
||||
db entry1
|
||||
db entry2
|
||||
db -1 ; cancel
|
||||
...
|
||||
```
|
||||
|
||||
If it's `SCROLLINGMENU_ITEMS_QUANTITY` (2):
|
||||
|
||||
```
|
||||
db entries not including cancel
|
||||
db entry1, quantity1
|
||||
db entry2, quantity2
|
||||
db -1 ; cancel
|
||||
...
|
||||
```
|
||||
|
||||
In case it's 1, `[wMenuSelectionQuantity]` will simply contain the next entry.
|
||||
|
||||
## `_2DMenu`
|
||||
|
||||
This, like is implied by the name, is a 2-dimensional menu, where you can move your cursor in all 4 directions. It's only used for the battle menus as well as Earl's academy.
|
||||
|
||||
Structure:
|
||||
|
||||
```asm
|
||||
.MenuHeader:
|
||||
db MENU_BACKUP_TILES ; flags
|
||||
db 12, 08 ; start coords
|
||||
db 17, 19 ; end coords
|
||||
dw .MenuData
|
||||
db 1 ; default option
|
||||
|
||||
.MenuData:
|
||||
db STATICMENU_CURSOR ; flags
|
||||
dn 2, 2 ; rows, columns
|
||||
db 6 ; spacing
|
||||
dba Strings
|
||||
dba Function
|
||||
```
|
||||
|
||||
`wMenuDataFlags`:
|
||||
|
||||
```
|
||||
7: Leave one tile of spacing between the left textbox border and the text, enabling the cursor.
|
||||
6: Don't leave one tile of spacing between the top textbox border and the text
|
||||
5: Set bits 4 and 5 in w2DMenuFlags1 (Wrap around horizontally and vertically)
|
||||
4: Unused
|
||||
3: Unused
|
||||
2: Unused
|
||||
1: Select is functional
|
||||
0: Disable B button
|
||||
```
|
||||
|
||||
The bank for the `Strings` is generated when you call `_2DMenu`, and as such it doesn't really matter what bank you specify there (unless you callba `_2DMenu_` directly, of course).
|
||||
|
||||
`; spacing` is not a misnomer here, it's used to define how much space there is between columns.
|
||||
|
||||
`Function` is called after printing all the strings. `hl` will be pointed at the row below the last in the menu in `TileMap`. We don't know of its purpose, since it's never actually used anywhere. Only the bank number is always set to the same bank as the menu, but not used otherwise, since the address is 0.
|
||||
|
||||
|
||||
## `DoNthMenu`/`SetUpMenu`
|
||||
|
||||
These are like the regular `VerticalMenu`, except they allow for creating slightly more "dynamic" menus, where the options aren't predefined, much like the `ScrollingMenu`.
|
||||
|
||||
Structure:
|
||||
|
||||
```
|
||||
.MenuHeader:
|
||||
db MENU_BACKUP_TILES ; flags
|
||||
menu_coords 0, 0, 10, 7
|
||||
dw .MenuData
|
||||
db 1 ; default option
|
||||
|
||||
.MenuData:
|
||||
db STATICMENU_CURSOR | STATICMENU_DISABLE_B ; flags
|
||||
db 0 ; items
|
||||
dw Items
|
||||
dw DisplayFunction
|
||||
dw StringPointers
|
||||
```
|
||||
|
||||
`wMenuDataFlags`:
|
||||
|
||||
```
|
||||
7: Unused
|
||||
6: Unused
|
||||
5: Set bit 5 in w2DMenuFlags1 (Wrap around vertically)
|
||||
4: Unused
|
||||
3: Start is functional
|
||||
2: D-left and D-right are functional
|
||||
1: Unused
|
||||
0: Unused
|
||||
```
|
||||
|
||||
The `; items` entry should be left empty, as it's autogenerated with the `Items` array in `GetMenuIndexSet`.
|
||||
|
||||
The bottom coord (`07` in the example) is autogenerated regardless of what you specify when building the MenuBox in `AutomaticGetMenuBottomCoord`, which also calculates the `bc` passed to MenuBox, which is useless because it's calculated again by MenuBox in `GetMenuBoxDims`.
|
||||
|
||||
`[wWhichIndexSet]` decides which menu is used through `GetMenuIndexSet`. You can define multiple menus at the Items pointer as such:
|
||||
|
||||
```
|
||||
Items:
|
||||
db entries not including cancel
|
||||
db entry1, entry2, entry3
|
||||
db -1 ; cancel
|
||||
db entries not including cancel for 2nd menu
|
||||
db entry1, entry2, entry3, entry4
|
||||
db -1 ; cancel
|
||||
```
|
||||
|
||||
This is actively used in `MainMenu`.
|
||||
|
||||
`StringPointers` isn't handled by `DoNthMenu` internally. It's handled by different `DisplayFunction`s. A custom one could choose to completely ignore it.
|
||||
|
||||
`StringPointers` struct handled through `PlaceNthMenuStrings` as `DisplayFunction` and `MenuJumptable`:
|
||||
|
||||
```asm
|
||||
StringPointers:
|
||||
dw FunctionToCall, PointerToString ; index 1
|
||||
dw FunctionToCall, PointerToString ; index 2
|
||||
...
|
||||
```
|
||||
|
||||
`StringPointers` struct handled through `PlaceMenuStrings`:
|
||||
|
||||
```asm
|
||||
StringPointers:
|
||||
db "STRING1@"
|
||||
db "STRING2@"
|
||||
...
|
||||
```
|
||||
|
||||
Call state for `DisplayFunction`:
|
||||
```
|
||||
[wMenuSelection] = Current item. -1 is the CANCEL item.
|
||||
de = Cursor position in TileMap
|
||||
```
|
||||
|
||||
## `VerticalMenu`
|
||||
|
||||
This is the simplest menu. Like, the most boring. Nothing special. Just normal. …nooooooormal…
|
||||
|
||||
Structure:
|
||||
|
||||
```asm
|
||||
.MenuHeader:
|
||||
db MENU_SPRITE_ANIMS | MENU_BACKUP_TILES ; flags
|
||||
menu_coords 12, 12, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
|
||||
dw .MenuData
|
||||
db 1 ; default option
|
||||
|
||||
.MenuData:
|
||||
db STATICMENU_CURSOR ; flags
|
||||
db 2 ; # items
|
||||
db "GIVE@"
|
||||
db "TAKE@"
|
||||
```
|
||||
|
||||
`wMenuDataFlags`:
|
||||
|
||||
```
|
||||
7: Leave one tile of spacing between the left textbox border and the text
|
||||
6: Don't leave one tile of spacing between the top textbox border and the text
|
||||
5: Set bit 5 in w2DMenuFlags1 (Wrap around vertically)
|
||||
4: Place menubox "title". See notes.
|
||||
3: Unused
|
||||
2: Unused
|
||||
1: Select is functional
|
||||
0: Disable B button
|
||||
```
|
||||
|
||||
If bit 4 is set, a string at the end of the items array will be put at an offset from the start coord of the menu box. This string is defined like this:
|
||||
|
||||
```asm
|
||||
db 2 ; # items
|
||||
db "GIVE@"
|
||||
db "TAKE@"
|
||||
db 2 ; x offset
|
||||
db "TEST@"
|
||||
```
|
||||
|
||||
This is used in the menu for selecting the character's name.
|
||||
|
||||
## Misc/Generic
|
||||
|
||||
`MenuHeader` flags (`wMenuFlags`):
|
||||
|
||||
```
|
||||
7: Save a backup of the tiles
|
||||
6: Save a backup of the tiles
|
||||
5: Unused
|
||||
4: Set bit 6 in w2DMenuFlags1 (Enable sprite animations)
|
||||
3: Disable click sound
|
||||
2: Unused
|
||||
1: Unused
|
||||
0: Call RestoreTileBackup when exiting the menu. This bit depends on whether bit 6 or 7 are set.
|
||||
```
|
||||
|
||||
`w2DMenuFlags1`:
|
||||
|
||||
```
|
||||
7: Disable checking of wMenuJoypadFilter
|
||||
6: Enable sprite animations
|
||||
5: Wrap around vertically
|
||||
4: Wrap around horizontally
|
||||
3: Set bit 7 in w2DMenuFlags2 and exit the loop if bit 5 is disabled and we tried to go too far down
|
||||
2: Set bit 7 in w2DMenuFlags2 and exit the loop if bit 5 is disabled and we tried to go too far up
|
||||
1: Set bit 7 in w2DMenuFlags2 and exit the loop if bit 4 is disabled and we tried to go too far left
|
||||
0: Set bit 7 in w2DMenuFlags2 and exit the loop if bit 4 is disabled and we tried to go too far right
|
||||
```
|
||||
|
||||
`w2DMenuFlags2`:
|
||||
|
||||
```
|
||||
7: ?????
|
||||
6: ?????
|
||||
5: ?????
|
||||
4: ?????
|
||||
3: ?????
|
||||
2: ?????
|
||||
1: ?????
|
||||
0: ?????
|
||||
```
|
||||
534
docs/move_effect_commands.md
Normal file
534
docs/move_effect_commands.md
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
# Move Effect Commands
|
||||
|
||||
Defined in [macros/scripts/battle_commands.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/battle_commands.asm) and [data/battle/effect_command_pointers.asm:BattleCommandPointers](https://github.com/pret/pokecrystal/blob/master/data/battle/effect_command_pointers.asm).
|
||||
|
||||
|
||||
## `$01`: `checkturn`
|
||||
|
||||
|
||||
## `$02`: `checkobedience`
|
||||
|
||||
|
||||
## `$03`: `usedmovetext`
|
||||
|
||||
|
||||
## `$04`: `doturn`
|
||||
|
||||
|
||||
## `$05`: `critical`
|
||||
|
||||
|
||||
## `$06`: `damagestats`
|
||||
|
||||
|
||||
## `$07`: `stab`
|
||||
|
||||
|
||||
## `$08`: `damagevariation`
|
||||
|
||||
|
||||
## `$09`: `checkhit`
|
||||
|
||||
|
||||
## `$0A`: `lowersub`
|
||||
|
||||
|
||||
## `$0B`: `hittargetnosub`
|
||||
|
||||
|
||||
## `$0C`: `raisesub`
|
||||
|
||||
|
||||
## `$0D`: `failuretext`
|
||||
|
||||
|
||||
## `$0E`: `applydamage`
|
||||
|
||||
|
||||
## `$0F`: `criticaltext`
|
||||
|
||||
|
||||
## `$10`: `supereffectivetext`
|
||||
|
||||
|
||||
## `$11`: `checkfaint`
|
||||
|
||||
|
||||
## `$12`: `buildopponentrage`
|
||||
|
||||
|
||||
## `$13`: `poisontarget`
|
||||
|
||||
|
||||
## `$14`: `sleeptarget`
|
||||
|
||||
|
||||
## `$15`: `draintarget`
|
||||
|
||||
|
||||
## `$16`: `eatdream`
|
||||
|
||||
|
||||
## `$17`: `burntarget`
|
||||
|
||||
|
||||
## `$18`: `freezetarget`
|
||||
|
||||
|
||||
## `$19`: `paralyzetarget`
|
||||
|
||||
|
||||
## `$1A`: `selfdestruct`
|
||||
|
||||
|
||||
## `$1B`: `mirrormove`
|
||||
|
||||
|
||||
## `$1C`: `statup`
|
||||
|
||||
|
||||
## `$1D`: `statdown`
|
||||
|
||||
|
||||
## `$1E`: `payday`
|
||||
|
||||
|
||||
## `$1F`: `conversion`
|
||||
|
||||
|
||||
## `$20`: `resetstats`
|
||||
|
||||
|
||||
## `$21`: `storeenergy`
|
||||
|
||||
|
||||
## `$22`: `unleashenergy`
|
||||
|
||||
|
||||
## `$23`: `forceswitch`
|
||||
|
||||
|
||||
## `$24`: `endloop`
|
||||
|
||||
|
||||
## `$25`: `flinchtarget`
|
||||
|
||||
|
||||
## `$26`: `ohko`
|
||||
|
||||
|
||||
## `$27`: `recoil`
|
||||
|
||||
|
||||
## `$28`: `mist`
|
||||
|
||||
|
||||
## `$29`: `focusenergy`
|
||||
|
||||
|
||||
## `$2A`: `confuse`
|
||||
|
||||
|
||||
## `$2B`: `confusetarget`
|
||||
|
||||
|
||||
## `$2C`: `heal`
|
||||
|
||||
|
||||
## `$2D`: `transform`
|
||||
|
||||
|
||||
## `$2E`: `screen`
|
||||
|
||||
|
||||
## `$2F`: `poison`
|
||||
|
||||
|
||||
## `$30`: `paralyze`
|
||||
|
||||
|
||||
## `$31`: `substitute`
|
||||
|
||||
|
||||
## `$32`: `rechargenextturn`
|
||||
|
||||
|
||||
## `$33`: `mimic`
|
||||
|
||||
|
||||
## `$34`: `metronome`
|
||||
|
||||
|
||||
## `$35`: `leechseed`
|
||||
|
||||
|
||||
## `$36`: `splash`
|
||||
|
||||
|
||||
## `$37`: `disable`
|
||||
|
||||
|
||||
## `$38`: `cleartext`
|
||||
|
||||
|
||||
## `$39`: `charge`
|
||||
|
||||
|
||||
## `$3A`: `checkcharge`
|
||||
|
||||
|
||||
## `$3B`: `traptarget`
|
||||
|
||||
|
||||
## `$3C`: `effect0x3c`
|
||||
|
||||
|
||||
## `$3D`: `rampage`
|
||||
|
||||
|
||||
## `$3E`: `checkrampage`
|
||||
|
||||
|
||||
## `$3F`: `constantdamage`
|
||||
|
||||
|
||||
## `$40`: `counter`
|
||||
|
||||
|
||||
## `$41`: `encore`
|
||||
|
||||
|
||||
## `$42`: `painsplit`
|
||||
|
||||
|
||||
## `$43`: `snore`
|
||||
|
||||
|
||||
## `$44`: `conversion2`
|
||||
|
||||
|
||||
## `$45`: `lockon`
|
||||
|
||||
|
||||
## `$46`: `sketch`
|
||||
|
||||
|
||||
## `$47`: `defrostopponent`
|
||||
|
||||
|
||||
## `$48`: `sleeptalk`
|
||||
|
||||
|
||||
## `$49`: `destinybond`
|
||||
|
||||
|
||||
## `$4A`: `spite`
|
||||
|
||||
|
||||
## `$4B`: `falseswipe`
|
||||
|
||||
|
||||
## `$4C`: `healbell`
|
||||
|
||||
|
||||
## `$4D`: `kingsrock`
|
||||
|
||||
|
||||
## `$4E`: `triplekick`
|
||||
|
||||
|
||||
## `$4F`: `kickcounter`
|
||||
|
||||
|
||||
## `$50`: `thief`
|
||||
|
||||
|
||||
## `$51`: `arenatrap`
|
||||
|
||||
|
||||
## `$52`: `nightmare`
|
||||
|
||||
|
||||
## `$53`: `defrost`
|
||||
|
||||
|
||||
## `$54`: `curse`
|
||||
|
||||
|
||||
## `$55`: `protect`
|
||||
|
||||
|
||||
## `$56`: `spikes`
|
||||
|
||||
|
||||
## `$57`: `foresight`
|
||||
|
||||
|
||||
## `$58`: `perishsong`
|
||||
|
||||
|
||||
## `$59`: `startsandstorm`
|
||||
|
||||
|
||||
## `$5A`: `endure`
|
||||
|
||||
|
||||
## `$5B`: `checkcurl`
|
||||
|
||||
|
||||
## `$5C`: `rolloutpower`
|
||||
|
||||
|
||||
## `$5D`: `effect0x5d`
|
||||
|
||||
|
||||
## `$5E`: `furycutter`
|
||||
|
||||
|
||||
## `$5F`: `attract`
|
||||
|
||||
|
||||
## `$60`: `happinesspower`
|
||||
|
||||
|
||||
## `$61`: `present`
|
||||
|
||||
|
||||
## `$62`: `damagecalc`
|
||||
|
||||
|
||||
## `$63`: `frustrationpower`
|
||||
|
||||
|
||||
## `$64`: `safeguard`
|
||||
|
||||
|
||||
## `$65`: `checksafeguard`
|
||||
|
||||
|
||||
## `$66`: `getmagnitude`
|
||||
|
||||
|
||||
## `$67`: `batonpass`
|
||||
|
||||
|
||||
## `$68`: `pursuit`
|
||||
|
||||
|
||||
## `$69`: `clearhazards`
|
||||
|
||||
|
||||
## `$6A`: `healmorn`
|
||||
|
||||
|
||||
## `$6B`: `healday`
|
||||
|
||||
|
||||
## `$6C`: `healnite`
|
||||
|
||||
|
||||
## `$6D`: `hiddenpower`
|
||||
|
||||
|
||||
## `$6E`: `startrain`
|
||||
|
||||
|
||||
## `$6F`: `startsun`
|
||||
|
||||
|
||||
## `$70`: `attackup`
|
||||
|
||||
|
||||
## `$71`: `defenseup`
|
||||
|
||||
|
||||
## `$72`: `speedup`
|
||||
|
||||
|
||||
## `$73`: `specialattackup`
|
||||
|
||||
|
||||
## `$74`: `specialdefenseup`
|
||||
|
||||
|
||||
## `$75`: `accuracyup`
|
||||
|
||||
|
||||
## `$76`: `evasionup`
|
||||
|
||||
|
||||
## `$77`: `attackup2`
|
||||
|
||||
|
||||
## `$78`: `defenseup2`
|
||||
|
||||
|
||||
## `$79`: `speedup2`
|
||||
|
||||
|
||||
## `$7A`: `specialattackup2`
|
||||
|
||||
|
||||
## `$7B`: `specialdefenseup2`
|
||||
|
||||
|
||||
## `$7C`: `accuracyup2`
|
||||
|
||||
|
||||
## `$7D`: `evasionup2`
|
||||
|
||||
|
||||
## `$7E`: `attackdown`
|
||||
|
||||
|
||||
## `$7F`: `defensedown`
|
||||
|
||||
|
||||
## `$80`: `speeddown`
|
||||
|
||||
|
||||
## `$81`: `specialattackdown`
|
||||
|
||||
|
||||
## `$82`: `specialdefensedown`
|
||||
|
||||
|
||||
## `$83`: `accuracydown`
|
||||
|
||||
|
||||
## `$84`: `evasiondown`
|
||||
|
||||
|
||||
## `$85`: `attackdown2`
|
||||
|
||||
|
||||
## `$86`: `defensedown2`
|
||||
|
||||
|
||||
## `$87`: `speeddown2`
|
||||
|
||||
|
||||
## `$88`: `specialattackdown2`
|
||||
|
||||
|
||||
## `$89`: `specialdefensedown2`
|
||||
|
||||
|
||||
## `$8A`: `accuracydown2`
|
||||
|
||||
|
||||
## `$8B`: `evasiondown2`
|
||||
|
||||
|
||||
## `$8C`: `statupmessage`
|
||||
|
||||
|
||||
## `$8D`: `statdownmessage`
|
||||
|
||||
|
||||
## `$8E`: `statupfailtext`
|
||||
|
||||
|
||||
## `$8F`: `statdownfailtext`
|
||||
|
||||
|
||||
## `$90`: `effectchance`
|
||||
|
||||
|
||||
## `$91`: `statdownanim`
|
||||
|
||||
|
||||
## `$92`: `statupanim`
|
||||
|
||||
|
||||
## `$93`: `switchturn`
|
||||
|
||||
|
||||
## `$94`: `fakeout`
|
||||
|
||||
|
||||
## `$95`: `bellydrum`
|
||||
|
||||
|
||||
## `$96`: `psychup`
|
||||
|
||||
|
||||
## `$97`: `rage`
|
||||
|
||||
|
||||
## `$98`: `doubleflyingdamage`
|
||||
|
||||
|
||||
## `$99`: `doubleundergrounddamage`
|
||||
|
||||
|
||||
## `$9A`: `mirrorcoat`
|
||||
|
||||
|
||||
## `$9B`: `checkfuturesight`
|
||||
|
||||
|
||||
## `$9C`: `futuresight`
|
||||
|
||||
|
||||
## `$9D`: `doubleminimizedamage`
|
||||
|
||||
|
||||
## `$9E`: `skipsuncharge`
|
||||
|
||||
|
||||
## `$9F`: `thunderaccuracy`
|
||||
|
||||
|
||||
## `$A0`: `teleport`
|
||||
|
||||
|
||||
## `$A1`: `beatup`
|
||||
|
||||
|
||||
## `$A2`: `ragedamage`
|
||||
|
||||
|
||||
## `$A3`: `resettypematchup`
|
||||
|
||||
|
||||
## `$A4`: `allstatsup`
|
||||
|
||||
|
||||
## `$A5`: `bidefailtext`
|
||||
|
||||
|
||||
## `$A6`: `raisesubnoanim`
|
||||
|
||||
|
||||
## `$A7`: `lowersubnoanim`
|
||||
|
||||
|
||||
## `$A8`: `beatupfailtext`
|
||||
|
||||
|
||||
## `$A9`: `clearmissdamage`
|
||||
|
||||
|
||||
## `$AA`: `movedelay`
|
||||
|
||||
|
||||
## `$AB`: `hittarget`
|
||||
|
||||
|
||||
## `$AC`: `tristatuschance`
|
||||
|
||||
|
||||
## `$AD`: `supereffectivelooptext`
|
||||
|
||||
|
||||
## `$AE`: `startloop`
|
||||
|
||||
|
||||
## `$AF`: `curl`
|
||||
|
||||
|
||||
## `$FE`: `endturn`
|
||||
|
||||
|
||||
## `$FF`: `endmove`
|
||||
123
docs/movement_commands.md
Normal file
123
docs/movement_commands.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# Movement Commands
|
||||
|
||||
Defined in [macros/scripts/movement.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/movement.asm) and [engine/overworld/movement.asm:MovementPointers](https://github.com/pret/pokecrystal/blob/master/engine/overworld/movement.asm).
|
||||
|
||||
|
||||
## `$00`−`$03`: <code>turn_head <i>direction</i></code>
|
||||
|
||||
|
||||
## `$04`−`$07`: <code>turn_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$08`−`$0B`: <code>slow_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$0C`−`$0F`: <code>step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$10`−`$13`: <code>big_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$14`−`$17`: <code>slow_slide_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$18`−`$1B`: <code>slide_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$1C`−`$1F`: <code>fast_slide_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$20`−`$23`: <code>turn_away <i>direction</i></code>
|
||||
|
||||
|
||||
## `$24`−`$27`: <code>turn_in <i>direction</i></code>
|
||||
|
||||
|
||||
## `$28`−`$2B`: <code>turn_waterfall <i>direction</i></code>
|
||||
|
||||
|
||||
## `$2C`−`$2F`: <code>slow_jump_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$30`−`$33`: <code>jump_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$34`−`$37`: <code>fast_jump_step <i>direction</i></code>
|
||||
|
||||
|
||||
## `$38`: `remove_sliding`
|
||||
|
||||
|
||||
## `$39`: `set_sliding`
|
||||
|
||||
|
||||
## `$3A`: `remove_fixed_facing`
|
||||
|
||||
|
||||
## `$3B`: `fix_facing`
|
||||
|
||||
|
||||
## `$3C`: `show_object`
|
||||
|
||||
|
||||
## `$3D`: `hide_object`
|
||||
|
||||
|
||||
## `$3E`−`$46`: <code>step_sleep <i>length</i></code>
|
||||
|
||||
|
||||
## `$47`: `step_end`
|
||||
|
||||
|
||||
## `$48`: <code>step_48 <i>param</i></code>
|
||||
|
||||
|
||||
## `$49`: `remove_object`
|
||||
|
||||
|
||||
## `$4A`: `step_loop`
|
||||
|
||||
|
||||
## `$4B`: `step_4b`
|
||||
|
||||
|
||||
## `$4C`: `teleport_from`
|
||||
|
||||
|
||||
## `$4D`: `teleport_to`
|
||||
|
||||
|
||||
## `$4E`: `skyfall`
|
||||
|
||||
|
||||
## `$4F`: <code>step_dig <i>length</i></code>
|
||||
|
||||
|
||||
## `$50`: `step_bump`
|
||||
|
||||
|
||||
## `$51`: `fish_got_bite`
|
||||
|
||||
|
||||
## `$52`: `fish_cast_rod`
|
||||
|
||||
|
||||
## `$53`: `hide_emote`
|
||||
|
||||
|
||||
## `$54`: `show_emote`
|
||||
|
||||
|
||||
## `$55`: <code>step_shake <i>displacement</i></code>
|
||||
|
||||
|
||||
## `$56`: `tree_shake`
|
||||
|
||||
|
||||
## `$57`: <code>rock_smash <i>length</i></code>
|
||||
|
||||
|
||||
## `$58`: <code>return_dig <i>length</i></code>
|
||||
|
||||
|
||||
## `$59`: `skyfall_top`
|
||||
290
docs/music_commands.md
Normal file
290
docs/music_commands.md
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
# Music Commands
|
||||
|
||||
Defined in [macros/scripts/audio.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/audio.asm) and [audio/engine.asm:MusicCommands](https://github.com/pret/pokecrystal/blob/master/audio/engine.asm).
|
||||
|
||||
Note: Commands that are intended for the song channels (1-4) can be used by the sound effect channels (5-8) if the sound effect channel exits sound effect mode with the `toggle_sfx` command.
|
||||
|
||||
|
||||
## <code>channel_count <i>n</i></code>
|
||||
|
||||
Used at the start of each sound header to specify how many channels are used in the sound.
|
||||
`n`: Number of channels [`1`, `4`]
|
||||
|
||||
|
||||
## <code>channel <i>index</i>, <i>address</i></code>
|
||||
|
||||
Used for each channel in a sound header.
|
||||
`index`: Channel number [`1`, `8`]
|
||||
`address`: Pointer to the sound data
|
||||
|
||||
|
||||
## <code>note <i>pitch</i>, <i>length</i></code>
|
||||
|
||||
Play a basic note. Used by channels 1-3.
|
||||
`pitch`: Pitch of note (see [constants/audio_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/audio_constants.asm))
|
||||
`length`: Length of note in "ticks" [`1`, `16`]. The exact duration of a tick is dependant on the current "speed" (see `note_type` and `drum_speed`) and the current "tempo" (see `tempo`).
|
||||
|
||||
|
||||
## <code>drum_note <i>instrument</i>, <i>length</i></code>
|
||||
|
||||
Play a predefined drum note. Used by channel 4.
|
||||
`instrument`: Instrument ID [`1`, `12`] (see `toggle_noise`)
|
||||
`length`: Length of note [`1`, `16`]
|
||||
|
||||
|
||||
## <code>rest <i>length</i></code>
|
||||
|
||||
Basic rest. Used by channels 1-4.
|
||||
`length`: Length of rest [`1`, `16`]
|
||||
|
||||
|
||||
## <code>square_note <i>length</i>, <i>volume</i>, <i>fade</i>, <i>frequency</i></code>
|
||||
|
||||
Sound effect square note. Used by channels 5-7.
|
||||
`length`: Length of note [`0`, `255`]
|
||||
`volume`: Initial volume [`0`, `15`]
|
||||
`fade`: Volume fade [`-7`, `7`]
|
||||
`frequency`: Note frequency [`0`, `65535`]
|
||||
|
||||
|
||||
## <code>noise_note <i>length</i>, <i>volume</i>, <i>fade</i>, <i>frequency</i></code>
|
||||
|
||||
Sound effect noise note. Used by channel 8.
|
||||
`length`: Length of note [`0`, `255`]
|
||||
`volume`: Initial volume [`0`, `15`]
|
||||
`fade`: Volume fade [`-7`, `7`]
|
||||
`frequency`: Note frequency [`0`, `255`]
|
||||
|
||||
|
||||
## `$D0`−`$D7`: <code>octave <i>n</i></code>
|
||||
|
||||
Set the octave for the notes played on the current channel. Used by channels 1-3.
|
||||
`n`: New octave [`1`, `8`]
|
||||
|
||||
|
||||
## `$D8`: <code>note_type <i>length</i>, <i>volume</i>, <i>fade/wave_instrument</i></code>
|
||||
|
||||
Set persistent note properties. Used by channels 1-3.
|
||||
`length`: Base note length [`1`, `15`] (`12` is often used for 4/4 common time because `12` is factorable by both `3` and `4`. Therefore it works very well for quarter notes, eighth notes, sixteenth notes, and triplets.)
|
||||
`volume`: Initial volume [`0`, `15`] for channels 1-2, [`0`, `3`] for channel 3 (see `volume_envelope`)
|
||||
`fade`: Volume fade [`-7`, `7`] (applies to channels 1-2)
|
||||
`wave_instrument`: Wave instrument ID (applies to channel 3) (see [audio/wave_samples.asm](https://github.com/pret/pokecrystal/blob/master/audio/wave_samples.asm))
|
||||
|
||||
|
||||
## `$D8`: <code>drum_speed <i>length</i></code>
|
||||
|
||||
Set persistent note properties. Used by channel 4.
|
||||
`length`: Base note length [`1`, `15`] (use `12` for common time)
|
||||
|
||||
|
||||
## `$D9`: <code>transpose <i>num_octaves</i>, <i>num_pitches</i></code>
|
||||
|
||||
Transpose all notes played on the current channel. Used by channels 1-3.
|
||||
`num_octaves`: Number of octaves to subtract from each note
|
||||
`num_pitches`: Number of pitches to add to each note
|
||||
|
||||
|
||||
## `$DA`: <code>tempo <i>tempo</i></code>
|
||||
|
||||
Set the tempo for all playing channels. This should only be used by channel 1.
|
||||
|
||||
The formula to convert from this tempo to BPM is: BPM = 19200 / `tempo`
|
||||
This formula also works backwards to convert BPM to tempo: `tempo` = 19200 / BPM
|
||||
|
||||
Only set or change this value when all playing channels are triggering a note or rest at the same time, otherwise desyncs may happen.
|
||||
|
||||
|
||||
## `$DB`: <code>duty_cycle <i>duty_cycle</i></code>
|
||||
|
||||
Set the square duty (sound) for the current channel. Used by channels 1-2.
|
||||
The only accepted values are 0-3.
|
||||
|
||||
- 0 = 12.5% waveform: `_______¯`
|
||||
- 1 = 25% waveform: `______¯¯`
|
||||
- 2 = 50% waveform: `____¯¯¯¯`
|
||||
- 3 = 75% waveform: `__¯¯¯¯¯¯` (sounds the same as 25%)
|
||||
|
||||
To change the sound for channel 3, use `note_type` or `volume_envelope`.
|
||||
|
||||
|
||||
## `$DC`: <code>volume_envelope <i>volume</i>, <i>fade/wave_instrument</i></code>
|
||||
|
||||
Set the volume envelope for the current channel. Used by channels 1-3.
|
||||
`volume`: Initial volume [`0`, `15`] for channels 1-2, [`0`, `3`] for channel 3
|
||||
`fade`: Volume fade [`-7`, `7`] (applies to channels 1-2)
|
||||
`wave_instrument`: Wave instrument ID (applies to channel 3) (see [audio/wave_samples.asm](https://github.com/pret/pokecrystal/blob/master/audio/wave_samples.asm))
|
||||
|
||||
For channel 3, the only accepted `volume` values are 0-3.
|
||||
|
||||
- 0 = Mute
|
||||
- 1 = 100% volume
|
||||
- 2 = 50% volume
|
||||
- 3 = 25% volume
|
||||
|
||||
Note about `fade`: A positive value means a decrease in volume; a negative value means an increase in volume. A small magnitude means a quick change; a large magnitude means a slow change. It is stored in signed magnitude representation, so a value of `8` is the same as (negative) `0`.
|
||||
|
||||
|
||||
## `$DD`: <code>pitch_sweep <i>length</i>, <i>pitch_change</i></code>
|
||||
|
||||
Set pitch sweep properties. Used by channel 5.
|
||||
`length`: Duration of effect [`0`, `15`]
|
||||
`pitch_change`: Extent of effect [`-7`, `8`] Note: `8` is used in place of `0`
|
||||
|
||||
|
||||
## `$DE`: <code>duty_cycle_pattern <i>a</i>, <i>b</i>, <i>c</i>, <i>d</i></code>
|
||||
|
||||
Set duty cycle pattern (ie, pulse width modulation). Used by channels 5-6.
|
||||
|
||||
This cycles the channel through 4 duty cycles, one per frame.
|
||||
Each argument defines a duty cycle, same as the `duty_cycle` command.
|
||||
|
||||
|
||||
## `$DF`: <code>toggle_sfx</code>
|
||||
|
||||
Toggle between pitch-based songs and frequency-based sound effects. Can be used by any channel.
|
||||
|
||||
Note: Similar to the pokered command `execute_music`, however `execute_music` can only be used on channels 5-8 and can not be disabled for the duration of the sound once it is enabled.
|
||||
|
||||
|
||||
## `$E0`: <code>pitch_slide <i>duration</i>, <i>octave</i>, <i>pitch</i></code>
|
||||
|
||||
Bend the pitch of the next note played, and only that note. Used by channel 1.
|
||||
`duration`: Duration of the target note after slide effect
|
||||
`octave`: Target octave
|
||||
`pitch`: Target pitch (see [constants/audio_constants.asm](https://github.com/pret/pokecrystal/blob/master/constants/audio_constants.asm))
|
||||
|
||||
|
||||
## `$E1`: <code>vibrato <i>delay</i>, <i>extent</i>, <i>rate</i></code>
|
||||
|
||||
Apply vibrato to current channel. Used by channels 1-3.
|
||||
`delay`: Delay until vibrato effect begins for each note [`0`, `255`]
|
||||
`extent`: Amplitude of vibrato [`0`, `15`]
|
||||
`rate`: Frequency of vibrato [`0`, `15`]
|
||||
|
||||
|
||||
## `$E2`: <code>unknownmusic0xe2 <i>unknown</i></code>
|
||||
|
||||
|
||||
## `$E3`: <code>toggle_noise <i>id</i></code>
|
||||
|
||||
Set the "drum kit" to be used if it is currently unset. Mute the channel otherwise. Used by channel 4.
|
||||
`id`: Drum kit ID [`0`, `5`] (see [audio/drumkits.asm](https://github.com/pret/pokecrystal/blob/master/audio/drumkits.asm))
|
||||
|
||||
Note: The drum kit ID is initially unset at the start of a song. When muting the channel, the `id` argument must not be present.
|
||||
|
||||
|
||||
## `$E4`: <code>force_stereo_panning <i>left_enable</i>, <i>right_enable</i></code>
|
||||
|
||||
Set left/right stereo output for the current channel, regardless of user's stereo setting. Used by channels 1-4.
|
||||
`left_enable`: `TRUE`/`FALSE`
|
||||
`right_enable`: `TRUE`/`FALSE`
|
||||
|
||||
|
||||
## `$E5`: <code>volume <i>left_volume</i>, <i>right_volume</i></code>
|
||||
|
||||
Set master volume for left/right speakers. Typically only used by channel 1.
|
||||
`left_volume`: Left speaker volume [`0`, `7`]
|
||||
`right_volume`: Right speaker volume [`0`, `7`]
|
||||
|
||||
Note: Minimum volume, `0`, is not muted.
|
||||
|
||||
|
||||
## `$E6`: <code>pitch_offset <i>pitch_offset</i></code>
|
||||
|
||||
Adjust the pitch of all notes on the current channel. Used by channels 1-3.
|
||||
`pitch_offset`: Frequency adjustment of each pitch
|
||||
|
||||
Note: Similar to the pokered command `toggle_perfect_pitch`. `toggle_perfect_pitch` can be replaced with a combination of `pitch_offset 1` and `pitch_offset 0`.
|
||||
|
||||
|
||||
## `$E7`: <code>unknownmusic0xe7 <i>unknown</i></code>
|
||||
|
||||
|
||||
## `$E8`: <code>unknownmusic0xe8 <i>unknown</i></code>
|
||||
|
||||
|
||||
## `$E9`: <code>tempo_relative <i>value</i></code>
|
||||
|
||||
|
||||
## `$EA`: <code>restart_channel <i>address</i></code>
|
||||
|
||||
|
||||
## `$EB`: <code>new_song <i>id</i></code>
|
||||
|
||||
|
||||
## `$EC`: <code>sfx_priority_on</code>
|
||||
|
||||
|
||||
## `$ED`: <code>sfx_priority_off</code>
|
||||
|
||||
|
||||
## `$EE`: <code>unknownmusic0xee <i>address</i></code>
|
||||
|
||||
|
||||
## `$EF`: <code>stereo_panning <i>left_enable</i>, <i>right_enable</i></code>
|
||||
|
||||
Set left/right stereo output for the current channel, if the user has stereo mode enabled. Used by channels 1-4.
|
||||
`left_enable`: `TRUE`/`FALSE`
|
||||
`right_enable`: `TRUE`/`FALSE`
|
||||
|
||||
|
||||
## `$F0`: <code>sfx_toggle_noise <i>id</i></code>
|
||||
|
||||
Set the "drum kit" to be used if it is currently unset. Mute the channel otherwise. Used by channel 8.
|
||||
`id`: Drum kit ID [`0`, `5`] (see [audio/drumkits.asm](https://github.com/pret/pokecrystal/blob/master/audio/drumkits.asm))
|
||||
|
||||
Note: The drum kit ID is initially unset at the start of a song. When muting the channel, the `id` argument must not be present.
|
||||
|
||||
|
||||
## `$F1`: <code>music0xf1</code>
|
||||
|
||||
|
||||
## `$F2`: <code>music0xf2</code>
|
||||
|
||||
|
||||
## `$F3`: <code>music0xf3</code>
|
||||
|
||||
|
||||
## `$F4`: <code>music0xf4</code>
|
||||
|
||||
|
||||
## `$F5`: <code>music0xf5</code>
|
||||
|
||||
|
||||
## `$F6`: <code>music0xf6</code>
|
||||
|
||||
|
||||
## `$F7`: <code>music0xf7</code>
|
||||
|
||||
|
||||
## `$F8`: <code>music0xf8</code>
|
||||
|
||||
|
||||
## `$F9`: <code>unknownmusic0xf9</code>
|
||||
|
||||
|
||||
## `$FA`: <code>set_condition <i>condition</i></code>
|
||||
|
||||
|
||||
## `$FB`: <code>sound_jump_if <i>condition</i>, <i>address</i></code>
|
||||
|
||||
|
||||
## `$FC`: <code>sound_jump <i>address</i></code>
|
||||
|
||||
|
||||
## `$FD`: <code>sound_loop <i>count</i>, <i>address</i></code>
|
||||
|
||||
Execute a branch of sound commands a total of `count` times.
|
||||
`count`: Number of times to execute the loop (including the first execution) (use `0` for an infinite loop)
|
||||
`address`: Pointer to the start of the loop of sound commands
|
||||
|
||||
|
||||
## `$FE`: <code>sound_call <i>address</i></code>
|
||||
|
||||
Execute a branch of sound commands, returning to the call point once a `sound_ret` command is reached.
|
||||
`address`: Pointer to the branch of sound commands to call
|
||||
|
||||
|
||||
## `$FF`: <code>sound_ret</code>
|
||||
|
||||
Return to the caller (ie, `sound_call`) if in a sub branch. End the sound otherwise.
|
||||
30
docs/pic_animations.md
Normal file
30
docs/pic_animations.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Pic Animations
|
||||
|
||||
Defined in [macros/scripts/pic_anims.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/pic_anims.asm).
|
||||
|
||||
Pic animations are assembled in 3 parts:
|
||||
|
||||
- Top-level animations:
|
||||
- <code>frame <i>N</i>, <i>duration</i></code>: Frame #0 is the original pic (no change)
|
||||
- <code>setrepeat <i>N</i></code>: Sets the number of times to repeat
|
||||
- <code>dorepeat <i>I</i></code>: Repeats from command #<i>I</i> (with the first command being #0)
|
||||
- `endanim`
|
||||
|
||||
- Bitmasks:
|
||||
Layered over the pic to designate affected tiles
|
||||
|
||||
- Frame definitions:
|
||||
first byte is the bitmask used for this frame
|
||||
following bytes are tile ids mapped to each bit in the mask
|
||||
|
||||
Animation data is in these files:
|
||||
|
||||
- [gfx/pokemon/anims.asm](https://github.com/pret/pokecrystal/blob/master/gfx/pokemon/anims.asm):
|
||||
Main animations (played everywhere)
|
||||
|
||||
- [gfx/pokemon/idles.asm](https://github.com/pret/pokecrystal/blob/master/gfx/pokemon/idles.asm):
|
||||
Idle animations, appended to the main animation.
|
||||
Used in the status screen (blinking, tail wags etc.)
|
||||
|
||||
- [gfx/pokemon/unown_anims.asm](https://github.com/pret/pokecrystal/blob/master/gfx/pokemon/unown_anims.asm) and [gfx/pokemon/unown_idles.asm](https://github.com/pret/pokecrystal/blob/master/gfx/pokemon/unown_idles.asm):
|
||||
Unown has its own animation data despite having an entry in the main tables.
|
||||
179
docs/text_commands.md
Normal file
179
docs/text_commands.md
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Text Commands
|
||||
|
||||
Defined in [macros/scripts/text.asm](https://github.com/pret/pokecrystal/blob/master/macros/scripts/text.asm) and [home/text.asm:TextCommands](https://github.com/pret/pokecrystal/blob/master/home/text.asm).
|
||||
|
||||
|
||||
## `$00`: `text_start`
|
||||
|
||||
Start writing text until `"@"`. The text can use [control characters](#control-characters).
|
||||
|
||||
|
||||
## `$01`: <code>text_ram <i>address</i></code>
|
||||
|
||||
Write text from a RAM address.
|
||||
|
||||
|
||||
## `$02`: <code>text_bcd <i>address</i>, <i>flags</i></code>
|
||||
|
||||
Write [BCD][bcd] from an address, typically RAM.
|
||||
|
||||
[bcd]: https://en.wikipedia.org/wiki/Binary-coded_decimal
|
||||
|
||||
|
||||
## `$03`: <code>text_move <i>address</i></code>
|
||||
|
||||
Move to a new tile.
|
||||
|
||||
|
||||
## `$04`: <code>text_box <i>address</i>, <i>height</i>, <i>width</i></code>
|
||||
|
||||
Draw a box.
|
||||
|
||||
|
||||
## `$05`: `text_low`
|
||||
|
||||
Write text at (1, 16).
|
||||
|
||||
|
||||
## `$06`: `text_promptbutton`
|
||||
|
||||
Wait for button press; show arrow.
|
||||
|
||||
|
||||
## `$07`: `text_scroll`
|
||||
|
||||
Pushes text up two lines and sets the `bc` cursor to the border tile below the
|
||||
first character column of the text box.
|
||||
|
||||
|
||||
## `$08`: `text_asm`
|
||||
|
||||
Start interpreting assembly code.
|
||||
|
||||
|
||||
## `$09`: <code>text_decimal <i>address</i>, <i>bytes</i>, <i>digits</i></code>
|
||||
|
||||
Read *bytes* bytes from *address* and print them as a *digits*-digit number.
|
||||
|
||||
|
||||
## `$0A`: `text_pause`
|
||||
|
||||
Pause for 30 frames unless A or B is pressed.
|
||||
|
||||
|
||||
## `$0B`: `sound_dex_fanfare_50_79`
|
||||
|
||||
Play `SFX_DEX_FANFARE_50_79`.
|
||||
|
||||
|
||||
## `$0C`: <code>text_dots <i>n</i></code>
|
||||
|
||||
Print *n* `"…"`s, pausing for 10 frames after each; interrupt if A or B is pressed.
|
||||
|
||||
|
||||
## `$0D`: `text_waitbutton`
|
||||
|
||||
Wait for button press; don't show arrow.
|
||||
|
||||
|
||||
## `$0E`: `sound_dex_fanfare_20_49`
|
||||
|
||||
Play `SFX_DEX_FANFARE_20_49`.
|
||||
|
||||
|
||||
## `$0F`: `sound_item`
|
||||
|
||||
Play `SFX_ITEM`.
|
||||
|
||||
|
||||
## `$10`: `sound_caught_mon`
|
||||
|
||||
Play `SFX_CAUGHT_MON`.
|
||||
|
||||
|
||||
## `$11`: `sound_dex_fanfare_80_109`
|
||||
|
||||
Play `SFX_DEX_FANFARE_80_109`.
|
||||
|
||||
|
||||
## `$12`: `sound_fanfare`
|
||||
|
||||
Play `SFX_FANFARE`.
|
||||
|
||||
|
||||
## `$13`: `sound_slot_machine_start`
|
||||
|
||||
Play `SFX_SLOT_MACHINE_START`.
|
||||
|
||||
|
||||
## `$14`: <code>text_buffer <i>id</i></code>
|
||||
|
||||
Write text from one of the following addresses (listed in [data/text_buffers.asm](https://github.com/pret/pokecrystal/blob/master/data/text_buffers.asm)):
|
||||
|
||||
0. `wStringBuffer3`
|
||||
1. `wStringBuffer4`
|
||||
2. `wStringBuffer5`
|
||||
3. `wStringBuffer2`
|
||||
4. `wStringBuffer1`
|
||||
5. `wEnemyMonNickname`
|
||||
6. `wBattleMonNickname`
|
||||
|
||||
|
||||
## `$15`: `text_today`
|
||||
|
||||
Print the weekday.
|
||||
|
||||
|
||||
## `$16`: <code>text_far <i>address</i></code>
|
||||
|
||||
Write text from a different bank.
|
||||
|
||||
|
||||
## `$50`: `text_end`
|
||||
|
||||
Stops processing text commands.
|
||||
|
||||
|
||||
# Control characters
|
||||
|
||||
These get interpreted in the context of printing regular text. Macros exist to conveniently place the control characters.
|
||||
|
||||
|
||||
## `$00`: <code>text <i>text</i></code>
|
||||
|
||||
Start writing text until `"@"`. (Not actually a control character, but shorter than `text_start` followed by `db`.)
|
||||
|
||||
|
||||
## `$4E`, `"<NEXT>"`: <code>next <i>text</i></code>
|
||||
|
||||
Move a line down.
|
||||
|
||||
|
||||
## `$4F`, `"<LINE>"`: <code>line <i>text</i></code>
|
||||
|
||||
Start writing at the bottom line.
|
||||
|
||||
|
||||
## `$50`, `"@"`: <code>page <i>text</i></code>
|
||||
|
||||
Start a new Pokédex page.
|
||||
|
||||
|
||||
## `$51`, `"<PARA>"`: <code>para <i>text</i></code>
|
||||
|
||||
Start a new paragraph.
|
||||
|
||||
|
||||
## `$55`, `"<CONT>"`: <code>cont <i>text</i></code>
|
||||
|
||||
Scroll to the next line.
|
||||
|
||||
|
||||
## `$57`, `"<DONE>"`: `done`
|
||||
|
||||
End a text box.
|
||||
|
||||
|
||||
## `$58`, `"<PROMPT>"`: `prompt`
|
||||
|
||||
Prompt the player to end a text box (initiating some other event).
|
||||
124
docs/vc_patch.md
Normal file
124
docs/vc_patch.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# Nintendo 2DS/3DS Virtual Console Patch
|
||||
|
||||
The Nintendo Virtual Console is an emulator on the 2DS and 3DS consoles. It can emulate the Game Boy Color (among other consoles), while applying enhancements or modifications to some games, such as replacing Link Cable functionality with the DS' Wireless Link capabilities, or disabling Game Boy Printer features.
|
||||
|
||||
Game-specific enhancements are determined by a `.patch` file corresponding to the `.gbc` ROM file. These files are bundled together in a `.cia` file; creating such a file is outside the scope of this project.
|
||||
|
||||
|
||||
## Build pokecrystal11.patch
|
||||
|
||||
To build **pokecrystal11.patch**:
|
||||
|
||||
```bash
|
||||
make crystal11_vc
|
||||
```
|
||||
|
||||
This will also create two ROM files, **pokecrystal11.gbc** and **pokecrystal11_vc.gbc**. The pokecrystal11_vc.gbc file has the patches already applied to it; do *not* use this file! The ROM file and patch file must share the same name, so use pokecrystal11.patch together with pokecrystal11.gbc.
|
||||
|
||||
|
||||
## Custom files
|
||||
|
||||
There are a few files involved with building the `.patch` file, in addition to the ones used for building ROMs.
|
||||
|
||||
|
||||
### vc/pokecrystal11.patch.template
|
||||
|
||||
The `.patch.template` file is the basis for the `.patch` file. Many numeric values in the `.patch` file are derived from the values of labels, constants, and ROM content; these values are abstracted into *commands* that get evaluated by `tools/make_patch` to output symbolic names as their actual values, formatted to match the original `.patch` file.
|
||||
|
||||
|
||||
### vc/pokecrystal11.constants.asm
|
||||
|
||||
The `.constants.asm` file is used to create a `.constants.sym` file. Typical `.sym` files only list the values of *labels* (ROM banks and addresses); this file is used to list *constants* that are needed by the `.patch.template`. Any constants that the `.patch.template` refers to must be explicitly printed here with the `vc_const` macro.
|
||||
|
||||
|
||||
### tools/make_patch.c
|
||||
|
||||
The program used to convert a `.patch.template` into a `.patch` file.
|
||||
|
||||
To convert `vc.patch.template` into `vc.patch`:
|
||||
|
||||
```bash
|
||||
tools/make_patch labels.sym constants.sym patched.gbc original.gbc vc.patch.template vc.patch
|
||||
```
|
||||
|
||||
For example, this is what `make crystal11_vc` does:
|
||||
|
||||
```bash
|
||||
tools/make_patch pokecrystal11_vc.sym vc/pokecrystal11.constants.sym pokecrystal11_vc.gbc pokecrystal11.gbc vc/pokecrystal11.patch.template pokecrystal11.patch
|
||||
```
|
||||
|
||||
|
||||
## Patch types
|
||||
|
||||
**Hooks** do not directly modify the ROM; they just identify locations within the ROM code. When the emulated code execution reaches a hook, the emulator performs an emulation function. For example, the `Enable_GS_Ball_mobile_event` hook is located after the code to add a new Hall of Fame entry, and causes the emulator to edit the save file to enable the GS Ball event.
|
||||
|
||||
Hooks are defined with the `vc_hook` macro, which defines a label starting with "`.VC_`" for the patch template file to use.
|
||||
|
||||
**Patches** directly modify the contents of the ROM. This is done before emulation begins. For example, the `print_forbid_1` patch modifies an "`and A_BUTTON`" instruction to "`and 0`", so pressing A will not print Unown on the Game Boy Printer.
|
||||
|
||||
Patches are defined with the `vc_patch` and `vc_patch_end` macros; `vc_patch` defines a label starting with "`.VC_`", `vc_patch_end` defines a corresponding label with "`_End`" appended. Between these two macros, the code or data is conditionally different depending on whether or not a patch file is being built.
|
||||
|
||||
The sole purpose of creating `pokecrystal11_vc.gbc` and `pokecrystal11_vc.sym` is to make these labels and modifications available to `make_patch` for use in the patch template.
|
||||
|
||||
|
||||
## Patch template syntax
|
||||
|
||||
**Comments** start at a semicolon "`;`" and continue until the end of the line. They are output as-is, without interpreting commands.
|
||||
|
||||
**Patch names** are contained in "`[`" brackets "`]`". They are output as-is, without interpreting commands.
|
||||
|
||||
Patch names also set the **current patch label**. This is the label starting with "`.VC_`" followed by the patch name, with any invalid characters (not letters "`A-Z`", digits "`0-9`", or underscore "`_`") converted to underscores "`_`". These labels are conditionally defined only when building the patch file with the `vc_hook` and `vc_patch` macros. For example, the patch name "`[fight begin]`" corresponds to the patch label "`.VC_fight_begin`", generated by the "`vc_hook fight_begin`" macro.
|
||||
|
||||
Patch names may designate an alternate for the label with an at-sign "`@`". This allows the label in the assembly source to have a more descriptive name, while still reproducing the original `.patch` file. For example, the patch name "`[BiographySave_ret@Enable_GS_Ball_mobile_event]`" corresponds to the label "`.VC_Enable_GS_Ball_mobile_event`" but is output as "`[BiographySave_ret]`".
|
||||
|
||||
**Commands** are contained in "`{`" braces "`}`". They are not output themselves, but may produce their own output when interpreted.
|
||||
|
||||
Commands are interpreted with a series of arguments, separated by whitespace (spaces, tabs, or newlines). Leading and trailing whitespace is ignored; for example, "`{ hex @ 4 }`" is interpreted the same as "`{hex @ 4}`".
|
||||
|
||||
Command names have variants to allow reproducing the exact formatting in a `.patch` file. If the command name is all lowercase, the output byte values use lowercase for hexadecimal digits A-F; if it is all uppercase, they use uppercase.
|
||||
|
||||
Some commands may output a **value series**, which is a series of two-digit hexadecimal bytes separated by spaces, preceded by a decimal count and a colon "`:`": "<code>a*N*: <i>v1</i> <i>v2</i> [...] <i>vN</i></code>". These commands have additional variants: if the command name ends in a slash "`/`", the count and colon are not output; or else, if it ends in an underscore "`_`", a space is output after the colon; otherwise, the count and colon are output without a space.
|
||||
|
||||
**Arguments** evaluate to numeric values. They may be any of the following:
|
||||
|
||||
- Literal numbers in decimal (base 10, e.g. "`42`"), hexadecimal (base 16, e.g. "`0x2a`"), or octal (base 8, e.g. "`052`"). They may start with a plus sign "`+`". Numbers should not be negative.
|
||||
- Comparison operators: "`==`" is 0, "`>`" is 1, "`<`" is 2, "`>=`" is 3, "`<=`" is 4, "`!=`" is 5, and "`||`" is 0x11.
|
||||
- Symbol names from the two `.sym` files provided to `make_patch` may evaluate as their relative address or their absolute offset, depending on the command. (Addresses are relative to the symbol's bank for ROM addresses, or to 0x8000, the start of all RAM, for RAM addresses.) They may also be followed by a plus sign and a literal number that gets added to the value.
|
||||
- "`@`" evaluates as the address or absolute offset of the current patch/hook label, depending on the command.
|
||||
|
||||
Any other characters are output as-is.
|
||||
|
||||
|
||||
## Patch template commands
|
||||
|
||||
|
||||
### <code>{patch[ <i>offset</i>[ <i>length</i>]]}</code>
|
||||
|
||||
Outputs the bytes of the current patch as a value series, or as a hexadecimal number if there is only one byte. The bytes are found between the current patch label, and the label which is the current patch label plus "`_End`". An optional first argument is an *offset* to add to the current patch label before gathering the contents between it and the end label. An optional second argument is a *length* of bytes to output instead of the length between the start and end labels.
|
||||
|
||||
For example, if "`{patch}`" outputs "`a3:ab cd ef`", then "`{patch +1}`" outputs "`a2:cd ef`", and "`{patch 0 1}`" outputs "`0xab`".
|
||||
|
||||
Converting the patch template will print a warning if any differences exist between the original and patched ROMs, which are not covered by "`patch`" commands.
|
||||
|
||||
|
||||
### <code>{dws <i>args</i>...}</code>
|
||||
|
||||
Outputs its arguments as a value series of little-endian 16-bit words. Symbol names or "`@`" are evaluated as their relative address.
|
||||
|
||||
For example, if "`{dws 42 0xabcd wCurSpecies}`" outputs "`a6:2a 00 cd ab 60 cf`", then "`{dws >= wCurSpecies+3}`" outputs "`a4:04 00 63 cf`".
|
||||
|
||||
|
||||
### <code>{db <i>arg</i>}</code>
|
||||
|
||||
Outputs its argument as a single-byte value series. Symbol names or "`@`" are evaluated as their relative address.
|
||||
|
||||
For example, "`{db 0xEF}`" outputs "`a1:ef`".
|
||||
|
||||
|
||||
### <code>{hex <i>arg</i>[ <i>padding</i>]}</code>
|
||||
|
||||
Outputs its first argument as a hexadecimal number. An optional second argument is the minimum length in digits; values shorter than it will be padded with leading zeros. Symbol names or "`@`" are evaluated as their absolute offset, or as their relative address if the command name ends in a tilde "`~`".
|
||||
|
||||
For example, if "`{hex @}`" outputs "`0x6789`", then "`{hex @+1 5}`" outputs "`0x0678a`".
|
||||
|
||||
This command has extra variants to reproduce inconsistent output casing: "`Hex`" prints the last three digits in lowercase and the rest uppercase; "`HEx`" prints the last two digits in lowercase and the rest uppercase; "`hEX`" prints the last three digits in uppercase and the rest lowercase; and "`heX`" prints the last two digits in uppercase and the rest lowercase.
|
||||
Loading…
Add table
Add a link
Reference in a new issue