tools/parse: add parsers for pokemon dex data

This commit is contained in:
Zack Buhman 2023-08-01 15:27:35 +00:00
parent 9f0c07e56a
commit 96cc628664
6 changed files with 125 additions and 49 deletions

View File

@ -0,0 +1,38 @@
from itertools import chain
def is_label(token_line):
return token_line[0].endswith(':')
def is_data(token_line):
return token_line[0] == 'db' or token_line[0] == 'dw' \
or token_line[0] == 'text_far'
Label = object()
Data = object()
def _event(token_line):
if is_label(token_line):
label0, = token_line
yield Label, label0.split(':')[0]
elif is_data(token_line):
_, args = token_line
yield Data, args
else:
return
def event(tokens):
return list(chain.from_iterable(map(_event, tokens)))
def pointer_table(type_args, ix):
pointer_table = []
while ix < len(type_args):
type, args = type_args[ix]
if type is Label:
break
elif type is Data:
evos_moves_label, = args
pointer_table.append(evos_moves_label)
else:
assert False, type_args
ix += 1
return ix, pointer_table

View File

@ -57,7 +57,6 @@ def parse_base_stat(lines):
tmhm,
)
def parse(path):
with open(path) as f:
token_lines = filter_lines(lines(f.read().split('\n')))
@ -66,5 +65,5 @@ def parse(path):
def parse_all(prefix):
base_path = prefix / 'data/pokemon/base_stats'
paths = [p for p in base_path.iterdir() if p.is_file()]
# order is pokedex order, not constant order
# in pokedex order
return [parse(path) for path in paths]

View File

@ -0,0 +1,60 @@
import builtins
from dataclasses import dataclass
from parse.generic import tokenize
from parse.generic import number
from parse.generic import string
from parse.generic import label_data
@dataclass
class DexEntry:
label: str
species: str
height: tuple[int, int]
weight: int
text_ptr: str
def dex_entry(type_args, ix):
label, species, height, weight, text_ptr = type_args[ix:ix+5]
label_type, label_value = label
assert label_type == label_data.Label, label
species_type, (species_value,) = species
assert species_type == label_data.Data, species_type
height_type, height_value = height
assert height_type == label_data.Data, height_type
weight_type, (weight_value,) = weight
assert weight_type == label_data.Data, weight_type
text_ptr_type, (text_ptr_value,) = text_ptr
assert text_ptr_type == label_data.Data, text_ptr_type
entry = DexEntry(
label_value,
string.parse(species_value).rstrip('@'),
tuple(map(number.parse, height_value)),
number.parse(weight_value),
text_ptr_value
)
return ix+5, entry
def build_tables(tokens):
type_args = label_data.event(tokens)
ix = 0
while ix < len(type_args):
type, args = type_args[ix]
if type is label_data.Label:
label = args
assert builtins.type(label) is str
if label == 'PokedexEntryPointers':
ix, pointer_table = label_data.pointer_table(type_args, ix + 1)
yield pointer_table
else:
ix, entry = dex_entry(type_args, ix)
yield entry
else:
assert False, (type, args)
def parse(prefix):
path = prefix / "data/pokemon/dex_entries.asm"
with open(path) as f:
return list(build_tables(tokenize.lines(f.read().split('\n'))))

View File

@ -0,0 +1,17 @@
from functools import partial
from parse.generic import tokenize
tokenize_lines = partial(tokenize.lines, prefix='db')
def flatten(tokens):
for t in tokens:
if t[0] == 'db':
_, (name,) = t
yield name
else:
assert False, t
def parse(prefix):
path = prefix / "data/pokemon/dex_order.asm"
with open(path) as f:
return list(flatten(tokenize_lines(f.read().split('\n'))))

View File

View File

@ -1,30 +1,9 @@
import builtins
from dataclasses import dataclass
from itertools import chain
from parse.generic import tokenize
from parse.generic import number
lines = tokenize.lines
def is_label(token_line):
return token_line[0].endswith(':')
def is_data(token_line):
return token_line[0] == 'db' or token_line[0] == 'dw'
Label = object()
Data = object()
def event(token_line):
if is_label(token_line):
label0, = token_line
yield Label, label0.split(':')[0]
elif is_data(token_line):
_, args = token_line
yield Data, args
else:
return
from parse.generic import label_data
@dataclass
class EvosMoves:
@ -54,37 +33,24 @@ def parse_ev(tokens):
else:
assert False, ev_type
def parse_pointer_table(type_args, ix):
pointer_table = []
while ix < len(type_args):
type, args = type_args[ix]
if type is Label:
break
elif type is Data:
evos_moves_label, = args
pointer_table.append(evos_moves_label)
else:
assert False, type_args
ix += 1
return ix, pointer_table
def parse_learnset_entry(args):
level_requirement, move_name = args
return number.parse(level_requirement), move_name
def build_tables(tokens):
evos_moves = EvosMoves()
pointer_table = []
type_args = list(chain.from_iterable(map(event, tokens)))
type_args = label_data.event(tokens)
ix = 0
while ix < len(type_args):
type, args = type_args[ix]
if type is Label:
if type is label_data.Label:
label = args
assert builtins.type(label) is str
if label == 'EvosMovesPointerTable':
ix, pointer_table = parse_pointer_table(type_args, ix + 1)
ix, pointer_table = label_data.pointer_table(type_args, ix + 1)
yield pointer_table
continue
if evos_moves.label is not None:
yield evos_moves
evos_moves = EvosMoves()
@ -92,7 +58,7 @@ def build_tables(tokens):
assert evos_moves.evolutions == [], evos_moves
assert evos_moves.learnset == [], evos_moves
evos_moves.label = label
elif type is Data:
elif type is label_data.Data:
if is_evolution(args):
evos_moves.evolutions.append(parse_ev(args))
elif is_learnset_entry(args):
@ -101,17 +67,13 @@ def build_tables(tokens):
pass # do nothing
else:
assert False, (type, args)
else:
assert False, (type, args)
ix += 1
def parse(prefix):
path = prefix / "data/pokemon/evos_moves.asm"
with open(path) as f:
return list(build_tables(lines(f.read().split('\n'))))
from pathlib import Path
from pprint import pprint
pprint(parse(Path("../pokered")))
return list(build_tables(tokenize.lines(f.read().split('\n'))))