diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/assembly_programming.md | 15 | ||||
-rw-r--r-- | docs/bugs_and_glitches.md | 1455 | ||||
-rw-r--r-- | docs/effect_commands.md | 358 | ||||
-rw-r--r-- | docs/event_commands.md | 348 | ||||
-rw-r--r-- | docs/images/hp_exp_bar_border.png | bin | 0 -> 125 bytes | |||
-rw-r--r-- | docs/images/hp_exp_bar_border_fix.png | bin | 0 -> 124 bytes | |||
-rw-r--r-- | docs/images/port.png | bin | 0 -> 1055 bytes | |||
-rw-r--r-- | docs/images/port_fix.png | bin | 0 -> 1056 bytes | |||
-rw-r--r-- | docs/map_scripts.md | 139 | ||||
-rw-r--r-- | docs/move_anim_commands.md | 102 | ||||
-rw-r--r-- | docs/movement_commands.md | 84 | ||||
-rw-r--r-- | docs/music_commands.md | 96 | ||||
-rw-r--r-- | docs/pic_animations.md | 31 | ||||
-rw-r--r-- | docs/text_commands.md | 164 |
14 files changed, 2792 insertions, 0 deletions
diff --git a/docs/assembly_programming.md b/docs/assembly_programming.md new file mode 100644 index 000000000..c04710b05 --- /dev/null +++ b/docs/assembly_programming.md @@ -0,0 +1,15 @@ +# Assembly Programming + +- [**RGBDS documentation**](rgbds-doc): Includes information on the RGBDS tools and the assembly language syntax. +- [**Pan Docs**](pan-docs): Everything You Always Wanted To Know About GAMEBOY (but were afraid to ask). +- [**GameBoy Programming Manual](gb-manual): The official GameBoy programming and hardware manual by Nintendo. +- [**GameBoy Opcode Summary**](gb-opcodes): Describes the opcodes of GameBoy assembly language. +- [**GameBoy Memory Map**](gb-memory-map): Describes the GameBoy Color address space. +- [**awesome-gbdev**](awesome-gbdev): A curated list of Game Boy development resources such as tools, docs, emulators, related projects and open-source ROMs. + +[rgbds-doc]: https://rednex.github.io/ +[pan-docs]: http://bgb.bircd.org/pandocs.htm +[gb-manual]: https://ia801906.us.archive.org/19/items/GameBoyProgManVer1.1/GameBoyProgManVer1.1.pdf +[gb-opcodes]: http://www.devrs.com/gb/files/opcodes.html +[gb-memory-map]: http://gameboy.mongenel.com/dmg/asmmemmap.html +[awesome-gbdev]: https://github.com/avivace/awesome-gbdev diff --git a/docs/bugs_and_glitches.md b/docs/bugs_and_glitches.md new file mode 100644 index 000000000..b38ec12ee --- /dev/null +++ b/docs/bugs_and_glitches.md @@ -0,0 +1,1455 @@ +# Bugs and Glitches + + +## Contents + +- [Thick Club and Light Ball can decrease damage done with boosted (Special) Attack](#thick-club-and-light-ball-can-decrease-damage-done-with-boosted-special-attack) +- [Metal Powder can increase damage taken with boosted (Special) Defense](#metal-powder-can-increase-damage-taken-with-boosted-special-defense) +- [Belly Drum sharply boosts Attack even with under 50% HP](#belly-drum-sharply-boosts-attack-even-with-under-50-hp) +- [Moves that lower Defense can do so after breaking a Substitute](#moves-that-lower-defense-can-do-so-after-breaking-a-substitute) +- [Counter and Mirror Coat still work if the opponent uses an item](#counter-and-mirror-coat-still-work-if-the-opponent-uses-an-item) +- [A Disabled but PP Up–enhanced move may not trigger Struggle](#a-disabled-but-pp-upenhanced-move-may-not-trigger-struggle) +- [A Pokémon that fainted from Pursuit will have its old status condition when revived](#a-pokémon-that-fainted-from-pursuit-will-have-its-old-status-condition-when-revived) +- [Lock-On and Mind Reader don't always bypass Fly and Dig](#lock-on-and-mind-reader-dont-always-bypass-fly-and-dig) +- [Beat Up can desynchronize link battles](#beat-up-can-desynchronize-link-battles) +- [Present damage is incorrect in link battles](#present-damage-is-incorrect-in-link-battles) +- ["Smart" AI encourages Mean Look if its own Pokémon is badly poisoned](#smart-ai-encourages-mean-look-if-its-own-pokémon-is-badly-poisoned) +- [AI makes a false assumption about `CheckTypeMatchup`](#ai-makes-a-false-assumption-about-checktypematchup) +- [NPC use of Full Heal or Full Restore does not cure Nightmare status](#npc-use-of-full-heal-or-full-restore-does-not-cure-nightmare-status) +- [HP bar animation is slow for high HP](#hp-bar-animation-is-slow-for-high-hp) +- [HP bar animation off-by-one error for low HP](#hp-bar-animation-off-by-one-error-for-low-hp) +- [Experience underflow for level 1 Pokémon with Medium-Slow growth rate](#experience-underflow-for-level-1-pokémon-with-medium-slow-growth-rate) +- [Five-digit experience gain is printed incorrectly](#five-digit-experience-gain-is-printed-incorrectly) +- [BRN/PSN/PAR do not affect catch rate](#brnpsnpar-do-not-affect-catch-rate) +- [Moon Ball does not boost catch rate](#moon-ball-does-not-boost-catch-rate) +- [Love Ball boosts catch rate for the wrong gender](#love-ball-boosts-catch-rate-for-the-wrong-gender) +- [Fast Ball only boosts catch rate for three Pokémon](#fast-ball-only-boosts-catch-rate-for-three-pokémon) +- [Dragon Scale, not Dragon Fang, boosts Dragon-type moves](#dragon-scale-not-dragon-fang-boosts-dragon-type-moves) +- [Daisy's grooming doesn't always increase happiness](#daisys-grooming-doesnt-always-increase-happiness) +- [Magikarp in Lake of Rage are shorter, not longer](#magikarp-in-lake-of-rage-are-shorter-not-longer) +- [Magikarp lengths can be miscalculated](#magikarp-lengths-can-be-miscalculated) +- [Battle transitions fail to account for the enemy's level](#battle-transitions-fail-to-account-for-the-enemys-level) +- [Slot machine payout sound effects cut each other off](#slot-machine-payout-sound-effects-cut-each-other-off) +- [Team Rocket battle music is not used for Executives or Scientists](#team-rocket-battle-music-is-not-used-for-executives-or-scientists) +- [No bump noise if standing on tile `$3E`](#no-bump-noise-if-standing-on-tile-3e) +- [Playing Entei's Pokédex cry can distort Raikou's and Suicune's](#playing-enteis-pokédex-cry-can-distort-raikous-and-suicunes) +- [In-battle “`…`” ellipsis is too high](#in-battle--ellipsis-is-too-high) +- [Two tiles in the `port` tileset are drawn incorrectly](#two-tiles-in-the-port-tileset-are-drawn-incorrectly) +- [`LoadMetatiles` wraps around past 128 blocks](#loadmetatiles-wraps-around-past-128-blocks) +- [Surfing directly across a map connection does not load the new map](#surfing-directly-across-a-map-connection-does-not-load-the-new-map) +- [`Function6ec1` does not correctly limit object movement](#function6ec1-does-not-correctly-limit-object-movement) +- [`CheckOwnMon` only checks the first five letters of OT names](#checkownmon-only-checks-the-first-five-letters-of-ot-names) +- [Catching a Transformed Pokémon always catches a Ditto](#catching-a-transformed-pokémon-always-catches-a-ditto) +- [Using a Park Ball in normal battles has a corrupt animation](#using-a-park-ball-in-normal-battles-has-a-corrupt-animation) +- [`HELD_CATCH_CHANCE` has no effect](#held_catch_chance-has-no-effect) +- [Only the first three `EvosAttacks` evolution entries can have Stone compatibility reported correctly](#only-the-first-three-evosattacks-evolution-entries-can-have-stone-compatibility-reported-correctly) +- [`ScriptCall` can overflow `wScriptStack` and crash](#scriptcall-can-overflow-wscriptstack-and-crash) +- [`LoadSpriteGFX` does not limit the capacity of `UsedSprites`](#loadspritegfx-does-not-limit-the-capacity-of-usedsprites) +- [`ChooseWildEncounter` doesn't really validate the wild Pokémon species](#choosewildencounter-doesnt-really-validate-the-wild-pokémon-species) +- [`TryObjectEvent` arbitrary code execution](#tryobjectevent-arbitrary-code-execution) +- [`Special_CheckBugContestContestantFlag` can read beyond its data table](#special_checkbugcontestcontestantflag-can-read-beyond-its-data-table) +- [`ClearWRAM` only clears WRAM bank 1](#clearwram-only-clears-wram-bank-1) +- [`GetForestTreeFrame` works, but it's still bad](#getforesttreeframe-works-but-its-still-bad) + + +## Thick Club and Light Ball can decrease damage done with boosted (Special) Attack + +([Video](https://www.youtube.com/watch?v=rGqu3d3pdok&t=450)) + +This is a bug with `SpeciesItemBoost` in [battle/effect_commands.asm](/battle/effect_commands.asm): + +```asm +; Double the stat + sla l + rl h + ret +``` + +**Fix:** + +```asm +; Double the stat + sla l + rl h + + ld a, 999 / $100 + cp h + jr c, .cap + ld a, 999 % $100 + cp l + ret nc + +.cap + ld h, 999 / $100 + ld l, 999 % $100 + ret +``` + + +## Metal Powder can increase damage taken with boosted (Special) Defense + +([Video](https://www.youtube.com/watch?v=rGqu3d3pdok&t=450)) + +This is a bug with `DittoMetalPowder` in [battle/effect_commands.asm](/battle/effect_commands.asm): + +```asm + ld a, c + srl a + add c + ld c, a + ret nc + + srl b + ld a, b + and a + jr nz, .done + inc b +.done + scf + rr c + ret +``` + +**Fix:** + +```asm + ld a, c + srl a + add c + ld c, a + ret nc + + srl b + ld a, b + and a + jr nz, .done + inc b +.done + scf + rr c + + ld a, 999 / $100 + cp b + jr c, .cap + ld a, 999 % $100 + cp c + ret nc + +.cap + ld b, 999 / $100 + ld c, 999 % $100 + ret +``` + + +## Belly Drum sharply boosts Attack even with under 50% HP + +([Video](https://www.youtube.com/watch?v=zuCLMikWo4Y)) + +This is a bug with `BattleCommand_BellyDrum` in [battle/effect_commands.asm](/battle/effect_commands.asm): + +```asm +BattleCommand_BellyDrum: ; 37c1a +; bellydrum +; This command is buggy because it raises the user's attack +; before checking that it has enough HP to use the move. +; Swap the order of these two blocks to fix. + call BattleCommand_AttackUp2 + ld a, [AttackMissed] + and a + jr nz, .failed + + callab GetHalfMaxHP + callab CheckUserHasEnoughHP + jr nc, .failed +``` + +**Fix:** + +```asm +BattleCommand_BellyDrum: ; 37c1a +; bellydrum + callab GetHalfMaxHP + callab CheckUserHasEnoughHP + jr nc, .failed + + call BattleCommand_AttackUp2 + ld a, [AttackMissed] + and a + jr nz, .failed +``` + + +## Moves that lower Defense can do so after breaking a Substitute + +([Video](https://www.youtube.com/watch?v=OGwKPRJLaaI)) + +This bug affects Acid, Iron Tail, and Rock Smash. + +This is a bug with `DefenseDownHit` in [battle/moves/move_effects.asm](/battle/moves/move_effects.asm): + +```asm +DefenseDownHit: + checkobedience + usedmovetext + doturn + critical + damagestats + damagecalc + stab + damagevariation + checkhit + effectchance + hittarget + failuretext + checkfaint + criticaltext + supereffectivetext + checkdestinybond + buildopponentrage + effectchance ; bug: duplicate effectchance shouldn't be here + defensedown + statdownmessage + endmove +``` + +**Fix:** Delete the second `effectchance`. + + +## Counter and Mirror Coat still work if the opponent uses an item + +([Video](https://www.youtube.com/watch?v=uRYyzKRatFk)) + +*To do:* Identify specific code causing this bug and fix it. + + +## A Disabled but PP Up–enhanced move may not trigger Struggle + +([Video](https://www.youtube.com/watch?v=1v9x4SgMggs)) + +This is a bug with `CheckPlayerHasUsableMoves` in [battle/core.asm](/battle/core.asm): + +```asm +.done + ; Bug: this will result in a move with PP Up confusing the game. + ; Replace with "and $3f" to fix. + and a + ret nz + +.force_struggle + ld hl, BattleText_PkmnHasNoMovesLeft + call StdBattleTextBox + ld c, 60 + call DelayFrames + xor a + ret +``` + +**Fix:** Change `and a` to `and $3f`. + + +## A Pokémon that fainted from Pursuit will have its old status condition when revived + +([Video](https://www.youtube.com/watch?v=tiRvw-Nb2ME)) + +*To do:* Identify specific code causing this bug and fix it. + + +## Lock-On and Mind Reader don't always bypass Fly and Dig + +This bug affects Attract, Curse, Foresight, Mean Look, Mimic, Nightmare, Spider Web, Transform, and stat-lowering effects of moves like String Shot or Bubble during the semi-invulnerable turn of Fly or Dig. + +This is a bug with `CheckHiddenOpponent` in [battle/effect_commands.asm](/battle/effect_commands.asm): + +```asm +CheckHiddenOpponent: ; 37daa +; BUG: This routine should account for Lock-On and Mind Reader. + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret +``` + +*To do:* Fix this bug. + + +## Beat Up can desynchronize link battles + +([Video](https://www.youtube.com/watch?v=202-iAsrIa8)) + +This is a bug with `BattleCommand_BeatUp` in [battle/effect_commands.asm](/battle/effect_commands.asm): + +```asm +.got_mon + ld a, [wd002] + ld hl, PartyMonNicknames + call GetNick + ld a, MON_HP + call GetBeatupMonLocation + ld a, [hli] + or [hl] + jp z, .beatup_fail ; fainted + ld a, [wd002] + ld c, a + ld a, [CurBattleMon] + ; BUG: this can desynchronize link battles + ; Change "cp [hl]" to "cp c" to fix + cp [hl] + ld hl, BattleMonStatus + jr z, .active_mon + ld a, MON_STATUS + call GetBeatupMonLocation +.active_mon + ld a, [hl] + and a + jp nz, .beatup_fail +``` + +**Fix:** Change `cp [hl]` to `cp c`. + + +## Present damage is incorrect in link battles + +([Video](https://www.youtube.com/watch?v=XJaQoKtrEuw)) + +This bug existed for all battles in Gold and Silver, and was only fixed for single-player battles in Crystal to preserve link compatibility. + +This is a bug with `BattleCommand_Present` in [battle/effects/present.asm](/battle/effects/present.asm): + +```asm +BattleCommand_Present: ; 37874 +; present + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .colosseum_skippush + push bc + push de +.colosseum_skippush + + call BattleCommand_Stab + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .colosseum_skippop + pop de + pop bc +.colosseum_skippop +``` + +**Fix:** + +```asm +BattleCommand_Present: ; 37874 +; present + + push bc + push de + call BattleCommand_Stab + pop de + pop bc +``` + + +## "Smart" AI encourages Mean Look if its own Pokémon is badly poisoned + +([Video](https://www.youtube.com/watch?v=cygMO-zHTls)) + +This is a bug with `AI_Smart_MeanLook` in [battle/ai/scoring.asm](/battle/ai/scoring.asm): + +```asm +; 80% chance to greatly encourage this move if the enemy is badly poisoned (buggy). +; Should check PlayerSubStatus5 instead. + ld a, [EnemySubStatus5] + bit SUBSTATUS_TOXIC, a + jr nz, .asm_38e26 +``` + +**Fix:** Change `EnemySubStatus5` to `PlayerSubStatus5`. + + +## AI makes a false assumption about `CheckTypeMatchup` + +In [battle/effect_commands.asm](/battle/effect_commands.asm): + +```asm +BattleCheckTypeMatchup: ; 347c8 + ld hl, EnemyMonType1 + ld a, [hBattleTurn] + and a + jr z, CheckTypeMatchup + ld hl, BattleMonType1 +CheckTypeMatchup: ; 347d3 +; There is an incorrect assumption about this function made in the AI related code: when +; the AI calls CheckTypeMatchup (not BattleCheckTypeMatchup), it assumes that placing the +; offensive type in a will make this function do the right thing. Since a is overwritten, +; this assumption is incorrect. A simple fix would be to load the move type for the +; current move into a in BattleCheckTypeMatchup, before falling through, which is +; consistent with how the rest of the code assumes this code works like. + push hl + push de + push bc + ld a, BATTLE_VARS_MOVE_TYPE + call GetBattleVar + ld d, a +``` + +*To do:* Fix this bug. + + +## NPC use of Full Heal or Full Restore does not cure Nightmare status + +([Video](https://www.youtube.com/watch?v=rGqu3d3pdok&t=322)) + +This is a bug with `AI_HealStatus` in [battle/ai/items.asm](/battle/ai/items.asm): + +```asm +AI_HealStatus: ; 384e0 + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + ld bc, PARTYMON_STRUCT_LENGTH + call AddNTimes + xor a + ld [hl], a + ld [EnemyMonStatus], a + ; Bug: this should reset SUBSTATUS_NIGHTMARE too + ; Uncomment the lines below to fix + ; ld hl, EnemySubStatus1 + ; res SUBSTATUS_NIGHTMARE, [hl] + ld hl, EnemySubStatus5 + res SUBSTATUS_TOXIC, [hl] + ret +; 384f7 +``` + +**Fix:** Uncomment `ld hl, EnemySubStatus1` and `res SUBSTATUS_NIGHTMARE, [hl]`. + + +## HP bar animation is slow for high HP + +([Video](https://www.youtube.com/watch?v=SE-BfsFgZVM)) + +This is a bug with `LongAnim_UpdateVariables` in [engine/anim_hp_bar.asm](/engine/anim_hp_bar.asm): + +```asm + ; This routine is buggy. The result from ComputeHPBarPixels is stored + ; in e. However, the pop de opcode deletes this result before it is even + ; used. The game then proceeds as though it never deleted that output. + ; To fix, uncomment the line below. + call ComputeHPBarPixels + ; ld a, e + pop bc + pop de + pop hl + ld a, e ; Comment or delete this line to fix the above bug. + ld hl, wCurHPBarPixels + cp [hl] + jr z, .loop + ld [hl], a + and a + ret +``` + +**Fix:** Move `ld a, e` to right after `call ComputeHPBarPixels`. + + +## HP bar animation off-by-one error for low HP + +([Video](https://www.youtube.com/watch?v=9KyNVIZxJvI)) + +This is a bug with `ShortHPBar_CalcPixelFrame` in [engine/anim_hp_bar.asm](/engine/anim_hp_bar.asm): + +```asm + ld b, 0 +; This routine is buggy. If [wCurHPAnimMaxHP] * [wCurHPBarPixels] is divisible +; by 48, the loop runs one extra time. To fix, uncomment the line below. +.loop + ld a, l + sub 6 * 8 + ld l, a + ld a, h + sbc $0 + ld h, a + ; jr z, .done + jr c, .done + inc b + jr .loop +``` + +**Fix:** Uncomment `jr z, .done`. + + +## Experience underflow for level 1 Pokémon with Medium-Slow growth rate + +([Video](https://www.youtube.com/watch?v=SXH8u0plHrE)) + +This can bring Pokémon straight from level 1 to 100 by gaining just a few experience points. + +This is a bug with `CalcExpAtLevel` in [main.asm](/main.asm): + +```asm +CalcExpAtLevel: ; 50e47 +; (a/b)*n**3 + c*n**2 + d*n - e + ld a, [BaseGrowthRate] + add a + add a + ld c, a + ld b, 0 + ld hl, GrowthRates + add hl, bc +``` + +**Fix:** + +```asm +CalcExpAtLevel: ; 50e47 +; (a/b)*n**3 + c*n**2 + d*n - e + ld a, d + cp 1 + jr nz, .UseExpFormula +; Pokémon have 0 experience at level 1 + xor a + ld hl, hProduct + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ret + +.UseExpFormula + ld a, [BaseGrowthRate] + add a + add a + ld c, a + ld b, 0 + ld hl, GrowthRates + add hl, bc +``` + + +## Five-digit experience gain is printed incorrectly + +([Video](https://www.youtube.com/watch?v=o54VjpAEoO8)) + +This is a bug with `Text_ABoostedStringBuffer2ExpPoints` and `Text_StringBuffer2ExpPoints` in [text/common_2.asm](/text/common_2.asm): + +```asm +Text_ABoostedStringBuffer2ExpPoints:: + text "" + line "a boosted" + cont "@" + deciram StringBuffer2, 2, 4 + text " EXP. Points!" + prompt + +Text_StringBuffer2ExpPoints:: + text "" + line "@" + deciram StringBuffer2, 2, 4 + text " EXP. Points!" + prompt +``` + +**Fix:** Change both `deciram StringBuffer2, 2, 4` to `deciram StringBuffer2, 2, 5`. + + +## BRN/PSN/PAR do not affect catch rate + +This is a bug with `PokeBall` in [items/item_effects.asm](/items/item_effects.asm): + +```asm +.statuscheck +; This routine is buggy. It was intended that SLP and FRZ provide a higher +; catch rate than BRN/PSN/PAR, which in turn provide a higher catch rate than +; no status effect at all. But instead, it makes BRN/PSN/PAR provide no +; benefit. +; Uncomment the line below to fix this. + ld b, a + ld a, [EnemyMonStatus] + and 1 << FRZ | SLP + ld c, 10 + jr nz, .addstatus + ; ld a, [EnemyMonStatus] + and a + ld c, 5 + jr nz, .addstatus + ld c, 0 +.addstatus + ld a, b + add c + jr nc, .max_1 + ld a, $ff +.max_1 +``` + +**Fix:** Uncomment `ld a, [EnemyMonStatus]`. + + +## Moon Ball does not boost catch rate + +This is a bug with `MoonBallMultiplier` in [items/item_effects.asm](/items/item_effects.asm): + +```asm +MoonBallMultiplier: +; This function is buggy. +; Intent: multiply catch rate by 4 if mon evolves with moon stone +; Reality: no boost + +... + +; Moon Stone's constant from Pokémon Red is used. +; No Pokémon evolve with Burn Heal, +; so Moon Balls always have a catch rate of 1×. + push bc + ld a, BANK(EvosAttacks) + call GetFarByte + cp MOON_STONE_RED ; BURN_HEAL + pop bc + ret nz +``` + +**Fix:** Change `MOON_STONE_RED` to `MOON_STONE`. + + +## Love Ball boosts catch rate for the wrong gender + +This is a bug with `LoveBallMultiplier` in [items/item_effects.asm](/items/item_effects.asm): + +```asm +LoveBallMultiplier: +; This function is buggy. +; Intent: multiply catch rate by 8 if mons are of same species, different sex +; Reality: multiply catch rate by 8 if mons are of same species, same sex + +... + + ld a, d + pop de + cp d + pop bc + ret nz ; for the intended effect, this should be "ret z" +``` + +**Fix:** Change `ret nz` to `ret z`. + + +## Fast Ball only boosts catch rate for three Pokémon + +This is a bug with `FastBallMultiplier` in [items/item_effects.asm](/items/item_effects.asm): + +```asm +FastBallMultiplier: +; This function is buggy. +; Intent: multiply catch rate by 4 if enemy mon is in one of the three +; FleeMons tables. +; Reality: multiply catch rate by 4 if enemy mon is one of the first three in +; the first FleeMons table. + +... + + inc hl + cp -1 + jr z, .next + cp c + jr nz, .next ; for the intended effect, this should be "jr nz, .loop" + sla b + jr c, .max +``` + +**Fix:** Change `jr nz, .next` to `jr nz, .loop`. + + +## Dragon Scale, not Dragon Fang, boosts Dragon-type moves + +This is a bug with `ItemAttributes` in [items/item_attributes.asm](/items/item_attributes.asm): + +```asm +; DRAGON FANG + item_attribute 100, 0, 0, CANT_SELECT, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE + +... + +; DRAGON SCALE + item_attribute 2100, HELD_DRAGON_BOOST, 10, CANT_SELECT, ITEM, ITEMMENU_NOUSE, ITEMMENU_NOUSE +``` + +**Fix:** Move `HELD_DRAGON_BOOST` to the `DRAGON FANG` attributes and `0` to `DRAGON SCALE`. + + +## Daisy's grooming doesn't always increase happiness + +This is a bug with `MassageOrHaircut` in [event/special.asm](/event/special.asm): + +```asm +; Bug: Subtracting $ff from $ff fails to set c. +; This can result in overflow into the next data array. +; In the case of getting a massage from Daisy, we bleed +; into CopyPokemonName_Buffer1_Buffer3, which passes +; $d0 to ChangeHappiness and returns $73 to the script. +; The end result is that there is a 0.4% chance your +; Pokemon's happiness will not change at all. +.loop + sub [hl] + jr c, .ok + inc hl + inc hl + inc hl + jr .loop + +.ok + inc hl + ld a, [hli] + ld [ScriptVar], a + ld c, [hl] + call ChangeHappiness + ret + +... + +Data_DaisyMassage: ; 746b + db $ff, 2, HAPPINESS_MASSAGE ; 99.6% chance + +CopyPokemonName_Buffer1_Buffer3: ; 746e + ld hl, StringBuffer1 + ld de, StringBuffer3 + ld bc, PKMN_NAME_LENGTH + jp CopyBytes +``` + +**Fix:** + +```asm +Data_DaisyMassage: ; 746b + db $80, 2, HAPPINESS_MASSAGE ; 50% chance + db $ff, 2, HAPPINESS_MASSAGE ; 50% chance +``` + + +## Magikarp in Lake of Rage are shorter, not longer + +This is a bug with `LoadEnemyMon.CheckMagikarpArea` in [battle/core.asm](/battle/core.asm): + +```asm +.CheckMagikarpArea: +; The z checks are supposed to be nz +; Instead, all maps in GROUP_LAKE_OF_RAGE (mahogany area) +; and routes 20 and 44 are treated as Lake of Rage + +; This also means Lake of Rage Magikarp can be smaller than ones +; caught elsewhere rather than the other way around + +; Intended behavior enforces a minimum size at Lake of Rage +; The real behavior prevents size flooring in the Lake of Rage area + ld a, [MapGroup] + cp GROUP_LAKE_OF_RAGE + jr z, .Happiness + ld a, [MapNumber] + cp MAP_LAKE_OF_RAGE + jr z, .Happiness +``` + +**Fix:** Change both `jr z, .Happiness` to `jr nz, .Happiness`. + + +## Magikarp lengths can be miscalculated + +This is a bug with `CalcMagikarpLength.BCLessThanDE` in [event/magikarp.asm](/event/magikarp.asm): + +```asm +.BCLessThanDE: ; fbc9a +; Intention: Return bc < de. +; Reality: Return b < d. + ld a, b + cp d + ret c + ret nc ; whoops + ld a, c + cp e + ret +; fbca1 +``` + +**Fix:** Delete `ret nc`. + + +## Battle transitions fail to account for the enemy's level + +([Video](https://www.youtube.com/watch?v=eij_1060SMc)) + +This is a bug with `StartTrainerBattle_DetermineWhichAnimation` in [engine/battle_start.asm](/engine/battle_start.asm): + +```asm +StartTrainerBattle_DetermineWhichAnimation: ; 8c365 (23:4365) +; The screen flashes a different number of times depending on the level of +; your lead Pokemon relative to the opponent's. +; BUG: BattleMonLevel and EnemyMonLevel are not set at this point, so whatever +; values happen to be there will determine the animation. + ld de, 0 + ld a, [BattleMonLevel] + add 3 + ld hl, EnemyMonLevel + cp [hl] + jr nc, .okay + set 0, e +.okay + ld a, [wPermission] + cp CAVE + jr z, .okay2 + cp PERM_5 + jr z, .okay2 + cp DUNGEON + jr z, .okay2 + set 1, e +.okay2 + ld hl, .StartingPoints + add hl, de + ld a, [hl] + ld [wJumptableIndex], a + ret +; 8c38f (23:438f) + +.StartingPoints: ; 8c38f + db 1, 9 + db 16, 24 +; 8c393 +``` + +*To do:* Fix this bug. + + +## Slot machine payout sound effects cut each other off + +([Video](https://www.youtube.com/watch?v=ojq3xqfRF6I)) + +This is a bug with `Slots_PayoutAnim` in [engine/slot_machine.asm](/engine/slot_machine.asm): + +```asm +.okay + ld [hl], e + dec hl + ld [hl], d + ld a, [wcf64] + and $7 + ret z ; ret nz would be more appropriate + ld de, SFX_GET_COIN_FROM_SLOTS + call PlaySFX + ret +``` + +**Fix:** Change `ret z` to `ret nz`. + + +## Team Rocket battle music is not used for Executives or Scientists + +This is a bug with `PlayBattleMusic` in [main.asm](/main.asm): + +```asm + ; really, they should have included admins and scientists here too... + ld de, MUSIC_ROCKET_BATTLE + cp GRUNTM + jr z, .done + cp GRUNTF + jr z, .done +``` + +**Fix:** + +```asm + ld de, MUSIC_ROCKET_BATTLE + cp GRUNTM + jr z, .done + cp GRUNTF + jr z, .done + cp EXECUTIVEM + jr z, .done + cp EXECUTIVEF + jr z, .done + cp SCIENTIST + jr z, .done +``` + + +## No bump noise if standing on tile `$3E` + +This is a bug with `DoPlayerMovement.CheckWarp` in [engine/player_movement.asm](/engine/player_movement.asm): + +```asm +; Bug: Since no case is made for STANDING here, it will check +; [.edgewarps + $ff]. This resolves to $3e at $8035a. +; This causes wd041 to be nonzero when standing on tile $3e, +; making bumps silent. + + ld a, [WalkingDirection] + ; cp STANDING + ; jr z, .not_warp + ld e, a + ld d, 0 + ld hl, .EdgeWarps + add hl, de + ld a, [PlayerStandingTile] + cp [hl] + jr nz, .not_warp + + ld a, 1 + ld [wd041], a + ld a, [WalkingDirection] + ; This is in the wrong place. + cp STANDING + jr z, .not_warp +``` + +**Fix:** + +```asm + ld a, [WalkingDirection] + cp STANDING + jr z, .not_warp + ld e, a + ld d, 0 + ld hl, .EdgeWarps + add hl, de + ld a, [PlayerStandingTile] + cp [hl] + jr nz, .not_warp + + ld a, 1 + ld [wd041], a + ld a, [WalkingDirection] +``` + + +## Playing Entei's Pokédex cry can distort Raikou's and Suicune's + +([Video](https://www.youtube.com/watch?v=z305e4sIO24)) + +The exact cause is unknown, but a workaround exists for `DexEntryScreen_MenuActionJumptable.Cry` in [engine/pokedex.asm](/engine/pokedex.asm): + +```asm +.Cry: ; 40340 + call Pokedex_GetSelectedMon + ld a, [wd265] + call GetCryIndex + ld e, c + ld d, b + call PlayCryHeader + ret +``` + +**Workaround:** + +```asm +.Cry: ; 40340 + ld a, [CurPartySpecies] + call PlayCry + ret +``` + + +## In-battle “`…`” ellipsis is too high + +This is a mistake with the “`…`” tile in [gfx/battle/hp_exp_bar_border.png](/gfx/battle/hp_exp_bar_border.png): + + + +**Fix:** Lower the ellipsis by two pixels: + + + + +## Two tiles in the `port` tileset are drawn incorrectly + +This is a mistake with the left-hand warp carpet corner tiles in [gfx/tilesets/port.png](/gfx/tilesets/port.png): + + + +**Fix:** Adjust them to match the right-hand corner tiles: + + + + +## `LoadMetatiles` wraps around past 128 blocks + +This bug prevents you from using blocksets with more than 128 blocks. + +In [home/map.asm](/home/map.asm): + +```asm + ; Set hl to the address of the current metatile data ([TilesetBlocksAddress] + (a) tiles). + ; This is buggy; it wraps around past 128 blocks. + ; To fix, uncomment the line below. + add a ; Comment or delete this line to fix the above bug. + ld l, a + ld h, 0 + ; add hl, hl + add hl, hl + add hl, hl + add hl, hl + ld a, [TilesetBlocksAddress] + add l + ld l, a + ld a, [TilesetBlocksAddress + 1] + adc h + ld h, a +``` + +**Fix:** Delete `add a` and uncomment `add hl, hl`. + + +## Surfing directly across a map connection does not load the new map + +([Video](https://www.youtube.com/watch?v=XFOWvMNG-zw)) + +*To do:* Identify specific code causing this bug and fix it. + + +## `Function6ec1` does not correctly limit object movement + +This bug is why the Lapras in Union Cave, which uses `SPRITEMOVEDATA_LAPRAS`, is not restricted by its `1, 1` movement radius. + +In [engine/npc_movement.asm](/engine/npc_movement.asm): + +```asm + ld hl, OBJECT_FLAGS1 + add hl, bc + bit 4, [hl] ; lost, uncomment next line to fix +; jr nz, .resume +``` + +**Fix:** Uncomment `jr nz, .resume`. + + +## `CheckOwnMon` only checks the first five letters of OT names + +([Video](https://www.youtube.com/watch?v=GVTTmReM4nQ)) + +This bug can allow you to talk to Eusine in Celadon City and encounter Ho-Oh with only traded legendary beasts. + +In [engine/search.asm](/engine/search.asm): + +```asm +; check OT +; This only checks five characters, which is fine for the Japanese version, +; but in the English version the player name is 7 characters, so this is wrong. + + ld hl, PlayerName + +rept NAME_LENGTH_JAPANESE +- 2 ; should be PLAYER_NAME_LENGTH +- 2 + ld a, [de] + cp [hl] + jr nz, .notfound + cp "@" + jr z, .found ; reached end of string + inc hl + inc de +endr + + ld a, [de] + cp [hl] + jr z, .found + +.notfound + pop de + pop hl + pop bc + and a + ret +``` + +**Fix:** Change `rept NAME_LENGTH_JAPANESE +- 2` to `rept PLAYER_NAME_LENGTH +- 2`. + + +## Catching a Transformed Pokémon always catches a Ditto + +This bug can affect Mew or Pokémon other than Ditto that used Transform via Mirror Move or Sketch. + +This is a bug with `PokeBall` in [items/item_effects.asm](/items/item_effects.asm): + +```asm + ld hl, EnemySubStatus5 + ld a, [hl] + push af + set SUBSTATUS_TRANSFORMED, [hl] + +; This code is buggy. Any wild Pokémon that has Transformed will be +; caught as a Ditto, even if it was something else like Mew. +; To fix, do not set [TempEnemyMonSpecies] to DITTO. + bit SUBSTATUS_TRANSFORMED, a + jr nz, .ditto + jr .not_ditto + +.ditto + ld a, DITTO + ld [TempEnemyMonSpecies], a + jr .load_data + +.not_ditto + set SUBSTATUS_TRANSFORMED, [hl] + ld hl, wEnemyBackupDVs + ld a, [EnemyMonDVs] + ld [hli], a + ld a, [EnemyMonDVs + 1] + ld [hl], a + +.load_data + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld a, [EnemyMonLevel] + ld [CurPartyLevel], a + callba LoadEnemyMon + + pop af + ld [EnemySubStatus5], a +``` + +**Fix:** + +```asm + ld hl, EnemySubStatus5 + ld a, [hl] + push af + set SUBSTATUS_TRANSFORMED, [hl] + + bit SUBSTATUS_TRANSFORMED, a + jr nz, .load_data + + ld hl, wEnemyBackupDVs + ld a, [EnemyMonDVs] + ld [hli], a + ld a, [EnemyMonDVs + 1] + ld [hl], a + +.load_data + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld a, [EnemyMonLevel] + ld [CurPartyLevel], a + callba LoadEnemyMon + + pop af + ld [EnemySubStatus5], a +``` + + +## Using a Park Ball in normal battles has a corrupt animation + +([Video](https://www.youtube.com/watch?v=v1ErZdLCIyU)) + +This is a bug with `ParkBall` in [items/item_effects.asm](/items/item_effects.asm): + +```asm +.room_in_party + xor a + ld [wWildMon], a + ld a, [CurItem] + cp PARK_BALL + call nz, ReturnToBattle_UseBall +``` + +**Fix:** + +```asm +.room_in_party + xor a + ld [wWildMon], a + ld a, [BattleType] + cp BATTLETYPE_CONTEST + call nz, ReturnToBattle_UseBall +``` + + +## `HELD_CATCH_CHANCE` has no effect + +This is a bug with `PokeBall` in [items/item_effects.asm](/items/item_effects.asm): + +```asm + ; BUG: callba overwrites a, + ; and GetItemHeldEffect takes b anyway. + + ; This is probably the reason + ; the HELD_CATCH_CHANCE effect + ; is never used. + + ; Uncomment the line below to fix. + + ld a, [BattleMonItem] +; ld b, a + callba GetItemHeldEffect + ld a, b + cp HELD_CATCH_CHANCE +``` + +**Fix:** Uncomment `ld b, a`. + + +## Only the first three `EvosAttacks` evolution entries can have Stone compatibility reported correctly + +This is a bug with `PlacePartyMonEvoStoneCompatibility.DetermineCompatibility` in [engine/party_menu.asm](/engine/party_menu.asm): + +```asm +.DetermineCompatibility: ; 50268 + ld de, StringBuffer1 + ld a, BANK(EvosAttacksPointers) + ld bc, 2 + call FarCopyBytes + ld hl, StringBuffer1 + ld a, [hli] + ld h, [hl] + ld l, a + ld de, StringBuffer1 + ld a, BANK(EvosAttacks) + ld bc, $a + call FarCopyBytes +``` + +**Fix:** Change `ld bc, $a` to `ld bc, $10` to support up to five Stone entries. + + +## `ScriptCall` can overflow `wScriptStack` and crash + +In [engine/scripting.asm](/engine/scripting.asm): + +```asm +ScriptCall: +; Bug: The script stack has a capacity of 5 scripts, yet there is +; nothing to stop you from pushing a sixth script. The high part +; of the script address can then be overwritten by modifications +; to ScriptDelay, causing the script to return to the rst/interrupt +; space. + + push de + ld hl, wScriptStackSize + ld e, [hl] + inc [hl] + ld d, $0 + ld hl, wScriptStack + add hl, de + add hl, de + add hl, de + pop de + ld a, [ScriptBank] + ld [hli], a + ld a, [ScriptPos] + ld [hli], a + ld a, [ScriptPos + 1] + ld [hl], a + ld a, b + ld [ScriptBank], a + ld a, e + ld [ScriptPos], a + ld a, d + ld [ScriptPos + 1], a + ret +``` + + +## `LoadSpriteGFX` does not limit the capacity of `UsedSprites` + +In [engine/overworld.asm](/engine/overworld.asm): + +```asm +LoadSpriteGFX: ; 14306 +; Bug: b is not preserved, so it's useless as a next count. +; Uncomment the lines below to fix. + + ld hl, UsedSprites + ld b, SPRITE_GFX_LIST_CAPACITY +.loop + ld a, [hli] + and a + jr z, .done + push hl + call .LoadSprite + pop hl + ld [hli], a + dec b + jr nz, .loop + +.done + ret + +.LoadSprite: + ; push bc + call GetSprite + ; pop bc + ld a, l + ret +; 1431e +``` + +**Fix:** Uncomment `push bc` and `pop bc`. + + +## `ChooseWildEncounter` doesn't really validate the wild Pokémon species + +In [engine/wildmons.asm](/engine/wildmons.asm): + +```asm +ChooseWildEncounter: ; 2a14f +... + + ld a, b + ld [CurPartyLevel], a + ld b, [hl] + ; ld a, b + call ValidateTempWildMonSpecies + jr c, .nowildbattle + + ld a, b ; This is in the wrong place. + cp UNOWN + jr nz, .done + +... + +ValidateTempWildMonSpecies: ; 2a4a0 +; Due to a development oversight, this function is called with the wild Pokemon's level, not its species, in a. +``` + +**Fix:** + +```asm + ld a, b + ld [CurPartyLevel], a + ld b, [hl] + ld a, b + call ValidateTempWildMonSpecies + jr c, .nowildbattle + + cp UNOWN + jr nz, .done +``` + +## `TryObjectEvent` arbitrary code execution + +In [engine/events.asm](/engine/events.asm): + +```asm +; Bug: If IsInArray returns nc, data at bc will be executed as code. + push bc + ld de, 3 + ld hl, .pointers + call IsInArray + jr nc, .nope_bugged + pop bc + + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +.nope_bugged + ; pop bc + xor a + ret +``` + +**Fix:** Uncomment `pop bc`. + + +## `Special_CheckBugContestContestantFlag` can read beyond its data table + +In [event/bug_contest_2.asm](/event/bug_contest_2.asm): + +```asm +Special_CheckBugContestContestantFlag: ; 139ed +; Checks the flag of the Bug Catching Contestant whose index is loaded in a. + +; Bug: If a >= 10 when this is called, it will read beyond the table. + + ld hl, BugCatchingContestantEventFlagTable + ld e, a + ld d, 0 + add hl, de + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + ld b, CHECK_FLAG + call EventFlagAction + ret +; 139fe + +BugCatchingContestantEventFlagTable: ; 139fe + dw EVENT_BUG_CATCHING_CONTESTANT_1A + dw EVENT_BUG_CATCHING_CONTESTANT_2A + dw EVENT_BUG_CATCHING_CONTESTANT_3A + dw EVENT_BUG_CATCHING_CONTESTANT_4A + dw EVENT_BUG_CATCHING_CONTESTANT_5A + dw EVENT_BUG_CATCHING_CONTESTANT_6A + dw EVENT_BUG_CATCHING_CONTESTANT_7A + dw EVENT_BUG_CATCHING_CONTESTANT_8A + dw EVENT_BUG_CATCHING_CONTESTANT_9A + dw EVENT_BUG_CATCHING_CONTESTANT_10A +; 13a12 +``` + + +## `ClearWRAM` only clears WRAM bank 1 + +In [home/init.asm](/home/init.asm): + +```asm +ClearWRAM:: ; 25a +; Wipe swappable WRAM banks (1-7) +; Assumes CGB or AGB + + ld a, 1 +.bank_loop + push af + ld [rSVBK], a + xor a + ld hl, $d000 + ld bc, $1000 + call ByteFill + pop af + inc a + cp 8 + jr nc, .bank_loop ; Should be jr c + ret +; 270 +``` + +**Fix:** Change `jr nc, .bank_loop` to `jr c, .bank_loop`. + + +## `GetForestTreeFrame` works, but it's still bad + +In [tilesets/animations.asm](/tilesets/animations.asm): + +```asm +GetForestTreeFrame: ; fc54c +; 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 + ret +; fc56d +``` + +**Fix:** + +```asm +GetForestTreeFrame: ; fc54c +; Return 0 if a is even, or 2 if odd. + and 1 + add a + ret +; fc56d +``` diff --git a/docs/effect_commands.md b/docs/effect_commands.md new file mode 100644 index 000000000..3112950a9 --- /dev/null +++ b/docs/effect_commands.md @@ -0,0 +1,358 @@ +# Effect Commands + +Defined in [macros/scripts/effect_commands.asm](/macros/scripts/effect_commands.asm) and [battle/effect_command_pointers.asm:BattleCommandPointers](/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`: `checkfaint` + +## `$0F`: `criticaltext` + +## `$10`: `supereffectivetext` + +## `$11`: `checkdestinybond` + +## `$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`: `effect0xa5` + +## `$A6`: `raisesubnoanim` + +## `$A7`: `lowersubnoanim` + +## `$A8`: `effect0xa8` + +## `$A9`: `clearmissdamage` + +## `$AA`: `movedelay` + +## `$AB`: `hittarget` + +## `$AC`: `tristatuschance` + +## `$AD`: `supereffectivelooptext` + +## `$AE`: `startloop` + +## `$AF`: `curl` + +## `$FE`: `endturn` + +## `$FF`: `endmove` diff --git a/docs/event_commands.md b/docs/event_commands.md new file mode 100644 index 000000000..151d74b54 --- /dev/null +++ b/docs/event_commands.md @@ -0,0 +1,348 @@ +# Event Commands + +Defined in [macros/scripts/event.asm](/macros/scripts/event.asm) and [engine/scripting.asm:ScriptCommandTable](/engine/scripting.asm). + + +## `$00`: `scall` *script* + +## `$01`: `farscall` *script* + +## `$02`: `ptcall` *script* + +## `$03`: `jump` *script* + +## `$04`: `farjump` *script* + +## `$05`: `ptjump` *script* + +## `$06`: `if_equal` *byte*, *script* + +## `$07`: `if_not_equal` *byte*, *script* + +## `$08`: `iffalse` *script* + +## `$09`: `iftrue` *script* + +## `$0A`: `if_greater_than` *byte*, *script* + +## `$0B`: `if_less_than` *byte*, *script* + +## `$0C`: `jumpstd` *std_script* + +## `$0D`: `callstd` *std_script* + +## `$0E`: `callasm` *asm* + +## `$0F`: `special` *special_pointer* + +## `$10`: `ptcallasm` *asm* + +## `$11`: `checkmapscene` *map* + +## `$12`: `setmapscene` *map*, *scene_id* + +## `$13`: `checkscene` + +## `$14`: `setscene` *scene_id* + +## `$15`: `writebyte` *value* + +## `$16`: `addvar` *value* + +## `$17`: `random` *value* + +## `$18`: `checkver` + +## `$19`: `copybytetovar` *address* + +## `$1A`: `copyvartobyte` *address* + +## `$1B`: `loadvar` *address*, *value* + +## `$1C`: `checkcode` *variable* + +## `$1D`: `writevarcode` *variable* + +## `$1E`: `writecode` *variable*, *value* + +## `$1F`: `giveitem` *item_id*[, *quantity*=1] + +## `$20`: `takeitem` *item_id*[, *quantity*=1] + +## `$21`: `checkitem` *item_id* + +## `$22`: `givemoney` *account*, *value* + +## `$23`: `takemoney` *account*, *value* + +## `$24`: `checkmoney` *account*, *value* + +## `$25`: `givecoins` *value* + +## `$26`: `takecoins` *value* + +## `$27`: `checkcoins` *value* + +## `$28`: `addcellnum` *contact_id* + +## `$29`: `delcellnum` *contact_id* + +## `$2A`: `checkcellnum` *contact_id* + +## `$2B`: `checktime` *time* + +- **`checkmorn`:** `checktime MORN` +- **`checkday`:** `checktime DAY` +- **`checknite`:** `checktime NITE` + +## `$2C`: `checkpoke` *mon_id* + +## `$2D`: `givepoke` *mon_id*, *level*[, *item*=0[, *trainer*=0, *ot_name*, *nickname*]] + +## `$2E`: `giveegg` *mon_id*, *level* + +## `$2F`: `givepokeitem` *pointer* + +## `$30`: `checkpokeitem` *pointer* + +## `$31`: `checkevent` *event_flag* + +## `$32`: `clearevent` *event_flag* + +## `$33`: `setevent` *event_flag* + +## `$34`: `checkflag` *engine_flag* + +## `$35`: `clearflag` *engine_flag* + +## `$36`: `setflag` *engine_flag* + +## `$37`: `wildon` + +## `$38`: `wildoff` + +## `$39`: `xycompare` *pointer* + +## `$3A`: `warpmod` *warp_id*, *map* + +## `$3B`: `blackoutmod` *map* + +## `$3C`: `warp` *map*, *x*, *y* + +## `$3D`: `readmoney` *account*, *memory* + +## `$3E`: `readcoins` *memory* + +## `$3F`: `RAM2MEM` *memory* + +## `$40`: `pokenamemem` *mon_id*, *memory* + +## `$41`: `itemtotext` *item_id*, *memory* + +## `$42`: `mapnametotext` *memory* + +## `$43`: `trainertotext` *trainer_id*, *trainer_group*, *memory* + +## `$44`: `stringtotext` *text_pointer*, *memory* + +## `$45`: `itemnotify` + +## `$46`: `pocketisfull` + +## `$47`: `opentext` + +## `$48`: `refreshscreen` *dummy* + +## `$49`: `closetext` + +## `$4A`: `loadbytec2cf` *byte* + +## `$4B`: `farwritetext` *text_pointer* + +## `$4C`: `writetext` *text_pointer* + +## `$4D`: `repeattext` *byte1*, *byte2* + +## `$4E`: `yesorno` + +## `$4F`: `loadmenudata` *data_pointer* + +## `$50`: `closewindow` + +## `$51`: `jumptextfaceplayer` *text_pointer* + +## `$52`: `farjumptext` *text_pointer* + +## `$53`: `jumptext` *text_pointer* + +## `$54`: `waitbutton` + +## `$55`: `buttonsound` + +## `$56`: `pokepic` *mon_id* + +## `$57`: `closepokepic` + +## `$58`: `_2dmenu` + +## `$59`: `verticalmenu` + +## `$5A`: `loadpikachudata` + +## `$5B`: `randomwildmon` + +## `$5C`: `loadmemtrainer` + +## `$5D`: `loadwildmon` *mon_id*, *level* + +## `$5E`: `loadtrainer` *trainer_group*, *trainer_id* + +## `$5F`: `startbattle` + +## `$60`: `reloadmapafterbattle` + +## `$61`: `catchtutorial` *byte* + +## `$62`: `trainertext` *which_text* + +## `$63`: `trainerflagaction` *action* + +## `$64`: `winlosstext` *win_text_pointer*, *loss_text_pointer* + +## `$65`: `scripttalkafter` + +## `$66`: `end_if_just_battled` + +## `$67`: `check_just_battled` + +## `$68`: `setlasttalked` *object_id* + +## `$69`: `applymovement` *object_id*, *data_pointer* + +## `$6A`: `applymovement2` *data_pointer* + +## `$6B`: `faceplayer` + +## `$6C`: `faceobject` *object1*, *object2* + +## `$6D`: `variablesprite` *variable_sprite_id*, *sprite_id* + +## `$6E`: `disappear` *object_id* + +## `$6F`: `appear` *object_id* + +## `$70`: `follow` *object2*, *object1* + +## `$71`: `stopfollow` + +## `$72`: `moveobject` *object_id*, *x*, *y* + +## `$73`: `writeobjectxy` *object_id* + +## `$74`: `loademote` *emote_id* + +## `$75`: `showemote` *emote_id*, *object_id*, *length* + +## `$76`: `spriteface` *object_id*, *facing* + +## `$77`: `follownotexact` *object2*, *object1* + +## `$78`: `earthquake` *param* + +## `$79`: `changemap` *bank*, *blockdata_pointer* + +## `$7A`: `changeblock` *x*, *y*, *block* + +## `$7B`: `reloadmap` + +## `$7C`: `reloadmappart` + +## `$7D`: `writecmdqueue` *queue_pointer* + +## `$7E`: `delcmdqueue` *byte* + +## `$7F`: `playmusic` *music_id* + +## `$80`: `encountermusic` + +## `$81`: `musicfadeout` *music_id*, *length* + +## `$82`: `playmapmusic` + +## `$83`: `dontrestartmapmusic` + +## `$84`: `cry` *mon_id* + +## `$85`: `playsound` *sfx_id* + +## `$86`: `waitsfx` + +## `$87`: `warpsound` + +## `$88`: `specialsound` + +## `$89`: `passtoengine` *data_pointer* + +## `$8A`: `newloadmap` *which_method* + +## `$8B`: `pause` *length* + +## `$8C`: `deactivatefacing` *length* + +## `$8D`: `priorityjump` *script* + +## `$8E`: `warpcheck` + +## `$8F`: `ptpriorityjump` *script* + +## `$90`: `return` + +## `$91`: `end` + +## `$92`: `reloadandreturn` *which_method* + +## `$93`: `end_all` + +## `$94`: `pokemart` *dialog_id*, *mart_id* + +## `$95`: `elevator` *floor_list* + +## `$96`: `trade` *trade_id* + +## `$97`: `askforphonenumber` *contact_id* + +## `$98`: `phonecall` *call_id* + +## `$99`: `hangup` + +## `$9A`: `describedecoration` *byte* + +## `$9B`: `fruittree` *tree_id* + +## `$9C`: `specialphonecall` *call_id* + +## `$9D`: `checkphonecall` + +## `$9E`: `verbosegiveitem` *item_id*[, *quantity*=1] + +## `$9F`: `verbosegiveitem2` *item_id*, *variable* + +## `$A0`: `swarm` *swarm_id*, *map* + +## `$A1`: `halloffame` + +## `$A2`: `credits` + +## `$A3`: `warpfacing` *facing*, *map*, *x*, *y* + +## `$A4`: `battletowertext` *memory* + +## `$A5`: `landmarktotext` *landmark_id*, *memory* + +## `$A6`: `trainerclassname` *trainer_group*, *memory* + +## `$A7`: `name` *type*, *id*, *memory* + +## `$A8`: `wait` *duration* + +## `$A9`: `check_save` diff --git a/docs/images/hp_exp_bar_border.png b/docs/images/hp_exp_bar_border.png Binary files differnew file mode 100644 index 000000000..9d16a042b --- /dev/null +++ b/docs/images/hp_exp_bar_border.png diff --git a/docs/images/hp_exp_bar_border_fix.png b/docs/images/hp_exp_bar_border_fix.png Binary files differnew file mode 100644 index 000000000..02d36f8a0 --- /dev/null +++ b/docs/images/hp_exp_bar_border_fix.png diff --git a/docs/images/port.png b/docs/images/port.png Binary files differnew file mode 100644 index 000000000..8a18aad7d --- /dev/null +++ b/docs/images/port.png diff --git a/docs/images/port_fix.png b/docs/images/port_fix.png Binary files differnew file mode 100644 index 000000000..055a377a5 --- /dev/null +++ b/docs/images/port_fix.png diff --git a/docs/map_scripts.md b/docs/map_scripts.md new file mode 100644 index 000000000..fa8fa308b --- /dev/null +++ b/docs/map_scripts.md @@ -0,0 +1,139 @@ +# Map Scripts + + +## `const_value set 2` + +- **`const` *`MAPNAME_OBJECTNAME`*** + + +## `MapName_MapScriptHeader:` + + +## `.SceneScripts: db` *N* + +- **`scene_script` *script*** + + +## `.MapCallbacks: db` *N* + +- **`dbw` *type*, *script*** + +Callback types: + +- **`MAPCALLBACK_NEWMAP`** + +- **`MAPCALLBACK_TILES`** + +- **`MAPCALLBACK_OBJECTS`** + +- **`MAPCALLBACK_SPRITES`** + +- **`MAPCALLBACK_CMDQUEUE`** + + **`dbw CMDQUEUE_STONETABLE,` *table_pointer*** + + **`stonetable` *warp_id*, *person*, *script*** + + **`db -1 ; end`** + + +## Event scripts + +[Event commands](event_commands.md) + + +## Text + +[Text commands](text_commands.md) + + +## Movement data + +[Movement commands](movement_commands.md) + + +## `MapName_MapEventHeader:` + + ; filler + db 0, 0 + + +## `.Warps: db` *N* + +- **`warp_def` *y*, *x*, *warp_id*, *map*** + + +## `.CoordEvents: db` *N* + +- **`coord_event` *scene id*, *y*, *x*, *script*** + + +## `.BGEvents: db` *N* + +- **`bg_event` *y*, *x*, *type*, *script*** + +BG event types: + +- **`BGEVENT_READ`** + +- **`BGEVENT_UP/DOWN/LEFT/RIGHT`** + +- **`BGEVENT_IFSET/IFNOTSET`** + + **`dw` *event_flag*, *script*** + +- **`BGEVENT_ITEM`** + + **`dwb` *event_flag*, *item_id*** + +- **`BGEVENT_COPY`** + +## `.ObjectEvents: db` *N* + +- **`object_event` *sprite*, *y*, *x*, *movement*, *ry*, *rx*, *h1*, *h2*, *palette*, *type*, *range*, *script*, *event_flag*** + +Movement types: + +- **`SPRITEMOVEDATA_ITEM_TREE`** + +- **`SPRITEMOVEDATA_WANDER`** + +- **`SPRITEMOVEDATA_SPINRANDOM_SLOW`** + +- **`SPRITEMOVEDATA_WALK_UP_DOWN`** + +- **`SPRITEMOVEDATA_WALK_LEFT_RIGHT`** + +- **`SPRITEMOVEDATA_STANDING_UP/DOWN/LEFT/RIGHT`** + +- **`SPRITEMOVEDATA_SPINRANDOM_FAST`** + +- **`SPRITEMOVEDATA_SNORLAX`** + +- **`SPRITEMOVEDATA_POKEMON`** + +- **`SPRITEMOVEDATA_SUDOWOODO`** + +- **`SPRITEMOVEDATA_SMASHABLE_ROCK`** + +- **`SPRITEMOVEDATA_STRENGTH_BOULDER`** + +- **`SPRITEMOVEDATA_SPINCOUNTERCLOCKWISE`** + +- **`SPRITEMOVEDATA_SPINCLOCKWISE`** + +- **`SPRITEMOVEDATA_BIGDOLL`** + +- **`SPRITEMOVEDATA_LAPRAS`** + +Object types: + +- **`OBJECTTYPE_SCRIPT`** + +- **`OBJECTTYPE_ITEMBALL`** + + **`itemball` *item_id*** + +- **`OBJECTTYPE_TRAINER`** + + **`trainer` *event_flag*, *group_id*, *trainer_id*, *seen_text*, *beaten_text*, *loss_text*, *script*** diff --git a/docs/move_anim_commands.md b/docs/move_anim_commands.md new file mode 100644 index 000000000..9772550c3 --- /dev/null +++ b/docs/move_anim_commands.md @@ -0,0 +1,102 @@ +# Move Animation Commands + +Defined in [macros/scripts/move_anim.asm](/macros/scripts/move_anim.asm) and [battle/anims.asm:BattleAnimations](/battle/anims.asm). + + +## `$00`−`$EF`: `anim_wait` *length* + +## `$D0`: `anim_obj` *object*, *x*, *y*, *param* + +## `$D1`: `anim_1gfx` *gfx* + +## `$D2`: `anim_2gfx` *gfx1*, *gfx2* + +## `$D3`: `anim_3gfx` *gfx1*, *gfx2*, *gfx3* + +## `$D4`: `anim_4gfx` *gfx1*, *gfx2*, *gfx3*, *gfx4* + +## `$D5`: `anim_5gfx` *gfx1*, *gfx2*, *gfx3*, *gfx4*, *gfx5* + +## `$D6`: `anim_incobj` *id* + +## `$D7`: `anim_setobj` *id*, *object* + +## `$D8`: `anim_incbgeffect` *effect* + +## `$D9`: `anim_enemyfeetobj` + +## `$DA`: `anim_playerheadobj` + +## `$DB`: `anim_checkpokeball` + +## `$DC`: `anim_transform` + +## `$DD`: `anim_raisesub` + +## `$DE`: `anim_dropsub` + +## `$DF`: `anim_resetobp0` + +## `$E0`: `anim_sound` *duration*, *tracks*, *id* + +## `$E1`: `anim_cry` *pitch* + +## `$E2`: `anim_minimizeopp` + +## `$E3`: `anim_oamon` + +## `$E4`: `anim_oamoff` + +## `$E5`: `anim_clearobjs` + +## `$E6`: `anim_beatup` + +## `$E7`: `anim_0xe7` + +## `$E8`: `anim_updateactorpic` + +## `$E9`: `anim_minimize` + +## `$EA`: `anim_0xea` + +## `$EB`: `anim_0xeb` + +## `$EC`: `anim_0xec` + +## `$ED`: `anim_0xed` + +## `$EE`: `anim_if_param_and` *value*, *address* + +## `$EF`: `anim_jumpuntil` *address* + +## `$F0`: `anim_bgeffect` *effect*, *unknown1*, *unknown2*, *unknown3* + +## `$F1`: `anim_bgp` *colors* + +## `$F2`: `anim_obp0` *colors* + +## `$F3`: `anim_obp1` *colors* + +## `$F4`: `anim_clearsprites` + +## `$F5`: `anim_0xf5` + +## `$F6`: `anim_0xf6` + +## `$F7`: `anim_0xf7` + +## `$F8`: `anim_if_param_equal` *value*, *address* + +## `$F9`: `anim_setvar` *value* + +## `$FA`: `anim_incvar` + +## `$FB`: `anim_if_var_equal` *value*, *address* + +## `$FC`: `anim_jump` *address* + +## `$FD`: `anim_loop` *count*, *address* + +## `$FE`: `anim_call` *address* + +## `$FF`: `anim_ret` diff --git a/docs/movement_commands.md b/docs/movement_commands.md new file mode 100644 index 000000000..56b55f53e --- /dev/null +++ b/docs/movement_commands.md @@ -0,0 +1,84 @@ +# Movement Commands + +Defined in [macros/scripts/movement.asm](/macros/scripts/movement.asm) and [engine/movement.asm:MovementPointers](/engine/movement.asm). + + +## `$00`−`$03`: `turn_head` *direction* + +## `$04`−`$07`: `turn_step` *direction* + +## `$08`−`$0B`: `slow_step` *direction* + +## `$0C`−`$0F`: `step` *direction* + +## `$10`−`$13`: `big_step` *direction* + +## `$14`−`$17`: `slow_slide_step` *direction* + +## `$18`−`$1B`: `slide_step` *direction* + +## `$1C`−`$1F`: `fast_slide_step` *direction* + +## `$20`−`$23`: `turn_away` *direction* + +## `$24`−`$27`: `turn_in` *direction* + +## `$28`−`$2B`: `turn_waterfall` *direction* + +## `$2C`−`$2F`: `slow_jump_step` *direction* + +## `$30`−`$33`: `jump_step` *direction* + +## `$34`−`$37`: `fast_jump_step` *direction* + +## `$38`: `remove_sliding` + +## `$39`: `set_sliding` + +## `$3A`: `remove_fixed_facing` + +## `$3B`: `fix_facing` + +## `$3C`: `show_object` + +## `$3D`: `hide_object` + +## `$3E`−`$46`: `step_sleep` *length* + +## `$47`: `step_end` + +## `$48`: `step_48` *param* + +## `$49`: `remove_object` + +## `$4A`: `step_loop` + +## `$4B`: `step_4b` + +## `$4C`: `teleport_from` + +## `$4D`: `teleport_to` + +## `$4E`: `skyfall` + +## `$4F`: `step_dig` *length* + +## `$50`: `step_bump` + +## `$51`: `fish_got_bite` + +## `$52`: `fish_cast_rod` + +## `$53`: `hide_emote` + +## `$54`: `show_emote` + +## `$55`: `step_shake` *displacement* + +## `$56`: `tree_shake` + +## `$57`: `rock_smash` *length* + +## `$58`: `return_dig` *length* + +## `$59`: `skyfall_top` diff --git a/docs/music_commands.md b/docs/music_commands.md new file mode 100644 index 000000000..bf6359068 --- /dev/null +++ b/docs/music_commands.md @@ -0,0 +1,96 @@ +# Music Commands + +Defined in [macros/scripts/audio.asm](/macros/scripts/audio.asm) and [audio/engine.asm:MusicCommands](/audio/engine.asm). + + +## `musicheader` *n*, *index*, *address* + +## `cry_header` *n*, *index*, *address* + +## `note` *pitch*, *octave* + +## `sound` *pitch*, *octave*, *intensity*, *frequency* + +## `noise` *pitch*, *duration*, *intensity*, *frequency* + +## `$D0`−`$D7`: `octave` *n* + +## `$D8`: `notetype` *length*[, *intensity*] + +## `$D9`: `pitchoffset` *octave*, *key* + +## `$DA`: `tempo` *tempo* + +## `$DB`: `dutycycle` *duty_cycle* + +## `$DC`: `intensity` *intensity* + +## `$DD`: `soundinput` *input* + +## `$DE`: `sound_duty` *a*, *b*, *c*, *d* + +## `$DF`: `togglesfx` + +## `$E0`: `slidepitchto` *duration*, *octave*, *pitch* + +## `$E1`: `vibrato` *delay*, *extent* + +## `$E2`: `unknownmusic0xe2` *unknown* + +## `$E3`: `togglenoise` *id* + +## `$E4`: `panning` *tracks* + +## `$E5`: `volume` *volume* + +## `$E6`: `tone` *tone* + +## `$E7`: `unknownmusic0xe7` *unknown* + +## `$E8`: `unknownmusic0xe8` *unknown* + +## `$E9`: `tempo_relative` *value* + +## `$EA`: `restartchannel` *address* + +## `$EB`: `newsong` *id* + +## `$EC`: `sfxpriorityon` + +## `$ED`: `sfxpriorityoff` + +## `$EE`: `unknownmusic0xee` *address* + +## `$EF`: `stereopanning` *tracks* + +## `$F0`: `sfxtogglenoise` *id* + +## `$F1`: `music0xf1` + +## `$F2`: `music0xf2` + +## `$F3`: `music0xf3` + +## `$F4`: `music0xf4` + +## `$F5`: `music0xf5` + +## `$F6`: `music0xf6` + +## `$F7`: `music0xf7` + +## `$F8`: `music0xf8` + +## `$F9`: `unknownmusic0xf9` + +## `$FA`: `setcondition` *condition* + +## `$FB`: `jumpif` *condition*, *address* + +## `$FC`: `jumpchannel` *address* + +## `$FD`: `loopchannel` *count*, *address* + +## `$FE`: `callchannel` *address* + +## `$FF`: `endchannel` diff --git a/docs/pic_animations.md b/docs/pic_animations.md new file mode 100644 index 000000000..57c7f151a --- /dev/null +++ b/docs/pic_animations.md @@ -0,0 +1,31 @@ +# Pic Animations + +Defined in [macros/scripts/gfx_anim.asm](/macros/scripts/gfx_anim.asm) and [battle/anim_commands.asm:BattleAnimCommands](/battle/anim_commands.asm). + + +Pic animations are assembled in 3 parts: + +- Top-level animations: + - `frame` *#*, *duration*: Frame 0 is the original pic (no change) + - `setrepeat` *#*: Sets the number of times to repeat + - `dorepeat` *#*: Repeats from command *#* (starting from 0) + - `end` + +- 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/pics/anims.asm: + Main animations (played everywhere) + +- gfx/pics/extras.asm: + Extra animations, appended to the main animation. + Used in the status screen (blinking, tail wags etc.) + +- gfx/pics/unown_anims.asm and gfx/pics/unown_extras.asm: + Unown has its own animation data despite having an entry in the main tables. diff --git a/docs/text_commands.md b/docs/text_commands.md new file mode 100644 index 000000000..cf3a53327 --- /dev/null +++ b/docs/text_commands.md @@ -0,0 +1,164 @@ +# Text Commands + +Defined in [macros/scripts/text.asm](/macros/scripts/text.asm) and [home/text.asm:TextCommands](/home/text.asm). + + +## `$00`: `text` *text* + +Start writing text until `"@"`. + + +## `$4E`: `next` *text* + +Move a line down. + + +## `$4F`: `line` *text* + +Start writing at the bottom line. + + +## `$50`: `page` *text* + +Start a new Pokédex page. + + +## `$51`: `para` *text* + +Start a new paragraph. + + +## `$55`: `cont` *text* + +Scroll to the next line. + + +## `$57`: `done` + +End a text box. + + +## `$58`: `prompt` + +Prompt the player to end a text box (initiating some other event). + + +## `$01`: `text_from_ram` *address* + +Write text from a RAM address. + + +## `$02`: `text_bcd` *address*, *flags* + +Write [BCD](bcd) from an address, typically RAM. + +[bcd]: https://en.wikipedia.org/wiki/Binary-coded_decimal + + +## `$03`: `text_move` *address* + +Move to a new tile. + + +## `$04`: `text_box` *address*, *height*, *width* + +Draw a box. + + +## `$05`: `text_low` + +Write text at (1, 16). + + +## `$06`: `text_waitbutton` + +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`: `start_asm` + +Start interpreting assembly code. + + +## `$09`: `deciram` *address*, *bytes*, *digits* + +Read *bytes* bytes from *address* and print them as a *digits*-digit number. + + +## `$0A`: `interpret_data` + +Exit. + + +## `$0B`: `sound_dex_fanfare_50_79` + +Play `SFX_DEX_FANFARE_50_79`. + + +## `$0C`: `limited_interpret_data` *number* + +Print *number* `"…"`s. + + +## `$0D`: `link_wait_button` + +Wait for button press; 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`: `text_buffer` *id* + +Write text from one of the following addresses (listed in `StringBufferPointers`): + +0. `StringBuffer3` +1. `StringBuffer4` +2. `StringBuffer5` +3. `StringBuffer2` +4. `StringBuffer1` +5. `EnemyMonNick` +6. `BattleMonNick` + + +## `$15`: `current_day` + +Print the weekday. + + +## `$16`: `text_jump` *address* + +Write text from a different bank. |