pokemon/tools/parse/map_objects.py
2023-07-25 05:35:33 +00:00

120 lines
3.1 KiB
Python

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)