from dataclasses import dataclass from parse import number from parse import map_header def tokenize_label(line): return line.split(':')[0].strip() def tokenize_lines(lines): for line in lines: if line.strip().endswith(':'): yield (tokenize_label(line),) elif ('dw ' in line or 'db ' in line) and ' \\' not in line: yield map_header.tokenize_line(line) elif 'hidden_object' in line or 'hidden_text_predef' in line: yield map_header.tokenize_line(line) def flatten0(tokens): stack = [] label = None for t in tokens: if len(t) == 1: if label is not None: yield (label, stack) stack = [] label = None assert label is None label, = t else: stack.append(t) @dataclass class HiddenObject: location: tuple[int, int] item_id: str object_routine: str @dataclass class HiddenObjects: label: str hidden_objects: HiddenObject def flatten(f0): for label, values in f0: if values[0][0] in {"db", "dw"} and values[0][1] != ['-1']: def vals(): for v in values: assert len(v) == 2 v0, v1 = v assert len(v1) == 1 if v0 in {"db", "dw"}: yield v1[0] yield label, list(vals()) else: assert label.endswith("Objects"), name def vals(): for value in values: macro, args = value if macro in {'hidden_object', 'hidden_text_predef'}: yield args else: assert macro == 'db', macro yield HiddenObjects( label, [ HiddenObject( location=tuple(map(number.parse, [x, y])), item_id=item_id, object_routine=object_routine ) for x, y, item_id, object_routine in vals() ] ) def parse(prefix): path = prefix / "data/events/hidden_objects.asm" with open(path) as f: tokens = list(tokenize_lines(f.read().split('\n'))) return list(flatten(flatten0(tokens)))