138 lines
4.3 KiB
C
138 lines
4.3 KiB
C
|
#include <assert.h>
|
||
|
#include <stdbool.h>
|
||
|
#include "device/device.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;
|
||
|
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) {
|
||
|
game_dialogue_screen.visible = true;
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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;
|
||
|
|
||
|
sys_i32 cx = DEVICE_W / 2;
|
||
|
sys_i32 cy = DEVICE_H - game_dialogue_screen.h / 2 - 8;
|
||
|
|
||
|
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_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,
|
||
|
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;
|
||
|
|
||
|
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);
|
||
|
}
|