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, tmhm,
) )
def parse(path): def parse(path):
with open(path) as f: with open(path) as f:
token_lines = filter_lines(lines(f.read().split('\n'))) token_lines = filter_lines(lines(f.read().split('\n')))
@ -66,5 +65,5 @@ def parse(path):
def parse_all(prefix): def parse_all(prefix):
base_path = prefix / 'data/pokemon/base_stats' base_path = prefix / 'data/pokemon/base_stats'
paths = [p for p in base_path.iterdir() if p.is_file()] 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] 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 import builtins
from dataclasses import dataclass from dataclasses import dataclass
from itertools import chain
from parse.generic import tokenize from parse.generic import tokenize
from parse.generic import number from parse.generic import number
from parse.generic import label_data
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
@dataclass @dataclass
class EvosMoves: class EvosMoves:
@ -54,37 +33,24 @@ def parse_ev(tokens):
else: else:
assert False, ev_type 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): def parse_learnset_entry(args):
level_requirement, move_name = args level_requirement, move_name = args
return number.parse(level_requirement), move_name return number.parse(level_requirement), move_name
def build_tables(tokens): def build_tables(tokens):
evos_moves = EvosMoves() evos_moves = EvosMoves()
pointer_table = []
type_args = list(chain.from_iterable(map(event, tokens))) type_args = label_data.event(tokens)
ix = 0 ix = 0
while ix < len(type_args): while ix < len(type_args):
type, args = type_args[ix] type, args = type_args[ix]
if type is Label: if type is label_data.Label:
label = args label = args
assert builtins.type(label) is str assert builtins.type(label) is str
if label == 'EvosMovesPointerTable': 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: if evos_moves.label is not None:
yield evos_moves yield evos_moves
evos_moves = EvosMoves() evos_moves = EvosMoves()
@ -92,7 +58,7 @@ def build_tables(tokens):
assert evos_moves.evolutions == [], evos_moves assert evos_moves.evolutions == [], evos_moves
assert evos_moves.learnset == [], evos_moves assert evos_moves.learnset == [], evos_moves
evos_moves.label = label evos_moves.label = label
elif type is Data: elif type is label_data.Data:
if is_evolution(args): if is_evolution(args):
evos_moves.evolutions.append(parse_ev(args)) evos_moves.evolutions.append(parse_ev(args))
elif is_learnset_entry(args): elif is_learnset_entry(args):
@ -101,17 +67,13 @@ def build_tables(tokens):
pass # do nothing pass # do nothing
else: else:
assert False, (type, args) assert False, (type, args)
else: else:
assert False, (type, args) assert False, (type, args)
ix += 1 ix += 1
def parse(prefix): def parse(prefix):
path = prefix / "data/pokemon/evos_moves.asm" path = prefix / "data/pokemon/evos_moves.asm"
with open(path) as f: with open(path) as f:
return list(build_tables(lines(f.read().split('\n')))) return list(build_tables(tokenize.lines(f.read().split('\n'))))
from pathlib import Path
from pprint import pprint
pprint(parse(Path("../pokered")))