basic sign rendering

All defined signs are now interactable, but the sign message is not
dismissable yet, and only the first paragraph is displayed in
multi-paragraph signs.
This commit is contained in:
Zack Buhman 2023-07-31 18:08:59 +00:00
parent c2ea17d25a
commit 60c346406c
9 changed files with 88 additions and 12 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -6,7 +6,7 @@
#include "font.hpp"
#include "control.hpp"
constexpr inline uint8_t ascii_to_font(uint8_t c)
uint8_t ascii_to_font(uint8_t c)
{
if (c >= 'A' && c <= 'Z')
return (c - 'A') + 0;
@ -16,6 +16,7 @@ constexpr inline uint8_t ascii_to_font(uint8_t c)
return (c - '0') + 64;
switch (c) {
case ' ': return 0x4f;
case '!': return 0x1a;
case '(': return 0x1b;
case ')': return 0x1c;

View File

@ -3,3 +3,4 @@
#include <cstdint>
uint32_t load_font(uint32_t top);
uint8_t ascii_to_font(uint8_t c);

View File

@ -4,7 +4,9 @@
#include "coordinates.hpp"
#include "graphic.hpp"
#include "font.hpp"
#include "start_size.hpp"
#include "control.hpp"
#include "render_map.hpp"
struct dialog_border {
@ -64,7 +66,49 @@ void draw_box_border(const uint32_t base_pattern,
}
}
void dialog_t::draw(const uint32_t base_pattern)
void dialog_t::draw(const uint32_t base_pattern,
const start_size_t& text)
{
draw_box_border(base_pattern, top_left, bottom_right);
for (uint32_t x = top_left.x + 1; x < bottom_right.x; x++) {
put_char(base_pattern, x, top_left.y + 1, ascii_to_font(' '));
put_char(base_pattern, x, top_left.y + 2, ascii_to_font(' '));
put_char(base_pattern, x, top_left.y + 3, ascii_to_font(' '));
put_char(base_pattern, x, top_left.y + 4, ascii_to_font(' '));
}
uint32_t ix = 0;
uint32_t x = top_left.x + 1;
uint32_t y = top_left.y + 2;
// ignore C-string null terminator
while (ix < (text.size - 1)) {
const uint8_t c = text.start[ix];
switch (c) {
case control_t::text: break;
case control_t::done: break;
case control_t::prompt: break;
case control_t::page: break;
case control_t::next: [[fallthrough]];
case control_t::line:
while (x < bottom_right.x) {
put_char(base_pattern, x, y, ascii_to_font(' '));
x++;
}
x = top_left.x + 1;
y += 2;
break;
case control_t::para: [[fallthrough]];
case control_t::cont:
// fixme:
ix = text.size;
break;
default:
put_char(base_pattern, x, y, ascii_to_font(c));
x += 1;
break;
}
ix++;
}
}

View File

@ -1,9 +1,12 @@
#pragma once
#include "start_size.hpp"
struct dialog_t
{
static constexpr screen_t top_left = { 0, 12};
static constexpr screen_t bottom_right = {19, 17};
static void draw(const uint32_t base_pattern);
static void draw(const uint32_t base_pattern,
const start_size_t& text);
};

View File

@ -56,4 +56,5 @@ struct event {
static inline bool cursor_right() { return input_flopped(input.right) >= 1; }
static inline bool cursor_up() { return input_flopped(input.up ) >= 1; }
static inline bool cursor_down() { return input_flopped(input.down ) >= 1; }
static inline bool button_a() { return input_flopped(input.a ) == 1; }
};

View File

@ -394,6 +394,22 @@ void update_warp()
}
}
void check_sign()
{
const world_t coord = direction_offset(state.player.world, state.player.facing);
const map_t& map = maps[state.map];
const object_t& obj = map_objects[state.map];
for (uint32_t i = 0; i < obj.bg_length; i++) {
const bg_event_t& event = obj.bg_events[i];
const bool position_match = event.position.x == coord.x && event.position.y == coord.y;
if (position_match && event.sign_id != 0xff) {
const start_size_t& text = map.text_pointers[event.sign_id];
dialog_t::draw(state.draw.base_pattern.font, text);
}
}
}
void update()
{
state.player.tick();
@ -404,6 +420,7 @@ void update()
else if (event::cursor_right()) collision_move(maps[state.map], actor_t::right);
else if (event::cursor_up() ) collision_move(maps[state.map], actor_t::up);
else if (event::cursor_down() ) collision_move(maps[state.map], actor_t::down);
else if (event::button_a() ) check_sign();
}
void render()
@ -559,14 +576,13 @@ void init_vdp2()
const uint32_t value = ((base_pattern + 127) & 0xfff) | PATTERN_NAME_TABLE_1WORD__PALETTE(1);
fill<uint32_t>(&vdp2.vram.u32[0x2000 / 4], value | value << 16, 0x2000);
dialog_t::draw(state.draw.base_pattern.font);
palette_data();
}
void main()
{
state.map = map_t::pallet_town;
//state.map = map_t::pewter_gym;
//state.map = map_t::viridian_forest;
//state.map = map_t::route_2;
state.player.world.x = 6;

View File

@ -6,3 +6,5 @@ struct start_size_t {
uint8_t const * const start;
uint32_t size;
};
typedef start_size_t const * const start_size_ptr_t;

View File

@ -64,7 +64,7 @@ def struct_map_t():
*struct_connection_t(),
"",
"start_size_t blocks;",
"start_size_t text_pointers;",
"start_size_ptr_t text_pointers;",
"uint32_t width;",
"uint32_t height;",
"connection_t connections[4];",
@ -106,9 +106,18 @@ def connections(map_header):
yield f".offset = {connection.offset},"
yield "},"
def text_pointers(map_header):
if map_header.name1 == "ViridianMart":
# fixme: viridianmart
return
else:
#array_size = f"(sizeof ({map_header.text_pointers()}))"
#type_size = f"(sizeof (start_size_t))"
#yield f".start = &{map_header.text_pointers()}[0],"
#yield f".length = {array_size} / {type_size},"
yield f".text_pointers = &{map_header.text_pointers()}[0],"
def map(map_header):
block_path = parse.maps_blocks_list()[map_header.blocks()]
map_constant = parse.map_constants_list()[map_header.name2]
return [
@ -116,9 +125,7 @@ def map(map_header):
".blocks = {",
*start_size_value(block_path),
"},",
".text_pointers = {",
"},",
*text_pointers(map_header),
f".width = {map_constant.width},",
f".height = {map_constant.height},",
".connections = {",
@ -149,6 +156,7 @@ def includes_source():
yield '#include <cstdint>'
yield ''
yield '#include "maps.hpp"'
yield '#include "text_pointers.hpp"'
yield ''
def generate_source():