map_object: define structs
This also improves map_object parsing code. There are still unhandled issues in the parser output related to quirks in the input data.
This commit is contained in:
parent
f9b0f43af6
commit
070e33d1e8
22
input.cpp
22
input.cpp
@ -5,10 +5,6 @@
|
||||
#include "input.hpp"
|
||||
#include "common/intback.hpp"
|
||||
|
||||
constexpr int input_arr = 10;
|
||||
constexpr int input_das = 20;
|
||||
constexpr int input_debounce = 2;
|
||||
|
||||
static inline void
|
||||
input_count(count_flop_t& button, const uint32_t input, const uint32_t mask)
|
||||
{
|
||||
@ -28,24 +24,6 @@ input_count(count_flop_t& button, const uint32_t input, const uint32_t mask)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
input_flopped(count_flop_t& button)
|
||||
{
|
||||
if (button.count == input_debounce && button.flop == 0) {
|
||||
button.flop = 1;
|
||||
return 1;
|
||||
} else if (button.flop == 1 && button.das == input_das && button.repeat == 0) {
|
||||
button.repeat = 1;
|
||||
button.das = 0;
|
||||
return 2;
|
||||
} else if (button.repeat == 1 && (button.das == input_arr)) {
|
||||
button.das = 0;
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
input_t input = { 0 };
|
||||
|
||||
void digital_callback(uint8_t fsm_state, uint8_t data)
|
||||
|
27
input.hpp
27
input.hpp
@ -28,3 +28,30 @@ struct input_t {
|
||||
void digital_callback(uint8_t fsm_state, uint8_t data);
|
||||
|
||||
extern input_t input;
|
||||
|
||||
constexpr int input_arr = 10;
|
||||
constexpr int input_das = 20;
|
||||
constexpr int input_debounce = 2;
|
||||
|
||||
static constexpr inline int32_t
|
||||
input_flopped(count_flop_t& button)
|
||||
{
|
||||
if (button.count == input_debounce && button.flop == 0) {
|
||||
button.flop = 1;
|
||||
return 1;
|
||||
} else if (button.flop == 1 && button.das == input_das && button.repeat == 0) {
|
||||
button.repeat = 1;
|
||||
button.das = 0;
|
||||
return 2;
|
||||
} else if (button.repeat == 1 && (button.das == input_arr)) {
|
||||
button.das = 0;
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct event {
|
||||
static inline bool cursor_left() { return input_flopped(input.a) == 1; }
|
||||
static inline bool cursor_right() { return input_flopped(input.b) == 1; }
|
||||
};
|
||||
|
76
main.cpp
76
main.cpp
@ -77,14 +77,44 @@ constexpr inline void render_block(const uint32_t base_pattern,
|
||||
}
|
||||
}
|
||||
|
||||
void render(const uint32_t base_pattern)
|
||||
{
|
||||
const map_t& map = maps[map_t::pallet_town];
|
||||
constexpr int32_t last_map = map_t::wardens_house;
|
||||
|
||||
for (uint32_t map_y = 0; map_y < map.height; map_y++) {
|
||||
for (uint32_t map_x = 0; map_x < map.width; map_x++) {
|
||||
struct state_t {
|
||||
int32_t map_ix;
|
||||
enum tileset_t::tileset tileset;
|
||||
uint32_t base_pattern;
|
||||
};
|
||||
|
||||
static state_t state = { 0, tileset_t::cavern, 0 };
|
||||
|
||||
enum tileset_t::tileset load_tileset(enum tileset_t::tileset tileset)
|
||||
{
|
||||
uint32_t top = (sizeof (union vdp2_vram));
|
||||
uint32_t base_address = top = cell_data(tilesets[tileset].tileset, top);
|
||||
state.base_pattern = base_address / 32;
|
||||
|
||||
/* use 1-word (16-bit) pattern names */
|
||||
/* update N0SCN in the event base_pattern moves (it usually does not) */
|
||||
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((state.base_pattern >> 10) & 0x1f);
|
||||
|
||||
return tileset;
|
||||
}
|
||||
|
||||
#include "map.hpp"
|
||||
|
||||
void render()
|
||||
{
|
||||
const map_t& map = maps[maps_ix[state.map_ix]];
|
||||
|
||||
if (map.tileset != state.tileset)
|
||||
state.tileset = load_tileset(map.tileset);
|
||||
|
||||
uint32_t height = map.height > 16 ? 16 : map.height;
|
||||
uint32_t width = map.width > 16 ? 16 : map.width;
|
||||
for (uint32_t map_y = 0; map_y < height; map_y++) {
|
||||
for (uint32_t map_x = 0; map_x < width; map_x++) {
|
||||
const uint8_t block = map.blocks.start[map.width * map_y + map_x];
|
||||
render_block(base_pattern,
|
||||
render_block(state.base_pattern,
|
||||
tilesets[map.tileset],
|
||||
map_x,
|
||||
map_y,
|
||||
@ -93,13 +123,36 @@ void render(const uint32_t base_pattern)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t base_pattern;
|
||||
void update()
|
||||
{
|
||||
if (event::cursor_right()) {
|
||||
state.map_ix++;
|
||||
if (state.map_ix >= map_ix_last)
|
||||
state.map_ix = 0;
|
||||
}
|
||||
if (event::cursor_left()) {
|
||||
state.map_ix--;
|
||||
if (state.map_ix < 0) state.map_ix = last_map;
|
||||
}
|
||||
}
|
||||
|
||||
static int count = 0;
|
||||
|
||||
extern "C"
|
||||
void v_blank_in_int(void) __attribute__ ((interrupt_handler));
|
||||
void v_blank_in_int()
|
||||
{
|
||||
render(base_pattern);
|
||||
if (++count > 60) {
|
||||
count = 0;
|
||||
state.map_ix++;
|
||||
if (state.map_ix >= map_ix_last)
|
||||
state.map_ix = 0;
|
||||
}
|
||||
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||
|
||||
render();
|
||||
update();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@ -150,14 +203,7 @@ void main()
|
||||
vdp2.reg.MPABN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(plane_a); // bits 5~0
|
||||
vdp2.reg.MPCDN0 = MPABN0__N0MPD(0) | MPABN0__N0MPC(0); // bits 5~0
|
||||
|
||||
uint32_t top = (sizeof (union vdp2_vram));
|
||||
palette_data();
|
||||
uint32_t base_address = top = cell_data(tilesets[tileset_t::overworld].tileset, top);
|
||||
base_pattern = base_address / 32;
|
||||
|
||||
/* use 1-word (16-bit) pattern names */
|
||||
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((base_pattern >> 10) & 0x1f);
|
||||
//vdp2.reg.PNCN0 = PNCN0__N0PNB__2WORD | PNCN0__N0CNSM;
|
||||
|
||||
vdp2.reg.CYCA0 = 0x0fff'ffff;
|
||||
vdp2.reg.CYCA1 = 0xffff'ffff;
|
||||
|
226
map.hpp
Normal file
226
map.hpp
Normal file
@ -0,0 +1,226 @@
|
||||
enum map_t::map maps_ix[] = {
|
||||
map_t::agathas_room,
|
||||
map_t::bike_shop,
|
||||
map_t::bills_house,
|
||||
map_t::blues_house,
|
||||
map_t::brunos_room,
|
||||
map_t::celadon_chief_house,
|
||||
map_t::celadon_city,
|
||||
map_t::celadon_diner,
|
||||
map_t::celadon_gym,
|
||||
map_t::celadon_hotel,
|
||||
map_t::celadon_mansion_1f,
|
||||
map_t::celadon_mansion_2f,
|
||||
map_t::celadon_mansion_3f,
|
||||
map_t::celadon_mansion_roof,
|
||||
map_t::celadon_mansion_roof_house,
|
||||
map_t::celadon_mart_1f,
|
||||
map_t::celadon_mart_2f,
|
||||
map_t::celadon_mart_3f,
|
||||
map_t::celadon_mart_4f,
|
||||
map_t::celadon_mart_5f,
|
||||
map_t::celadon_mart_elevator,
|
||||
map_t::celadon_mart_roof,
|
||||
map_t::celadon_pokecenter,
|
||||
map_t::cerulean_badge_house,
|
||||
map_t::cerulean_cave_1f,
|
||||
map_t::cerulean_cave_2f,
|
||||
map_t::cerulean_cave_b1f,
|
||||
map_t::cerulean_city,
|
||||
map_t::cerulean_gym,
|
||||
map_t::cerulean_mart,
|
||||
map_t::cerulean_pokecenter,
|
||||
map_t::cerulean_trade_house,
|
||||
map_t::cerulean_trashed_house,
|
||||
map_t::champions_room,
|
||||
map_t::cinnabar_gym,
|
||||
map_t::cinnabar_island,
|
||||
map_t::cinnabar_lab,
|
||||
map_t::cinnabar_lab_fossil_room,
|
||||
map_t::cinnabar_lab_metronome_room,
|
||||
map_t::cinnabar_lab_trade_room,
|
||||
map_t::cinnabar_mart,
|
||||
map_t::cinnabar_pokecenter,
|
||||
map_t::colosseum,
|
||||
map_t::copycats_house_1f,
|
||||
map_t::copycats_house_2f,
|
||||
map_t::daycare,
|
||||
map_t::digletts_cave,
|
||||
map_t::digletts_cave_route_11,
|
||||
map_t::digletts_cave_route_2,
|
||||
map_t::fighting_dojo,
|
||||
map_t::fuchsia_bills_grandpas_house,
|
||||
map_t::fuchsia_city,
|
||||
map_t::fuchsia_good_rod_house,
|
||||
map_t::fuchsia_gym,
|
||||
map_t::fuchsia_mart,
|
||||
map_t::fuchsia_meeting_room,
|
||||
map_t::fuchsia_pokecenter,
|
||||
map_t::game_corner,
|
||||
map_t::game_corner_prize_room,
|
||||
map_t::hall_of_fame,
|
||||
map_t::indigo_plateau,
|
||||
map_t::indigo_plateau_lobby,
|
||||
map_t::lances_room,
|
||||
map_t::lavender_cubone_house,
|
||||
map_t::lavender_mart,
|
||||
map_t::lavender_pokecenter,
|
||||
map_t::lavender_town,
|
||||
map_t::loreleis_room,
|
||||
map_t::mr_fujis_house,
|
||||
map_t::mr_psychics_house,
|
||||
map_t::mt_moon_1f,
|
||||
map_t::mt_moon_b1f,
|
||||
map_t::mt_moon_b2f,
|
||||
map_t::mt_moon_pokecenter,
|
||||
map_t::museum_1f,
|
||||
map_t::museum_2f,
|
||||
map_t::name_raters_house,
|
||||
map_t::oaks_lab,
|
||||
map_t::pallet_town,
|
||||
map_t::pewter_city,
|
||||
map_t::pewter_gym,
|
||||
map_t::pewter_mart,
|
||||
map_t::pewter_nidoran_house,
|
||||
map_t::pewter_pokecenter,
|
||||
map_t::pewter_speech_house,
|
||||
map_t::pokemon_fan_club,
|
||||
map_t::pokemon_mansion_1f,
|
||||
map_t::pokemon_mansion_2f,
|
||||
map_t::pokemon_mansion_3f,
|
||||
map_t::pokemon_mansion_b1f,
|
||||
map_t::pokemon_tower_1f,
|
||||
map_t::pokemon_tower_2f,
|
||||
map_t::pokemon_tower_3f,
|
||||
map_t::pokemon_tower_4f,
|
||||
map_t::pokemon_tower_5f,
|
||||
map_t::pokemon_tower_6f,
|
||||
map_t::pokemon_tower_7f,
|
||||
map_t::power_plant,
|
||||
map_t::reds_house_1f,
|
||||
map_t::reds_house_2f,
|
||||
map_t::rocket_hideout_b1f,
|
||||
map_t::rocket_hideout_b2f,
|
||||
map_t::rocket_hideout_b3f,
|
||||
map_t::rocket_hideout_b4f,
|
||||
map_t::rocket_hideout_elevator,
|
||||
map_t::rock_tunnel_1f,
|
||||
map_t::rock_tunnel_b1f,
|
||||
map_t::rock_tunnel_pokecenter,
|
||||
map_t::route_1,
|
||||
map_t::route_10,
|
||||
map_t::route_11,
|
||||
map_t::route_11_gate_1f,
|
||||
map_t::route_11_gate_2f,
|
||||
map_t::route_12,
|
||||
map_t::route_12_gate_1f,
|
||||
map_t::route_12_gate_2f,
|
||||
map_t::route_12_super_rod_house,
|
||||
map_t::route_13,
|
||||
map_t::route_14,
|
||||
map_t::route_15,
|
||||
map_t::route_15_gate_1f,
|
||||
map_t::route_15_gate_2f,
|
||||
map_t::route_16,
|
||||
map_t::route_16_fly_house,
|
||||
map_t::route_16_gate_1f,
|
||||
map_t::route_16_gate_2f,
|
||||
map_t::route_17,
|
||||
map_t::route_18,
|
||||
map_t::route_18_gate_1f,
|
||||
map_t::route_18_gate_2f,
|
||||
map_t::route_19,
|
||||
map_t::route_2,
|
||||
map_t::route_20,
|
||||
map_t::route_21,
|
||||
map_t::route_22,
|
||||
map_t::route_22_gate,
|
||||
map_t::route_23,
|
||||
map_t::route_24,
|
||||
map_t::route_25,
|
||||
map_t::route_2_gate,
|
||||
map_t::route_2_trade_house,
|
||||
map_t::route_3,
|
||||
map_t::route_4,
|
||||
map_t::route_5,
|
||||
map_t::route_5_gate,
|
||||
map_t::route_6,
|
||||
map_t::route_6_gate,
|
||||
map_t::route_7,
|
||||
map_t::route_7_gate,
|
||||
map_t::route_8,
|
||||
map_t::route_8_gate,
|
||||
map_t::route_9,
|
||||
map_t::safari_zone_center,
|
||||
map_t::safari_zone_center_rest_house,
|
||||
map_t::safari_zone_east,
|
||||
map_t::safari_zone_east_rest_house,
|
||||
map_t::safari_zone_gate,
|
||||
map_t::safari_zone_north,
|
||||
map_t::safari_zone_north_rest_house,
|
||||
map_t::safari_zone_secret_house,
|
||||
map_t::safari_zone_west,
|
||||
map_t::safari_zone_west_rest_house,
|
||||
map_t::saffron_city,
|
||||
map_t::saffron_gym,
|
||||
map_t::saffron_mart,
|
||||
map_t::saffron_pidgey_house,
|
||||
map_t::saffron_pokecenter,
|
||||
map_t::seafoam_islands_1f,
|
||||
map_t::seafoam_islands_b1f,
|
||||
map_t::seafoam_islands_b2f,
|
||||
map_t::seafoam_islands_b3f,
|
||||
map_t::seafoam_islands_b4f,
|
||||
map_t::silph_co_10f,
|
||||
map_t::silph_co_11f,
|
||||
map_t::silph_co_1f,
|
||||
map_t::silph_co_2f,
|
||||
map_t::silph_co_3f,
|
||||
map_t::silph_co_4f,
|
||||
map_t::silph_co_5f,
|
||||
map_t::silph_co_6f,
|
||||
map_t::silph_co_7f,
|
||||
map_t::silph_co_8f,
|
||||
map_t::silph_co_9f,
|
||||
map_t::silph_co_elevator,
|
||||
map_t::ss_anne_1f,
|
||||
map_t::ss_anne_1f_rooms,
|
||||
map_t::ss_anne_2f,
|
||||
map_t::ss_anne_2f_rooms,
|
||||
map_t::ss_anne_3f,
|
||||
map_t::ss_anne_b1f,
|
||||
map_t::ss_anne_b1f_rooms,
|
||||
map_t::ss_anne_bow,
|
||||
map_t::ss_anne_captains_room,
|
||||
map_t::ss_anne_kitchen,
|
||||
map_t::trade_center,
|
||||
map_t::underground_path_north_south,
|
||||
map_t::underground_path_route_5,
|
||||
map_t::underground_path_route_6,
|
||||
map_t::underground_path_route_7,
|
||||
map_t::underground_path_route_8,
|
||||
map_t::underground_path_west_east,
|
||||
map_t::vermilion_city,
|
||||
map_t::vermilion_dock,
|
||||
map_t::vermilion_gym,
|
||||
map_t::vermilion_mart,
|
||||
map_t::vermilion_old_rod_house,
|
||||
map_t::vermilion_pidgey_house,
|
||||
map_t::vermilion_pokecenter,
|
||||
map_t::vermilion_trade_house,
|
||||
map_t::victory_road_1f,
|
||||
map_t::victory_road_2f,
|
||||
map_t::victory_road_3f,
|
||||
map_t::viridian_city,
|
||||
map_t::viridian_forest,
|
||||
map_t::viridian_forest_north_gate,
|
||||
map_t::viridian_forest_south_gate,
|
||||
map_t::viridian_gym,
|
||||
map_t::viridian_mart,
|
||||
map_t::viridian_nickname_house,
|
||||
map_t::viridian_pokecenter,
|
||||
map_t::viridian_school_house,
|
||||
map_t::wardens_house,
|
||||
};
|
||||
|
||||
constexpr int map_ix_last = (sizeof (maps_ix)) / (sizeof (enum map_t::map));
|
60
map_object.hpp
Normal file
60
map_object.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
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;
|
||||
};
|
||||
};
|
5
tools/parse/__main__.py
Normal file
5
tools/parse/__main__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from pprint import pprint
|
||||
from parse import parse
|
||||
|
||||
for i in parse.map_objects_list.items():
|
||||
pprint(i)
|
@ -5,7 +5,8 @@ from parse.map_header import tokenize_line
|
||||
|
||||
@dataclass
|
||||
class ObjectEvent:
|
||||
location: tuple[int, int]
|
||||
type: str
|
||||
position: tuple[int, int]
|
||||
sprite_id: str
|
||||
movement: str
|
||||
range_or_direction: str
|
||||
@ -15,18 +16,18 @@ class ObjectEvent:
|
||||
|
||||
@dataclass
|
||||
class WarpEvent:
|
||||
location: tuple[int, int]
|
||||
position: tuple[int, int]
|
||||
destination_map: str
|
||||
destination_warp_id: str
|
||||
destination_warp_index: str
|
||||
|
||||
@dataclass
|
||||
class BgEvent:
|
||||
location: tuple[int, int]
|
||||
position: tuple[int, int]
|
||||
sign_id: str
|
||||
|
||||
@dataclass
|
||||
class Object:
|
||||
label: str
|
||||
border_block: int
|
||||
warp_events: list
|
||||
object_events: list
|
||||
bg_events: list
|
||||
@ -37,49 +38,71 @@ def tokenize_label(line):
|
||||
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:
|
||||
location = lambda : list(map(number.parse, args[0:2]))
|
||||
position = lambda : list(map(number.parse, args[0:2]))
|
||||
if token_name == 'label':
|
||||
assert label is None
|
||||
label = token_name
|
||||
label = args
|
||||
elif token_name == 'object_event':
|
||||
object_args = args[2:]
|
||||
event = ObjectEvent(
|
||||
location(),
|
||||
*(args[2:])
|
||||
object_id(object_args),
|
||||
position(),
|
||||
*object_args
|
||||
)
|
||||
object_events.append(event)
|
||||
elif token_name == 'warp_event':
|
||||
destination_map, destination_warp_id = args[2:]
|
||||
destination_map, destination_warp_index = args[2:]
|
||||
event = WarpEvent(
|
||||
location(),
|
||||
position(),
|
||||
destination_map,
|
||||
number.parse(destination_warp_id)
|
||||
number.parse(destination_warp_index)
|
||||
)
|
||||
warp_events.append(event)
|
||||
elif token_name == 'bg_event':
|
||||
event = BgEvent(
|
||||
location(),
|
||||
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
|
||||
return Object(
|
||||
label=label,
|
||||
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,
|
||||
@ -93,4 +116,4 @@ def parse(path):
|
||||
def parse_all(prefix):
|
||||
base_path = prefix / 'data/maps/objects'
|
||||
paths = (p for p in base_path.iterdir() if p.is_file())
|
||||
return [parse(path) for path in paths]
|
||||
return dict(parse(path) for path in paths)
|
||||
|
@ -24,3 +24,11 @@ collision_tile_ids_list = collision_tile_ids.parse(prefix)
|
||||
map_objects_list = map_objects.parse_all(prefix)
|
||||
hidden_objects_list = hidden_objects.parse(prefix)
|
||||
map_constants_list = map_constants.parse(prefix)
|
||||
|
||||
# need:
|
||||
#data/tilesets/pair_collision_tile_ids.asm
|
||||
#ledge_tiles.asm
|
||||
#cut_tree_blocks.asm
|
||||
|
||||
|
||||
# home/vcopy: animations
|
||||
|
Loading…
x
Reference in New Issue
Block a user