from dataclasses import dataclass from parse import number from parse.map_header import tokenize_line @dataclass class ObjectEvent: type: str position: tuple[int, int] sprite_id: str movement: str range_or_direction: str text_id: str items_id_or_trainer_id_or_pokemon_id: str = None trainer_number_or_pokemon_level: str = None @dataclass class WarpEvent: position: tuple[int, int] destination_map: str destination_warp_index: str @dataclass class BgEvent: position: tuple[int, int] sign_id: str @dataclass class Object: border_block: int warp_events: list object_events: list bg_events: list def tokenize_label(line): return ('label', line.split(':')[0].strip()) def tokenize_event(line): return list(tokenize_line(line)) def tokenize_border_block(line): return ('border_block', number.parse(line.strip().split()[1])) def tokenize_lines(lines): for line in lines: if "_event " in line: yield tokenize_event(line) elif ':' in line: yield tokenize_label(line) elif 'border block' in line: # special case where we are parsing a comment yield tokenize_border_block(line) def object_id(object_args): types = { 6: "trainer", 5: "item", 4: "generic", } assert len(object_args) in types, object_args return types[len(object_args)] def flatten(tokens): label = None border_block = None warp_events = [] object_events = [] bg_events = [] for token_name, args in tokens: position = lambda : list(map(number.parse, args[0:2])) if token_name == 'label': assert label is None label = args elif token_name == 'object_event': object_args = args[2:] event = ObjectEvent( object_id(object_args), position(), *object_args ) object_events.append(event) elif token_name == 'warp_event': destination_map, destination_warp_index = args[2:] event = WarpEvent( position(), destination_map, number.parse(destination_warp_index) ) warp_events.append(event) elif token_name == 'bg_event': event = BgEvent( position(), *(args[2:]) ) bg_events.append(event) elif token_name == 'border_block': assert border_block is None border_block = args else: assert False, (token_name, args) assert label is not None assert border_block is not None return label, Object( border_block=border_block, warp_events = warp_events, object_events = object_events, bg_events = bg_events, ) def parse(path): with open(path) as f: tokens = tokenize_lines(f.read().split('\n')) return flatten(tokens) def parse_all(prefix): base_path = prefix / 'data/maps/objects' paths = (p for p in base_path.iterdir() if p.is_file()) return dict(parse(path) for path in paths)