From 60c346406c0b4744a3a9efc4b24e7558b2228ac5 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 31 Jul 2023 18:08:59 +0000 Subject: [PATCH] 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. --- derived/font.png | Bin 5222 -> 5212 bytes font.cpp | 3 ++- font.hpp | 1 + graphic.cpp | 48 +++++++++++++++++++++++++++++++++++++++-- graphic.hpp | 5 ++++- input.hpp | 1 + main.cpp | 20 +++++++++++++++-- start_size.hpp | 2 ++ tools/generate/maps.py | 20 +++++++++++------ 9 files changed, 88 insertions(+), 12 deletions(-) diff --git a/derived/font.png b/derived/font.png index 3dc7acbd3d4dd26bb85d6449738f1bcfc35cbea2..3e60100ee1093bd93365cc6c557d570559531009 100644 GIT binary patch delta 987 zcmV<110?+BDBLKJM1R2%10e|fTSZDhmQyUp%Ux#DLCOy*X3iu#Bdn~hNH|~5N4Pa` zlptHyR8k^?6e(PdC=JveBT0`PQ?mV14>AR|5-h_nBtJjv@nbMjHMU)h^zOpG3dLVw z{W9W_&^l`TaHHZz;2}gesN-9distJV_LElVSfK^cwe6pMwk_!$o4o_(6A@$)kkJ6z zLO?Z=EduQzp%@pWURO7>f&81(M0f+``&k@PoD@p2@OlFzI5apmHDxh5Ej45`G%YkV zWo0cnWnyD3F=aD1IX7WBI5;_Fla2%*Brr2!Wn*P#GA%YTW;QJ}Wo2Y7VKO#hEi^VW zGh||AVlg#kVw2GXCnPXAHaBEBWi~A|HexX?G&VJ6EjVRiWi2-_WimNtW@2MFF)))H z1zij`F)%YWI5{^oHZ(btg#~m6IXW~pIxskr1}6tOIy5#qFgTMg28tvwI5IggVrFD5 zIXN*iEi`0dV=Xu|WMnO2GC5^9H!(3~H)Udz+y+huIXW~pIxsl1F$Zo41b;*yN0Xxu zAqxpE2+w}Uw*UYHd9%+CVgi4n!iQsoXbW$!jET!ij+wLPc>r@|!?m7Er+|WGin;+t zW)l2D7)x=Qcz=ntTla?N?6np?n_zQbt{LLXuc!Ilw$sA~viXpet zJqD1#aH zhnMKXOY}iodA_=sumx#l#A#?m9vmWI;X3}D2>RduVutq!Kw`gP+-Ce^ zJThhU|HKl)`!=Ap4yI zZH06uGk_h3w3ObpTglzzQmKFDz)=|c`gA(iSLwsq+K1YV)_2fVx0PE{@ z5OPPR+)X%kq1p>n zzKlo%Mn@w*&8V6YNQGbqO~2(+E&2L|qx&62mm9=oZ~JGTWi5JVly^YX5#WUZ)&?*Z z9GWCq7#IhoWyvFWR)U$yK>p2X!My?Fm01s~V13%L@OlFzG&43ZG-f$7EjTeTGA%SW zF)%G+IXGc0F*9a0WHd81G&M70la2%*BxW`>H8?jlH!Ws0G&3zUWHU7_I5RdkEiz#> zW-($jHZwC~IFr!?CnPgBFflYSH!&?@Gh;F>G+{DiEjTncGc7hSIW%H4V=_4~F*1`J z1zij_I5IFdF*7(YH8D4ng#~m6F*-FgIx{hn1}6tGIyE#pGcl7c28tvxI5|0DV>V?i zH!w9~Ei^DNH7#LeWHBvcIA&%!Wn?sDGiEcB+y+huF*-FgIx{h|F$Zo41PGHBhLfWY zAqxREAHb!HkpKV$gR{>MVgi3^eKBcoD9I(2l>1d|YNTNBeV6kg6= zsTguQwSe&|maDa!8(<7TrV4}64-lRnUwZI1gCfYM5ne^g%E71<9$bH{j@7X254KVb zT#+P>Z#5m34o1L#pgwT?%rWpu#SFay{1gGXa2RSt7`7Rb*RTKBXR=CxCXUMtN1efF zdp$=h&(Z3`OZ4F-`tTBc&{m$WE+%Y2S{ZQ~8WH(EePqg?xS9ut2w1p|KPQ6z_rI9o zJpz!}Zy2{3|JeB9nyr6rIDk(n!36Sg3k|(@%XIIjSPS#b<1kcu))Pa&u4X3LwW8M8<%+)s*Pct7m`9fd$}+sBIBW`7o1f z#v`hrEc@%Qi%D72)Iz1e0CJnCX={0I-9_U?hAL4OU%OFHlye*x(m TdiUlV00000NkvXXu0mjfM&_dx diff --git a/font.cpp b/font.cpp index 97279f6..959146a 100644 --- a/font.cpp +++ b/font.cpp @@ -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; diff --git a/font.hpp b/font.hpp index 0ce032e..b33598d 100644 --- a/font.hpp +++ b/font.hpp @@ -3,3 +3,4 @@ #include uint32_t load_font(uint32_t top); +uint8_t ascii_to_font(uint8_t c); diff --git a/graphic.cpp b/graphic.cpp index 05313fb..23d7a61 100644 --- a/graphic.cpp +++ b/graphic.cpp @@ -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++; + } } diff --git a/graphic.hpp b/graphic.hpp index 44c3313..2da2324 100644 --- a/graphic.hpp +++ b/graphic.hpp @@ -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); }; diff --git a/input.hpp b/input.hpp index 638c417..fb1ee62 100644 --- a/input.hpp +++ b/input.hpp @@ -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; } }; diff --git a/main.cpp b/main.cpp index 3caaa12..39b7135 100644 --- a/main.cpp +++ b/main.cpp @@ -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(&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; diff --git a/start_size.hpp b/start_size.hpp index 776059c..0d20088 100644 --- a/start_size.hpp +++ b/start_size.hpp @@ -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; diff --git a/tools/generate/maps.py b/tools/generate/maps.py index e86e7b4..5fb103b 100644 --- a/tools/generate/maps.py +++ b/tools/generate/maps.py @@ -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 ' yield '' yield '#include "maps.hpp"' + yield '#include "text_pointers.hpp"' yield '' def generate_source():