#include #include #include "device/device.h" #include "sys/sys.h" #include "game.h" #define GAME_DIALOGUE_MAX_N_CHARS 256 typedef enum { GAME_DIALOGUE_SCREEN_STATE_BOB_IN, GAME_DIALOGUE_SCREEN_STATE_TYPEWRITER, GAME_DIALOGUE_SCREEN_STATE_WAIT, GAME_DIALOGUE_SCREEN_STATE_BOB_OUT, } game_dialogue_screen_state; struct { bool visible; bool modal; const char* dialogue; sys_i32 w; sys_i32 h; game_dialogue_screen_state state; sys_i32 state_progress; sys_i32 n_chars_shown; sys_i32 n_chars; } game_dialogue_screen; uint8_t game_dialogue_frame; void game_dialogue_display(const char* text, bool modal) { game_dialogue_screen.visible = true; game_dialogue_screen.modal = modal; game_dialogue_screen.dialogue = text; sys_measure_text(text, &game_dialogue_screen.w, &game_dialogue_screen.h); game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_BOB_IN; game_dialogue_screen.state_progress = 0; game_dialogue_screen.n_chars_shown = 0; game_dialogue_screen.n_chars = strlen(text); assert(game_dialogue_screen.n_chars <= GAME_DIALOGUE_MAX_N_CHARS); } void game_dialogue_update(bool* allow_input) { game_dialogue_frame = ((uint32_t) game_dialogue_frame + 1) & 0xff; if ( game_dialogue_screen.visible && game_dialogue_screen.state < GAME_DIALOGUE_SCREEN_STATE_BOB_OUT ) { *allow_input = false; if (sys_btnp(DEVICE_BUTTON_0, false)) { if (game_dialogue_screen.state < GAME_DIALOGUE_SCREEN_STATE_WAIT) { game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_WAIT; game_dialogue_screen.n_chars_shown = game_dialogue_screen.n_chars; } else { game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_BOB_OUT; game_dialogue_screen.state_progress = 0; } } } switch (game_dialogue_screen.state) { case GAME_DIALOGUE_SCREEN_STATE_BOB_IN: game_dialogue_screen.state_progress += 25; if (game_dialogue_screen.state_progress >= 0x100) { game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_TYPEWRITER; game_dialogue_screen.state_progress = 0; } break; case GAME_DIALOGUE_SCREEN_STATE_TYPEWRITER: if (game_dialogue_frame % 4 == 0) { game_dialogue_screen.n_chars_shown = sys_min_i32( game_dialogue_screen.n_chars_shown + 1, game_dialogue_screen.n_chars ); } if (game_dialogue_screen.n_chars_shown >= game_dialogue_screen.n_chars) { game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_WAIT; } break; case GAME_DIALOGUE_SCREEN_STATE_WAIT: break; case GAME_DIALOGUE_SCREEN_STATE_BOB_OUT: game_dialogue_screen.state_progress += 25; if (game_dialogue_screen.state_progress >= 0x100) { game_dialogue_screen.visible = false; game_dialogue_screen.state_progress = 0; } } } bool game_dialogue_is_busy() { return game_dialogue_screen.visible; } void game_dialogue_draw() { if (!game_dialogue_screen.visible) { return; } sys_i32 x = DEVICE_W / 2 - game_dialogue_screen.w / 2; sys_i32 y = DEVICE_H - game_dialogue_screen.h - 8; if (game_dialogue_screen.modal) { y = DEVICE_H / 2 - game_dialogue_screen.h / 2; } sys_i32 interp_amt = 0; switch (game_dialogue_screen.state) { case GAME_DIALOGUE_SCREEN_STATE_BOB_IN: interp_amt = 255 - game_dialogue_screen.state_progress; break; case GAME_DIALOGUE_SCREEN_STATE_BOB_OUT: interp_amt = game_dialogue_screen.state_progress; break; default: break; } int x0 = x - 4; int y0 = y - 4; int x1 = x + game_dialogue_screen.w + 4; int y1 = y + game_dialogue_screen.h + 4; sys_i32 cx = (x0 + x1)/2; sys_i32 cy = (y0 + y1)/2; sys_oval_fill( x0 + (cx - x0) * interp_amt / 256, y0 + (cy - y0) * interp_amt / 256, x1 + (cx - x1) * interp_amt / 256, y1 + (cy - y1) * interp_amt / 256, game_dialogue_screen.modal ? 0 : 1 ); if (game_dialogue_screen.state == GAME_DIALOGUE_SCREEN_STATE_BOB_OUT) { return; } char chars[GAME_DIALOGUE_MAX_N_CHARS + 1]; strcpy(chars, game_dialogue_screen.dialogue); chars[game_dialogue_screen.n_chars_shown] = 0; if (game_dialogue_screen.modal) { for (int dy = -2; dy <= 2; dy++) { for (int dx = -2; dx <= 2; dx++) { sys_print(chars, x+dx, y+dy, 8); } } } for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { sys_print(chars, x+dx, y+dy, 0); } } sys_print(chars, x, y, 7); }