From feef75c5df98eb79f7ca26fca66d577932fd4a34 Mon Sep 17 00:00:00 2001 From: Remy Oukaour Date: Wed, 13 Dec 2017 16:46:31 -0500 Subject: [PATCH] Document more bugs and glitches Add a toc.py script to auto-generate tables of contents in Markdown files --- docs/bugs_and_glitches.md | 110 +++++++++++++++++++++++++++++++++++++- tools/toc.py | 98 +++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 tools/toc.py diff --git a/docs/bugs_and_glitches.md b/docs/bugs_and_glitches.md index 3e77d5093..c682244e3 100644 --- a/docs/bugs_and_glitches.md +++ b/docs/bugs_and_glitches.md @@ -14,6 +14,7 @@ - ["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) - [A Disabled, PP Up–enhanced move may not trigger automatic Struggling](#a-disabled-pp-upenhanced-move-may-not-trigger-automatic-struggling) - [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 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) - [Present damage is incorrect in link battles](#present-damage-is-incorrect-in-link-battles) - [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) @@ -25,10 +26,15 @@ - [Magikarp in Lake of Rage are shorter, not longer](#magikarp-in-lake-of-rage-are-shorter-not-longer) - [Battle transitions fail to account for the enemy's level](#battle-transitions-fail-to-account-for-the-enemys-level) - [No bump noise if standing on tile `$3E`](#no-bump-noise-if-standing-on-tile-3e) -- [`LoadMetatiles` wrap around past 128 blocks](#loadmetatiles-wrap-around-past-128-blocks) +- [Playing Entei's Pokédex cry can distort Raikou's and Suicune's](#playing-enteis-pokédex-cry-can-distort-raikous-and-suicunes) +- [Lock-On and Mind Reader don't always bypass Fly and Dig](#lock-on-and-mind-reader-dont-always-bypass-fly-and-dig) +- [`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) - [`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) @@ -371,6 +377,13 @@ This is a bug with `CheckPlayerHasUsableMoves` in [battle/core.asm](battle/core. *To do:* Identify specific code causing this bug and fix it. +## 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. + + ## Present damage is incorrect in link battles ([Video](https://www.youtube.com/watch?v=XJaQoKtrEuw)) @@ -720,7 +733,43 @@ This is a bug with `DoPlayerMovement.CheckWarp` in [engine/player_movement.asm]( ``` -## `LoadMetatiles` wrap around past 128 blocks +## 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 +``` + + +## 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. + +*To do:* Identify specific code causing this bug and fix it. + + +## `LoadMetatiles` wraps around past 128 blocks + +This bug prevents you from using blocksets with more than 128 blocks. [home/map.asm](home/map.asm): @@ -793,6 +842,40 @@ endr **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. + +*To do:* Identify specific code causing this bug and fix it. + + +## 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): @@ -817,6 +900,29 @@ This is a bug with `PokeBall` in [items/item_effects.asm](items/item_effects.asm **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 [engine/scripting.asm](engine/scripting.asm): diff --git a/tools/toc.py b/tools/toc.py new file mode 100644 index 000000000..1d7a58cec --- /dev/null +++ b/tools/toc.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Usage: python3 toc.py [-n] files.md... +Replace a "## TOC" heading in a Markdown file with a table of contents, +generated from the other headings in the file. Supports multiple files. +Use "-n" for numbered list items. +Headings must start with "##" signs to be detected. +""" + +import sys +import re +from collections import namedtuple + +toc_name = 'Contents' +valid_toc_headings = {'## TOC', '##TOC'} + +TocItem = namedtuple('TocItem', ['name', 'anchor', 'level']) +punctuation_regexp = re.compile(r'[^\w\- ]+') + +def name_to_anchor(name): + # GitHub's algorithm for generating anchors from headings + # https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb + anchor = name.strip().lower() # lowercase + anchor = re.sub(punctuation_regexp, '', anchor) # remove punctuation + anchor = anchor.replace(' ', '-') # replace spaces with dash + return anchor + +def get_toc_index(lines): + toc_index = None + for i, line in enumerate(lines): + if line.rstrip() in valid_toc_headings: + toc_index = i + break + return toc_index + +def get_toc_items(lines, toc_index): + for i, line in enumerate(lines): + if i <= toc_index: + continue + if line.startswith('##'): + name = line.lstrip('#') + level = len(line) - len(name) - len('##') + name = name.strip() + anchor = name_to_anchor(name) + yield TocItem(name, anchor, level) + +def toc_string(toc_items, numeric): + lines = ['## %s' % toc_name, ''] + for name, anchor, level in toc_items: + padding = ' ' * level + line = '%s- [%s](#%s)' % (padding, name, anchor) + lines.append(line) + return '\n'.join(lines) + '\n' + +def add_toc(filename, numeric): + with open(filename, 'r', encoding='utf-8') as f: + lines = f.readlines() + toc_index = get_toc_index(lines) + if toc_index is None: + return None # no TOC heading + toc_items = list(get_toc_items(lines, toc_index)) + if not toc_items: + return False # no content headings + with open(filename, 'w', encoding='utf-8') as f: + for i, line in enumerate(lines): + if i == toc_index: + f.write(toc_string(toc_items, numeric)) + else: + f.write(line) + return True # OK + +def main(): + if len(sys.argv) < 2: + print('*** ERROR: Not enough arguments') + print(__doc__) + exit(1) + del sys.argv[0] + numeric = False + if sys.argv[0] == '-n': + numeric = True + del sys.argv[0] + if not sys.argv: + print('*** ERROR: No filenames specified') + exit(1) + for filename in sys.argv: + print(filename) + result = add_toc(filename, numeric) + if result is None: + print('*** WARNING: No "## TOC" heading found') + elif result is False: + print('*** WARNING: No content headings found') + else: + print('OK') + +if __name__ == '__main__': + main()