diff --git a/map_object.hpp b/map_object.hpp deleted file mode 100644 index f40253b..0000000 --- a/map_object.hpp +++ /dev/null @@ -1,60 +0,0 @@ -struct position_t { - uint8_t x; - uint8_t y; -}; - -struct warp_event_t { - position_t position; - map_t::map destination_map; - uint8_t destination_warp_index; -}; - -struct object_event_t { - enum type { - generic, - item, - trainer, - pokemon, - }; - - enum movement { - stay, - walk, - }; - - enum range { - any_dir, - up_down, - left_right, - }; - - enum direction { - down, - up, - left, - right, - none, - }; - - position_t position; - uint8_t sprite_id; // fixme - enum movement movement; - union { - enum range range; - enum direction direction; - }; - uint8_t text_id; // fixme - union { - struct { - uint8_t id; - } item; - struct { - uint8_t type; // trainer class - uint8_t id; // trainer number - } trainer; - struct { - uint8_t id; // pokemon id - uint8_t level; - } pokemon; - }; -}; diff --git a/map_objects.hpp b/map_objects.hpp new file mode 100644 index 0000000..d399f55 --- /dev/null +++ b/map_objects.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include + +#include "gen/maps.hpp" + +struct position_t { + uint8_t x; + uint8_t y; +}; + +struct warp_event_t { + position_t position; + struct { + map_t::map map; + uint8_t warp_index; + } destination; +}; + +struct bg_event_t { + position_t position; + uint8_t sign_id; +}; + +struct object_event_t { + enum struct type { + generic, + item, + trainer, + pokemon, + }; + + enum struct movement { + stay, + walk, + }; + + enum struct range_or_direction { + any_dir, + up_down, + left_right, + down, + up, + left, + right, + none, + boulder_movement_byte_2, + }; + + enum type type; + position_t position; + uint8_t sprite_id; // fixme + enum movement movement; + enum range_or_direction range_or_direction; + uint8_t text_id; // fixme + union { + struct { + uint8_t id; + } item; + struct { + uint8_t type; // trainer class + uint8_t number; // trainer number + } trainer; + struct { + uint8_t id; // pokemon id + uint8_t level; + } pokemon; + }; +}; + +// this is written "oddly" to make the struct more compact; making a +// {length, events} struct for each event type would would require 28 +// bytes contrast to 16 bytes as modeled here. +struct object_t { + uint8_t border_block; + uint8_t warp_length; + uint8_t bg_length; + uint8_t object_length; + const warp_event_t * warp_events; + const bg_event_t * bg_events; + const object_event_t * object_events; +}; diff --git a/tools/generate/__main__.py b/tools/generate/__main__.py index 7f0aed3..8404744 100644 --- a/tools/generate/__main__.py +++ b/tools/generate/__main__.py @@ -3,11 +3,13 @@ from pprint import pprint import sys from generate import maps +from generate import map_objects def generate(base_path): files = [ (maps.generate_maps_header, "maps.hpp"), (maps.generate_maps_source, "maps.cpp"), + (map_objects.generate_map_objects_source, "map_objects.cpp") ] for func, filename in files: @@ -18,4 +20,3 @@ def generate(base_path): # sys.argv[1] is secretly used in parse base_path = Path(sys.argv[2]) generate(base_path) - diff --git a/tools/generate/map_objects.py b/tools/generate/map_objects.py new file mode 100644 index 0000000..227be50 --- /dev/null +++ b/tools/generate/map_objects.py @@ -0,0 +1,105 @@ +from parse import parse + +from generate.generate import renderer +from generate.maps import sorted_map_headers + +def warp_event(ev): + x, y = ev.position + return [ + "{", + f".position = {{ {x}, {y} }},", + ".destination = {", + f".map = map_t::{ev.destination_map.lower()},", + f".warp_index = {ev.destination_warp_index},", + "}", + "},", + ] + +def bg_event(ev): + x, y = ev.position + return [ + "{", + f".position = {{ {x}, {y} }},", + ".sign_id = 0,", # fixme + "},", + ] + +def range_or_direction(ev): + direction = ev.range_or_direction.lower() + if direction == '0': + direction = 'any_dir' # hack? + yield f".range_or_direction = object_event_t::range_or_direction::{direction}," + +def object_event(ev): + x, y = ev.position + return [ + "{", + f".type = object_event_t::type::{ev.type},", + f".position = {{ {x}, {y} }},", + ".sprite_id = 0,", # fixme + f".movement = object_event_t::movement::{ev.movement.lower()},", + *(range_or_direction(ev)), + ".text_id = 0,", # fixme + ".trainer = { 0 },", # fixme + "},", + ] + +def warp_events(map_name, obj): + yield f"const warp_event_t {map_name}_warp_events[] = {{" + for ev in obj.warp_events: + yield from warp_event(ev) + yield "};" + +def bg_events(map_name, obj): + yield f"const bg_event_t {map_name}_bg_events[] = {{" + for ev in obj.bg_events: + yield from bg_event(ev) + yield "};" + +def object_events(map_name, obj): + yield f"const object_event_t {map_name}_object_events[] = {{" + for ev in obj.object_events: + yield from object_event(ev) + yield "};" + +def object(map_name, obj): + return [ + f"[map_t::{map_name}] = {{", + f".border_block = {obj.border_block},", + f".warp_length = {len(obj.warp_events)},", + f".bg_length = {len(obj.bg_events)},", + f".object_length = {len(obj.object_events)},", + f".warp_events = &{map_name}_warp_events[0],", + f".bg_events = &{map_name}_bg_events[0],", + f".object_events = &{map_name}_object_events[0],", + "},", + ] + +def includes_source(): + yield '#include ' + yield "" + yield '#include "../map_objects.hpp"' + yield '#include "maps.hpp"' + yield "" + +def map_objects(): + map_headers = sorted_map_headers() + for map_header in map_headers: + map_name = map_header.name2.lower() + map_objects = parse.map_objects_list[map_header.object()] + yield from warp_events(map_name, map_objects) + yield from bg_events(map_name, map_objects) + yield from object_events(map_name, map_objects) + + yield "const object_t map_objects[] = {" + for map_header in map_headers: + map_name = map_header.name2.lower() + map_objects = parse.map_objects_list[map_header.object()] + yield from object(map_name, map_objects) + yield "};" + +def generate_map_objects_source(): + render, out = renderer() + render(includes_source()) + render(map_objects()) + return out diff --git a/tools/generate/maps.py b/tools/generate/maps.py index ffd00ea..627b13b 100644 --- a/tools/generate/maps.py +++ b/tools/generate/maps.py @@ -7,7 +7,9 @@ def sorted_map_headers(): map_headers = sorted(parse.map_headers, key=lambda m: m.name2) return filter(lambda m: m.name1 != "UndergroundPathRoute7Copy", map_headers) -def includes(): +def includes_header(): + yield "#pragma once" + yield "" for map_header in sorted_map_headers(): block_path = parse.maps_blocks_list[map_header.blocks()] yield f'#include "../res/{block_path}.h"' @@ -60,6 +62,8 @@ def struct_map_t(): "", "enum map {", *map_names, + "last_map,", # special map name + "unused_map_ed,", # special silph co elevator map name "};", "};", ] @@ -130,7 +134,7 @@ def maps(): def generate_maps_header(): render, out = renderer() - render(includes()) + render(includes_header()) render(struct_start_size_t()) render(struct_tileset_t()) render(struct_map_t()) @@ -138,13 +142,15 @@ def generate_maps_header(): render(maps_header()); return out -def include_maps_header(): +def includes_source(): + yield '#include ' + yield '' yield '#include "maps.hpp"' - yield "" + yield '' def generate_maps_source(): render, out = renderer() - render(include_maps_header()) + render(includes_source()) render(tilesets()) render(maps()) return out diff --git a/tools/parse/map_header.py b/tools/parse/map_header.py index defc93e..5b0b6c8 100644 --- a/tools/parse/map_header.py +++ b/tools/parse/map_header.py @@ -38,16 +38,16 @@ class MapHeader: return f"{self.name1}_TextPointers" def script(self): - return f"{self.name1}_Script", + return f"{self.name1}_Script" def object(self): - return f"{self.name1}_Object", + return f"{self.name1}_Object" def width(self): - return f"{self.name2}_WIDTH", + return f"{self.name2}_WIDTH" def height(self): - return f"{self.name2}_HEIGHT", + return f"{self.name2}_HEIGHT" def flatten(tokens): # expects tokens from a single file diff --git a/tools/parse/map_objects.py b/tools/parse/map_objects.py index e16416d..9888efd 100644 --- a/tools/parse/map_objects.py +++ b/tools/parse/map_objects.py @@ -11,7 +11,7 @@ class ObjectEvent: movement: str range_or_direction: str text_id: str - items_id_or_trainer_id_or_pokemon_id: str = None + item_id_or_trainer_class_or_pokemon_id: str = None trainer_number_or_pokemon_level: str = None @dataclass @@ -53,12 +53,16 @@ def tokenize_lines(lines): def object_id(object_args): types = { - 6: "trainer", + 6: "pokemon", 5: "item", 4: "generic", } assert len(object_args) in types, object_args - return types[len(object_args)] + type = types[len(object_args)] + # this feels almost too hacky... + if type == "pokemon" and "OPP_" in object_args[-2]: + type = "trainer" + return type def flatten(tokens): label = None