Compare commits

...

2 Commits

Author SHA1 Message Date
9645b4b414 main: add connection drawing 2023-07-27 05:32:54 +00:00
da49dbeb2b Makefile: improve build rules slightly
I'm still not satisfied with the Makefile, but this at least makes it
converge in a single make invocation again.

This also removes the enum value arrays.
2023-07-26 18:17:45 +00:00
13 changed files with 214 additions and 432 deletions

View File

@ -3,11 +3,19 @@ CFLAGS = -Isaturn
OPT ?= -Og OPT ?= -Og
LIB = ./saturn LIB = ./saturn
SRC = main.o input.o GEN_PYTHON_SOURCE = $(wildcard tools/source/*.py) $(wildcard tools/generate/*.py)
SRC += gen/maps.o
SRC += gen/map_objects.o GEN_SRC =
SRC += gen/sprites.o GEN_SRC += gen/maps.cpp
DEP = $(patsubst %.o,%.d,$(SRC)) GEN_SRC += gen/map_objects.cpp
GEN_SRC += gen/sprites.cpp
SRC =
SRC += $(GEN_SRC)
SRC += main.cpp
SRC += input.cpp
DEP = $(patsubst %.cpp,%.cpp.d,$(SRC))
res = $(subst pokered/,res/,$(patsubst %.$(1),%.$(1).o,$(wildcard $(2)*.$(1)))) res = $(subst pokered/,res/,$(patsubst %.$(1),%.$(1).o,$(wildcard $(2)*.$(1))))
res_png = $(subst pokered/,res/,$(patsubst %.png,%.$(1).o,$(wildcard $(2)*.png))) res_png = $(subst pokered/,res/,$(patsubst %.png,%.$(1).o,$(wildcard $(2)*.png)))
@ -17,8 +25,9 @@ GFX_BLOCKSETS = $(call res,bst,pokered/gfx/blocksets/)
GFX_SPRITES = $(call res_png,2bpp,pokered/gfx/sprites/) GFX_SPRITES = $(call res_png,2bpp,pokered/gfx/sprites/)
MAPS_BLOCKS = $(call res,blk,pokered/maps/) MAPS_BLOCKS = $(call res,blk,pokered/maps/)
GENERATED = $(GFX_TILESETS) $(GFX_BLOCKSETS) $(GFX_SPRITES) $(MAPS_BLOCKS) GENERATED = $(GFX_TILESETS) $(GFX_BLOCKSETS) $(GFX_SPRITES) $(MAPS_BLOCKS) $(GEN_SRC)
OBJ = $(SRC) $(GENERATED)
OBJ = $(patsubst %.cpp,%.o,$(SRC) $(GENERATED))
all: main.cue all: main.cue
@ -30,20 +39,16 @@ define LINK_BINARY
ln -sf $(shell realpath --relative-to="$(dir $@)" $<) $@ ln -sf $(shell realpath --relative-to="$(dir $@)" $<) $@
endef endef
GEN_PYTHON_SOURCE = $(wildcard tools/source/*.py) $(wildcard tools/generate/*.py)
define RUN_GENERATE define RUN_GENERATE
@mkdir -p ./gen @mkdir -p ./gen
PYTHONPATH=./tools python -m generate ./pokered ./gen ./res PYTHONPATH=./tools python -m generate ./pokered ./gen ./res
endef endef
gen/%.cpp: $(GEN_PYTHON_SOURCE)
$(RUN_GENERATE)
gen/%.hpp: $(GEN_PYTHON_SOURCE) gen/%.hpp: $(GEN_PYTHON_SOURCE)
$(RUN_GENERATE) $(RUN_GENERATE) $@
generated: $(GENERATED) gen/%.cpp: gen/%.hpp $(GEN_PYTHON_SOURCE)
$(RUN_GENERATE) $@
res/%.2bpp: pokered/%.png res/%.2bpp: pokered/%.png
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@ -85,4 +90,6 @@ clean: clean-sh
clean-sh: clean-sh:
rm -rf res gen rm -rf res gen
PHONY: generated-headers generated: $(GENERATED)
PHONY: generated

128
main.cpp
View File

@ -15,8 +15,6 @@
#include "gen/maps.hpp" #include "gen/maps.hpp"
#include "gen/sprites.hpp" #include "gen/sprites.hpp"
#include "map_objects.hpp" #include "map_objects.hpp"
#include "maps.hpp" // hack?
#include "sprites.hpp"
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b) constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
{ {
@ -88,8 +86,8 @@ constexpr inline void render_block(const uint32_t base_pattern,
const int32_t block_ix = 4 * block_y + block_x; const int32_t block_ix = 4 * block_y + block_x;
const uint8_t tile_ix = tileset.blockset.start[block * 4 * 4 + block_ix]; const uint8_t tile_ix = tileset.blockset.start[block * 4 * 4 + block_ix];
const int32_t cell_y = map_y * 4 + block_y; const uint32_t cell_y = map_y * 4 + block_y;
const int32_t cell_x = map_x * 4 + block_x; const uint32_t cell_x = map_x * 4 + block_x;
// assumes NBG0 map plane_a is at offset 0 // assumes NBG0 map plane_a is at offset 0
vdp2.vram.u16[64 * (cell_y % 64) + (cell_x % 64)] = (base_pattern & 0xfff) + tile_ix; vdp2.vram.u16[64 * (cell_y % 64) + (cell_x % 64)] = (base_pattern & 0xfff) + tile_ix;
//vdp2.vram.u32[64 * cell_y + cell_x] = base_pattern + tile_ix; //vdp2.vram.u32[64 * cell_y + cell_x] = base_pattern + tile_ix;
@ -101,25 +99,25 @@ constexpr int32_t last_map = map_t::wardens_house;
struct draw_t { struct draw_t {
struct { struct {
uint16_t tilesets[tilesets_ix_last]; // div 32 uint16_t tilesets[tileset_t::count]; // div 32
uint16_t spritesheets[spritesheets_ix_last]; // div 128 uint16_t spritesheets[spritesheet_t::count]; // div 128
} base_pattern; } base_pattern;
}; };
struct player_t { struct player_t {
struct { struct {
int16_t x; int32_t x;
int16_t y; int32_t y;
}; };
}; };
struct state_t { struct state_t {
int32_t map_ix; enum map_t::map map;
draw_t draw; draw_t draw;
player_t player; player_t player;
}; };
static state_t state = { 0 }; static state_t state = { map_t::pallet_town, 0 };
uint32_t load_tileset(uint32_t top, enum tileset_t::tileset tileset) uint32_t load_tileset(uint32_t top, enum tileset_t::tileset tileset)
{ {
@ -146,17 +144,17 @@ void load_vram()
vdp2.reg.CYCB1 = 0xeeee'eeee; vdp2.reg.CYCB1 = 0xeeee'eeee;
uint32_t vdp2_top = (sizeof (union vdp2_vram)); uint32_t vdp2_top = (sizeof (union vdp2_vram));
for (uint32_t i = 0; i < tilesets_ix_last; i++) for (uint32_t i = 0; i < tileset_t::count; i++)
vdp2_top = load_tileset(vdp2_top, tilesets_ix[i]); vdp2_top = load_tileset(vdp2_top, static_cast<enum tileset_t::tileset>(i));
vdp2.reg.CYCA0 = 0x0121'ffff; vdp2.reg.CYCA0 = 0x0fff'ffff;
vdp2.reg.CYCA1 = 0x0121'ffff; vdp2.reg.CYCA1 = 0x0fff'ffff;
vdp2.reg.CYCB0 = 0x4565'ffff; vdp2.reg.CYCB0 = 0x4fff'ffff;
vdp2.reg.CYCB1 = 0x4565'ffff; vdp2.reg.CYCB1 = 0x4fff'ffff;
uint32_t vdp1_top = (sizeof (union vdp1_vram)); uint32_t vdp1_top = (sizeof (union vdp1_vram));
for (uint32_t i = 0; i < spritesheets_ix_last; i++) for (uint32_t i = 0; i < spritesheet_t::count; i++)
vdp1_top = load_sprite(vdp1_top, spritesheets_ix[i]); vdp1_top = load_sprite(vdp1_top, static_cast<enum spritesheet_t::spritesheet>(i));
} }
// screen space // screen space
@ -244,16 +242,54 @@ static uint16_t scroll = 0;
*/ */
void render_map() // there are 16 pixels per block
static inline uint8_t get_block(const map_t& map, int32_t block_x, int32_t block_y)
{ {
if (++scroll > 64) { const uint8_t border_block = map_objects[state.map].border_block;
scroll = 0;
state.player.x += 1; const bool x_lt = block_x < static_cast<int32_t>(map.width);
state.player.y += 1; const bool y_lt = block_y < static_cast<int32_t>(map.height);
const bool x_gt = block_x >= 0;
const bool y_gt = block_y >= 0;
const bool inside_map = x_lt && y_lt && x_gt && y_gt;
const bool north = x_lt && x_gt && !(y_gt);
const bool south = x_lt && x_gt && !(y_lt);
const bool west = y_lt && y_gt && !(x_gt);
const bool east = y_lt && y_gt && !(x_lt);
#define _has(dir) (map.connections[map_t::connection_t::dir].map != map_t::unconnected)
#define _get(dir) (maps[map.connections[map_t::connection_t::dir].map])
#define _offset(dir) (map.connections[map_t::connection_t::dir].offset)
if (inside_map) {
return map.blocks.start[map.width * block_y + block_x];
} else if (north && _has(north)) {
const map_t& north_map = _get(north);
const uint32_t north_y = north_map.height + block_y;
const uint32_t north_x = block_x - _offset(north);
return get_block(north_map, north_x, north_y);
} else {
return border_block;
} }
vdp2.reg.SCXIN0 = (state.player.x - 1) * 16 + (scroll / 4); #undef _offset
vdp2.reg.SCYIN0 = (state.player.y - 1) * 16 + (scroll / 4); #undef _get
#undef _has
}
void render_map()
{
state.player.x = 8 * 16;
if (++scroll > 1) {
scroll = 0;
//state.player.x += 1;
state.player.y -= 1;
}
vdp2.reg.SCXIN0 = state.player.x - 16;
vdp2.reg.SCYIN0 = state.player.y - 16;
/* /*
vdp2.reg.WPSX0 = 80 << 1; vdp2.reg.WPSX0 = 80 << 1;
vdp2.reg.WPSY0 = 48; vdp2.reg.WPSY0 = 48;
@ -262,27 +298,18 @@ void render_map()
vdp2.reg.WCTLA = WCTLA__N0W0E | WCTLA__N0W0A__OUTSIDE; vdp2.reg.WCTLA = WCTLA__N0W0E | WCTLA__N0W0A__OUTSIDE;
*/ */
const map_t& map = maps[maps_ix[state.map_ix]]; const map_t& map = maps[state.map];
const uint8_t border_block = map_objects[maps_ix[state.map_ix]].border_block;
const uint32_t base_pattern = state.draw.base_pattern.tilesets[map.tileset]; const uint32_t base_pattern = state.draw.base_pattern.tilesets[map.tileset];
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((base_pattern >> 10) & 0x1f); vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((base_pattern >> 10) & 0x1f);
int32_t origin_x = state.player.x / 2; int32_t origin_x = state.player.x / 32;
int32_t origin_y = state.player.y / 2; int32_t origin_y = state.player.y / 32;
int32_t offset_x = state.player.x & 1;
int32_t offset_y = state.player.y & 1;
fill<uint32_t>(vdp2.vram.u32, 0, 64 * 64 * 2); fill<uint32_t>(vdp2.vram.u32, 0, 64 * 64 * 2);
for (int32_t y = origin_y - 3 + offset_x; y <= (origin_y + 2 + offset_x); y++) { for (int32_t y = origin_y - 3; y <= (origin_y + 3); y++) {
for (int32_t x = origin_x - 3 + offset_y; x <= (origin_x + 3 + offset_y); x++) { for (int32_t x = origin_x - 3; x <= (origin_x + 3); x++) {
const uint8_t block = ( (x < static_cast<int32_t>(map.width)) const uint8_t block = get_block(map, x, y);
&& (y < static_cast<int32_t>(map.height))
&& (x >= 0)
&& (y >= 0))
? map.blocks.start[map.width * y + x]
: border_block;
//const uint8_t block = map.blocks.start[map.width * 0 + 0];
render_block(base_pattern, render_block(base_pattern,
tilesets[map.tileset], tilesets[map.tileset],
@ -301,19 +328,6 @@ void render()
render_sprites(); render_sprites();
} }
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;
}
}
extern "C" extern "C"
void v_blank_in_int(void) __attribute__ ((interrupt_handler)); void v_blank_in_int(void) __attribute__ ((interrupt_handler));
void v_blank_in_int() void v_blank_in_int()
@ -326,7 +340,6 @@ void v_blank_in_int()
sh2.reg.FTCSR = 0; // clear flags sh2.reg.FTCSR = 0; // clear flags
render(); render();
update();
// wait at least 300us, as specified in the SMPC manual. // wait at least 300us, as specified in the SMPC manual.
// It appears reading FRC.H is mandatory and *must* occur before FRC.L on real // It appears reading FRC.H is mandatory and *must* occur before FRC.L on real
@ -421,8 +434,8 @@ void init_vdp2()
vdp2.reg.CHCTLA = CHCTLA__N0CHCN__16_COLOR vdp2.reg.CHCTLA = CHCTLA__N0CHCN__16_COLOR
| CHCTLA__N0BMEN__CELL_FORMAT | CHCTLA__N0BMEN__CELL_FORMAT
| CHCTLA__N0CHSZ__1x1_CELL | CHCTLA__N0CHSZ__1x1_CELL
| CHCTLA__N1CHCN__16_COLOR | CHCTLA__N1CHCN__16_COLOR
| CHCTLA__N1BMEN__CELL_FORMAT | CHCTLA__N1BMEN__CELL_FORMAT
| CHCTLA__N1CHSZ__1x1_CELL; | CHCTLA__N1CHSZ__1x1_CELL;
/* plane size */ /* plane size */
@ -462,7 +475,8 @@ void init_vdp2()
void main() void main()
{ {
state.map_ix = map_t::pallet_town; state.map = map_t::pallet_town;
state.player.y = 16 * 8;
load_vram(); load_vram();

View File

@ -3,6 +3,7 @@
#include <cstdint> #include <cstdint>
#include "gen/maps.hpp" #include "gen/maps.hpp"
#include "gen/sprites.hpp"
struct position_t { struct position_t {
uint8_t x; uint8_t x;
@ -44,12 +45,12 @@ struct object_event_t {
left, left,
right, right,
none, none,
boulder_movement_byte_2, boulder_movement_byte_2, // fixme
}; };
enum type type; enum type type;
position_t position; position_t position;
uint8_t sprite_id; // fixme enum spritesheet_t::spritesheet sprite_id; // fixme
enum movement movement; enum movement movement;
enum range_or_direction range_or_direction; enum range_or_direction range_or_direction;
uint8_t text_id; // fixme uint8_t text_id; // fixme

255
maps.hpp
View File

@ -1,255 +0,0 @@
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));
enum tileset_t::tileset tilesets_ix[] = {
tileset_t::cavern,
tileset_t::cemetery,
tileset_t::club,
tileset_t::dojo,
tileset_t::facility,
tileset_t::forest,
tileset_t::forest_gate,
tileset_t::gate,
tileset_t::gym,
tileset_t::house,
tileset_t::interior,
tileset_t::lab,
tileset_t::lobby,
tileset_t::mansion,
tileset_t::mart,
tileset_t::museum,
tileset_t::overworld,
tileset_t::plateau,
tileset_t::pokecenter,
tileset_t::reds_house_1,
tileset_t::reds_house_2,
tileset_t::ship,
tileset_t::ship_port,
tileset_t::underground,
};
constexpr int tilesets_ix_last = (sizeof (tilesets_ix)) / (sizeof (enum tileset_t::tileset));

View File

@ -1,77 +0,0 @@
enum spritesheet_t::spritesheet spritesheets_ix[] = {
spritesheet_t::agatha,
spritesheet_t::balding_guy,
spritesheet_t::beauty,
spritesheet_t::biker,
spritesheet_t::bike_shop_clerk,
spritesheet_t::bird,
spritesheet_t::blue,
spritesheet_t::boulder,
spritesheet_t::brunette_girl,
spritesheet_t::bruno,
spritesheet_t::captain,
spritesheet_t::channeler,
spritesheet_t::clerk,
spritesheet_t::clipboard,
spritesheet_t::cook,
spritesheet_t::cooltrainer_f,
spritesheet_t::cooltrainer_m,
spritesheet_t::daisy,
spritesheet_t::fairy,
spritesheet_t::fisher,
spritesheet_t::fishing_guru,
spritesheet_t::fossil,
spritesheet_t::gambler,
spritesheet_t::gambler_asleep,
spritesheet_t::gameboy_kid,
spritesheet_t::gentleman,
spritesheet_t::giovanni,
spritesheet_t::girl,
spritesheet_t::gramps,
spritesheet_t::granny,
spritesheet_t::guard,
spritesheet_t::gym_guide,
spritesheet_t::hiker,
spritesheet_t::koga,
spritesheet_t::lance,
spritesheet_t::link_receptionist,
spritesheet_t::little_boy,
spritesheet_t::little_girl,
spritesheet_t::lorelei,
spritesheet_t::middle_aged_man,
spritesheet_t::middle_aged_woman,
spritesheet_t::mom,
spritesheet_t::monster,
spritesheet_t::mr_fuji,
spritesheet_t::none,
spritesheet_t::nurse,
spritesheet_t::oak,
spritesheet_t::old_amber,
spritesheet_t::paper,
spritesheet_t::pokedex,
spritesheet_t::poke_ball,
spritesheet_t::red,
spritesheet_t::rocker,
spritesheet_t::rocket,
spritesheet_t::safari_zone_worker,
spritesheet_t::sailor,
spritesheet_t::scientist,
spritesheet_t::seel,
spritesheet_t::silph_president,
spritesheet_t::silph_worker_f,
spritesheet_t::silph_worker_m,
spritesheet_t::snorlax,
spritesheet_t::super_nerd,
spritesheet_t::swimmer,
spritesheet_t::unused_gambler_asleep_1,
spritesheet_t::unused_gambler_asleep_2,
spritesheet_t::unused_gameboy_kid,
spritesheet_t::unused_guard,
spritesheet_t::unused_old_amber,
spritesheet_t::unused_scientist,
spritesheet_t::waiter,
spritesheet_t::warden,
spritesheet_t::youngster,
};
constexpr int spritesheets_ix_last = (sizeof (spritesheets_ix)) / (sizeof (enum spritesheet_t::spritesheet));

View File

@ -2,24 +2,17 @@ from pathlib import Path
from pprint import pprint from pprint import pprint
import sys import sys
from generate import maps from generate.files import files
from generate import map_objects
from generate import sprites
files = [ def generate(base_path, target_path):
(maps.generate_maps_header, "maps.hpp"),
(maps.generate_maps_source, "maps.cpp"),
(map_objects.generate_map_objects_source, "map_objects.cpp"),
(sprites.generate_sprites_header, "sprites.hpp"),
(sprites.generate_sprites_source, "sprites.cpp"),
]
def generate(base_path):
for func, filename in files: for func, filename in files:
path = base_path / filename path = base_path / filename
if path != target_path:
continue
with open(path, 'w') as f: with open(path, 'w') as f:
f.write(func().getvalue()) f.write(func().getvalue())
# sys.argv[1] is secretly used in parse # sys.argv[1] is secretly used in parse
base_path = Path(sys.argv[2]) base_path = Path(sys.argv[2])
generate(base_path) target_path = Path(sys.argv[4])
generate(base_path, target_path)

11
tools/generate/files.py Normal file
View File

@ -0,0 +1,11 @@
from generate import maps
from generate import map_objects
from generate import sprites
files = [
(maps.generate_maps_header, "maps.hpp"),
(maps.generate_maps_source, "maps.cpp"),
(map_objects.generate_map_objects_source, "map_objects.cpp"),
(sprites.generate_sprites_header, "sprites.hpp"),
(sprites.generate_sprites_source, "sprites.cpp"),
]

View File

@ -2,6 +2,7 @@ from parse import parse
from generate.generate import renderer from generate.generate import renderer
from generate.maps import sorted_map_headers from generate.maps import sorted_map_headers
from generate.sprites import sprite_name
def warp_event(ev): def warp_event(ev):
x, y = ev.position x, y = ev.position
@ -36,7 +37,7 @@ def object_event(ev):
"{", "{",
f".type = object_event_t::type::{ev.type},", f".type = object_event_t::type::{ev.type},",
f".position = {{ {x}, {y} }},", f".position = {{ {x}, {y} }},",
".sprite_id = 0,", # fixme f".sprite_id = spritesheet_t::{sprite_name(ev.sprite_id)},",
f".movement = object_event_t::movement::{ev.movement.lower()},", f".movement = object_event_t::movement::{ev.movement.lower()},",
*(range_or_direction(ev)), *(range_or_direction(ev)),
".text_id = 0,", # fixme ".text_id = 0,", # fixme

View File

@ -19,6 +19,10 @@ from generate.sort import default_sort
from generate.binary import binary_res, start_size_value from generate.binary import binary_res, start_size_value
from generate.generate import renderer from generate.generate import renderer
from parse.map_header import Connection
directions = sorted(['north', 'south', 'east', 'west'])
def sorted_map_constants_list(): def sorted_map_constants_list():
return sorted(parse.map_constants_list.items(), key=default_sort) return sorted(parse.map_constants_list.items(), key=default_sort)
@ -57,9 +61,10 @@ def includes_header():
yield "" yield ""
def struct_tileset_t(): def struct_tileset_t():
_sorted_tilesets_constants_list = list(sorted_tilesets_constants_list())
tileset_names = ( tileset_names = (
f"{name.lower()}," f"{name.lower()},"
for name, _ in sorted_tilesets_constants_list() for name, _ in _sorted_tilesets_constants_list
) )
return [ return [
"struct tileset_t {", "struct tileset_t {",
@ -69,25 +74,46 @@ def struct_tileset_t():
"enum tileset {", "enum tileset {",
*tileset_names, *tileset_names,
"};", "};",
"",
f"static constexpr int32_t count = {len(_sorted_tilesets_constants_list)};",
"};", "};",
] ]
def struct_map_t(): def struct_map_t():
_sorted_map_headers = list(sorted_map_headers())
map_names = ( map_names = (
f"{map_header.name2.lower()}," f"{map_header.name2.lower()},"
for map_header in sorted_map_headers() for map_header in _sorted_map_headers
) )
return [ return [
"struct map_t {", "struct map_t {",
"enum map {",
*map_names,
"last_map, // special map name",
"unused_map_ed, // special silph co elevator map name",
"unconnected, // special unconnected map",
"};",
"",
*struct_connection_t(),
"",
"start_size_t blocks;", "start_size_t blocks;",
"enum tileset_t::tileset tileset;", "enum tileset_t::tileset tileset;",
"uint32_t width;", "uint32_t width;",
"uint32_t height;", "uint32_t height;",
"connection_t connections[4];",
"", "",
"enum map {", f"static constexpr int32_t count = {len(_sorted_map_headers)};",
*map_names, "};",
"last_map,", # special map name ]
"unused_map_ed,", # special silph co elevator map name
def struct_connection_t():
return [
"struct connection_t {",
"enum map_t::map map;",
"int8_t offset;",
"",
"enum direction {",
*(f"{d}," for d in directions),
"};", "};",
"};", "};",
] ]
@ -119,6 +145,25 @@ def tilesets():
yield from blockset_tileset(name) yield from blockset_tileset(name)
yield "};" yield "};"
def connections(map_header):
cs = dict((c.name, c) for c in map_header.connections)
assert len(cs) == len(map_header.connections), map_header.connections
unconnected = Connection(
name = "__invalid",
map_name1 = "Unconnected",
map_name2 = "unconnected",
offset = 0,
)
for direction in directions: # already sorted
connection = cs.get(direction, unconnected)
yield f"[map_t::connection_t::{direction}] = {{"
yield f".map = map_t::{connection.map_name2.lower()},"
yield f".offset = {connection.offset},"
yield "},"
def map(map_header): def map(map_header):
block_path = parse.maps_blocks_list[map_header.blocks()] block_path = parse.maps_blocks_list[map_header.blocks()]
map_constant = parse.map_constants_list[map_header.name2] map_constant = parse.map_constants_list[map_header.name2]
@ -130,6 +175,9 @@ def map(map_header):
f".tileset = tileset_t::{map_header.tileset.lower()},", f".tileset = tileset_t::{map_header.tileset.lower()},",
f".width = {map_constant.width},", f".width = {map_constant.width},",
f".height = {map_constant.height},", f".height = {map_constant.height},",
".connections = {",
*connections(map_header),
"},",
"},", "},",
] ]

View File

@ -40,9 +40,10 @@ def sprite_name(name):
return name.removeprefix('SPRITE_').lower() return name.removeprefix('SPRITE_').lower()
def struct_spritesheet_t(): def struct_spritesheet_t():
_sorted_sprite_constants_list = list(sorted_sprite_constants_list())
sprite_names = ( sprite_names = (
f"{sprite_name(name)}," f"{sprite_name(name)},"
for name, _ in sorted_sprite_constants_list() for name, _ in _sorted_sprite_constants_list
) )
return [ return [
"struct spritesheet_t {", "struct spritesheet_t {",
@ -52,6 +53,8 @@ def struct_spritesheet_t():
"enum spritesheet {", "enum spritesheet {",
*sprite_names, *sprite_names,
"};", "};",
"",
f"static constexpr int32_t count = {len(_sorted_sprite_constants_list)};",
"};", "};",
] ]

View File

@ -0,0 +1,8 @@
import sys
from pathlib import Path
from generate.files import files
base_path = Path(sys.argv[1])
for _, filename in files:
print(base_path / filename)

View File

@ -1,5 +1,5 @@
from pprint import pprint from pprint import pprint
from parse import parse from parse import parse
for i in parse.sprite_constants_list: for i in parse.map_objects_list.items():
pprint(i) pprint(i)

View File

@ -49,6 +49,16 @@ class MapHeader:
def height(self): def height(self):
return f"{self.name2}_HEIGHT" return f"{self.name2}_HEIGHT"
@dataclass
class Connection:
name: str
map_name1: str
map_name2: str
offset: int
def parse_connection():
return
def flatten(tokens): def flatten(tokens):
# expects tokens from a single file # expects tokens from a single file
@ -63,14 +73,32 @@ def flatten(tokens):
map_headers = [s for s in tokens if s[0] == 'map_header'] map_headers = [s for s in tokens if s[0] == 'map_header']
assert len(map_headers) == 1 assert len(map_headers) == 1
map_header, = map_headers map_header, = map_headers
_, (name1, name2, tileset, connection_mask) = map_header _, (name1, name2, tileset, connection_mask0) = map_header
connections = [s for s in tokens if s[0] == 'connection'] connections = [s[1] for s in tokens if s[0] == 'connection']
connection_mask = connection_mask0 if type(connection_mask0) is list else [connection_mask0]
null_mask = lambda m: (
len(m) == 1 and any(m[0] == n for n in {'0', '$0', '$00'})
)
connection_names = (
[] if null_mask(connection_mask) else connection_mask
)
return MapHeader( return MapHeader(
name1 = name1, name1 = name1,
name2 = name2, name2 = name2,
tileset = tileset, tileset = tileset,
connection_names = [] if connection_mask == '0' else connection_mask, connection_names = sorted(connection_names),
connections = [tuple(c[1]) for c in connections] connections = list(sorted(
(
Connection(
name,
map_name1,
map_name2,
int(offset)
)
for name, map_name1, map_name2, offset in connections
),
key=lambda c: c.name))
) )
def parse(path): def parse(path):