чување 6b07be5002aeccc62dd1a7fe9dc810fb389402a0
родитељ be83635a98b692d08b7062d0e6e7d9a1dd56b987
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Wed, 20 May 2026 15:38:12 +0000
Continue hall of fame WIP 2
Diffstat:
| M | hiscore.c | | | 18 | +++++++++++++----- |
| M | hiscore.h | | | 9 | +++++---- |
| M | linije.c | | | 586 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
измењених датотека: 3, додавања: 456(+), брисања: 157(-)
diff --git a/hiscore.c b/hiscore.c
@@ -11,7 +11,7 @@
int
hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
- const int score)
+ const unsigned int score)
{
struct HiScoreEntry* p = NULL;
struct HiScoreEntry* q = NULL;
@@ -40,7 +40,7 @@ hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
}
int
-hs_assign_ps(const char* name, const int name_len, const int score,
+hs_assign_ps(const char* name, const int name_len, const unsigned int score,
struct HiScoreEntry* dest)
{
char* new_name = NULL;
@@ -59,7 +59,11 @@ hs_assign_ps(const char* name, const int name_len, const int score,
return 1;
}
}
- memccpy(dest->name, name, 0, name_len);
+ if (!memccpy(dest->name, name, 0, name_len))
+ dest->name[name_len] = 0;
+ /*SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "hs_assign_ps: dest->name = {%s} [%d]",
+ dest->name, dest->name_len);*/
hs_assign_ps_skip_name:
dest->name_len = name_len;
@@ -86,7 +90,11 @@ hs_assign_ss(const struct HiScoreEntry* source, struct HiScoreEntry* dest)
return 1;
}
}
- memccpy(dest->name, source->name, 0, source->name_len);
+ if (!memccpy(dest->name, source->name, 0, source->name_len))
+ dest->name[source->name_len] = 0;
+ /*SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "hs_assign_ss: dest->name = {%s} [%d]",
+ dest->name, dest->name_len);*/
hs_assign_ss_skip_name:
dest->name_len = source->name_len;
@@ -110,7 +118,7 @@ hs_init(struct HiScoreEntry** table)
if (!p->name)
goto hs_init_malloc_error;
memccpy(p->name, HI_SCORE_DEFAULT_NAME, 0, len);
- p->name_len = len;
+ p->name_len = len - 1;
p->score = 0;
}
diff --git a/hiscore.h b/hiscore.h
@@ -3,18 +3,19 @@
* See the file LICENSE for exact copyright and license details. */
#define HI_SCORE_DEFAULT_NAME "Unknown player"
-#define HI_SCORE_MAX 10
+#define HI_SCORE_MAX 10
+#define HI_SCORE_NAME_MAX 40
struct HiScoreEntry {
char* name;
int name_len;
- int score;
+ unsigned int score;
};
int hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
- const int score);
+ const unsigned int score);
int hs_assign(const struct HiScoreEntry* source, struct HiScoreEntry* dest);
int hs_assign_ss(const struct HiScoreEntry* source, struct HiScoreEntry* dest);
-int hs_assign_ps(const char* name, const int name_len, const int score,
+int hs_assign_ps(const char* name, const int name_len, const unsigned int score,
struct HiScoreEntry* dest);
int hs_init(struct HiScoreEntry** table);
diff --git a/linije.c b/linije.c
@@ -25,22 +25,26 @@
#define FPS 60
#define ANIM_STEPS (ANIM_SPEED * FPS / 1000)
-#define BOLD_START '\1'
-#define BOLD_END '\2'
-#define BUFSIZE 4096
-#define CELL_SIZE 20
-#define DEFAULT_WIDTH 1280
-#define DEFAULT_HEIGHT 720
-#define HELP_DIALOG_WIDTH 900
-#define HELP_DIALOG_HEIGHT 500
-#define HOF_DIALOG_WIDTH 900
-#define HOF_DIALOG_HEIGHT 470
-#define HOF_DIALOG_MAX_LINE_LEN 60
-#define HOF_DIALOG_TEXT_ORIGIN_X 70
+#define BOLD_START '\1'
+#define BOLD_END '\2'
+#define CENTER_LINE '\3'
+#define BUFSIZE 4096
+#define CELL_SIZE 20
+#define DEFAULT_WIDTH 1280
+#define DEFAULT_HEIGHT 720
+#define HELP_DIALOG_WIDTH 900
+#define HELP_DIALOG_HEIGHT 500
+#define HOF_DIALOG_WIDTH 900
+#define HOF_DIALOG_HEIGHT 470
+#define HOF_DIALOG_MAX_LINE_LEN 60
+// #define HOF_DIALOG_TEXT_ORIGIN_X 70
+#define HOF_DIALOG_TEXT_ORIGIN_X 0
#define GAME_OVER_DIALOG_WIDTH 270
#define GAME_OVER_DIALOG_HEIGHT 110
#define GRID_WIDTH 15
#define GRID_HEIGHT 15
+#define INPUT_WIDTH 600
+#define INPUT_HEIGHT 120
#define LOCATION_STACK_MAX (GRID_WIDTH * GRID_HEIGHT)
#define MIN_POP_LEN 5
/* clang-format off */
@@ -49,6 +53,8 @@
/* clang-format on */
#define PRINT_BUFSIZE 4096
#define PROGNAME "linije"
+#define QUIT_MSGBOX_WIDTH 450
+#define QUIT_MSGBOX_HEIGHT 150
#define TER12_WIDTH 6
#define TER12_HEIGHT 12
#define TEXT_OPACITY_NORMAL 0.6f
@@ -105,15 +111,14 @@ const char* state_descriptions[] = {
};
const char* game_over_text[] = {
- "==== \1GAME OVER\2 ====",
- "Press \1F2\2 to restart",
+ "\3==== \1GAME OVER\2 ====",
+ "\3Press \1F2\2 to restart",
NULL
};
const char* help_text[] = {
- "\1linije - Color lines clone\2",
- "\1==========================\2",
- "Version " VERSION,
+ "\3==== \1linije - Color lines clone\2 ====",
+ "\3\\\\ Version " VERSION " //",
"",
"\1F1\2 - Show this help screen",
"\1F2\2 - Restart the game",
@@ -130,6 +135,42 @@ const char* help_text[] = {
NULL
};
+const char* name_text[] = {
+ "\3==== \1ENTER YOUR NAME\2 ====",
+ "",
+ NULL
+};
+
+const char* quit_msgbox_text[] = {
+ "\3==== \1CONFIRM\2 ====",
+ "",
+ "\3Do you really want to quit [\1y\2/\1n\2]?",
+ NULL
+};
+
+const char* restart_msgbox_text[] = {
+ "\3==== \1CONFIRM\2 ====",
+ "",
+ "\3Do you really want to start a new game [\1y\2/\1n\2]?",
+ NULL
+};
+
+const char ascii_shift[255] = {
+ ['`'] = '~', ['1'] = '!', ['2'] = '@', ['3'] = '#', ['4'] = '$',
+ ['5'] = '%', ['6'] = '^', ['7'] = '&', ['8'] = '*', ['9'] = '(',
+ ['0'] = ')', ['-'] = '_', ['='] = '+',
+
+ ['q'] = 'Q', ['w'] = 'W', ['e'] = 'E', ['r'] = 'R', ['t'] = 'T',
+ ['y'] = 'Y', ['u'] = 'U', ['i'] = 'I', ['o'] = 'O', ['p'] = 'P',
+ ['['] = '{', [']'] = '}',
+
+ ['a'] = 'A', ['s'] = 'S', ['d'] = 'D', ['f'] = 'F', ['g'] = 'G',
+ ['h'] = 'H', ['j'] = 'J', ['k'] = 'K', ['l'] = 'L', [';'] = ':',
+ ['\''] = '"',['\\'] = '|',
+
+ ['z'] = 'Z', ['x'] = 'X', ['c'] = 'C', ['v'] = 'V', ['b'] = 'B',
+ ['n'] = 'N', ['m'] = 'M', [','] = '<', ['.'] = '>', ['/'] = '?'
+};
/* clang-format on */
struct AnimationState {
@@ -173,6 +214,9 @@ struct State {
int display_height;
int full_screen;
struct HiScoreEntry* hall_of_fame;
+ void (*input_callback)(struct State*);
+ int input_col;
+ int input_shown;
int location_pointer;
SDL_FPoint* location_stack;
int mode;
@@ -181,8 +225,10 @@ struct State {
int nfree;
struct Cell* path_start;
struct Cell* path_end;
- char* player_name;
- int player_name_len;
+ char player_name[HI_SCORE_NAME_MAX];
+ int player_name_length;
+ int query_shown;
+ void (*query_callback)(struct State*);
int redraw;
SDL_Renderer* renderer;
int running;
@@ -214,6 +260,7 @@ void erase_cell(struct State* state, struct Cell* c);
void fill_triplet(struct State* state);
int find_shortest_path(struct Cell* c, struct Cell* source, const int dist);
void game_over(struct State* state);
+void game_over_dialog(struct State* state);
void get_sprite_xy(const char cell, float* x, float* y);
void grid_coord_to_screen_coord(const struct State* state, const int x,
const int y, const float startx, const float starty, float* to_x,
@@ -223,21 +270,27 @@ void grid_coord_to_screen_coordF(const struct State* state, const float x,
float* to_y);
void handle_click(struct State* state);
void handle_event(struct State* state, SDL_Event* event);
+void handle_input(struct State* state, SDL_Event* event);
+void handle_key_down(struct State* state, SDL_Event* event);
void init_cell(struct Cell* c, const int full, const SDL_FPoint* coords);
void init_state(struct State* state);
+void input_name(struct State* state);
+void input_name_callback(struct State* state);
int load_textures(struct State* state);
void location_delete(struct State* state, const int index);
int location_index(const struct State* state, const SDL_FPoint* location);
void location_push(struct State* state, const SDL_FPoint* location);
void mark_five(struct State* state, SDL_FPoint* start, SDL_FPoint* end);
void mark_path(struct Cell* c);
-int num_size(const int num);
+int num_size(const unsigned int num);
void pop_strings(struct State* state);
-void prepare_hof_dialog(struct State* state, const int show);
void prepare_dialog(struct State* state, const int w, const int h,
const char** text, const int dx, const int show);
+void prepare_hof_dialog(struct State* state, const int show);
void print_matrix(const struct Cell* M);
void print_path(struct Cell* c);
+void quit_callback(struct State* state);
+void really_quit(struct State* state);
void render_background(struct State* state, SDL_FRect* bg_rect);
void render_balls(struct State* state, const float startx, const float starty);
void render_dialog(struct State* state);
@@ -256,6 +309,7 @@ void screen_coord_to_grid_coordF(struct State* state, const float x,
const float y, const float startx, const float starty, float* to_x,
float* to_y);
void step_animation(struct State* state);
+int strlen_visible(const char* s);
SDL_Texture* try_load(SDL_Renderer* renderer, const char* filename);
void
@@ -645,12 +699,17 @@ game_over(struct State* state)
{
assert(state != NULL);
state->mode = STATE_GAME_OVER;
+ if (state->score > state->hall_of_fame[HI_SCORE_MAX - 1].score)
+ input_name(state);
+ else
+ game_over_dialog(state);
+}
+
+void
+game_over_dialog(struct State* state)
+{
prepare_dialog(state, GAME_OVER_DIALOG_WIDTH, GAME_OVER_DIALOG_HEIGHT,
game_over_text, 0, 1);
- SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
- "game_over: Prepared game over dialog");
- hs_add(&state->hall_of_fame, state->player_name, state->player_name_len,
- state->score);
}
void
@@ -853,81 +912,208 @@ handle_event(struct State* state, SDL_Event* event)
break;
case SDL_EVENT_KEY_DOWN:
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
- "Got Keydown, key = %X, mod = %X", event->key.key,
- event->key.mod);
+ "handle_event (before): player = {%s} [%d]",
+ state->player_name, state->player_name_length);
+ handle_key_down(state, event);
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "handle_event (after): player = {%s} [%d]",
+ state->player_name, state->player_name_length);
+ break;
+ case SDL_EVENT_MOUSE_BUTTON_UP:
+ handle_click(state);
+ break;
+ case SDL_EVENT_MOUSE_MOTION:
+ state->mouse.x = event->motion.x;
+ state->mouse.y = event->motion.y;
+ break;
+ }
+}
- switch (event->key.key)
- {
- case SDLK_F1:
- if (event->key.mod & SDL_KMOD_CTRL)
- {
- state->mode = STATE_GAME_OVER;
- prepare_dialog(state, GAME_OVER_DIALOG_WIDTH,
- GAME_OVER_DIALOG_HEIGHT, game_over_text,
- 0, 1);
- break;
- }
+void
+handle_input(struct State* state, SDL_Event* event)
+{
+ int i;
- if (state->dialog_shown)
- break;
- prepare_dialog(state, HELP_DIALOG_WIDTH,
- HELP_DIALOG_HEIGHT, help_text, 0, 1);
- SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
- "Dialog shown: %s",
- state->dialog_shown ? "YES" : "NO");
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "handle_input (before): state->player_name = {%s} [%d], %d",
+ state->player_name, state->player_name_length,
+ state->input_col);
+ switch (event->key.key)
+ {
+ case SDLK_ESCAPE:
+ state->input_shown = 0;
+ game_over_dialog(state);
+ break;
+ case SDLK_RETURN:
+ state->input_shown = 0;
+ if (state->input_callback)
+ state->input_callback(state);
+ game_over_dialog(state);
+ break;
+ case SDLK_BACKSPACE:
+ if (state->input_col == 0)
break;
- case SDLK_F2:
- if (state->dialog_shown
- && state->dialog_text == help_text)
- break;
- reset(state);
- fill_triplet(state);
+ for (i = state->input_col - 1; i < state->player_name_length;
+ i++)
+ state->player_name[i] = state->player_name[i + 1];
+ state->player_name_length--;
+ state->player_name[state->player_name_length] = 0;
+ state->input_col--;
+ state->redraw = 1;
+ break;
+ case SDLK_DELETE:
+ if (state->input_col == state->player_name_length)
break;
- case SDLK_F3:
- if (state->dialog_shown)
- break;
- prepare_hof_dialog(state, 1);
+ for (i = state->input_col; i < state->player_name_length; i++)
+ state->player_name[i] = state->player_name[i + 1];
+ state->player_name_length--;
+ state->player_name[state->player_name_length] = 0;
+ state->redraw = 1;
+ break;
+ case SDLK_LEFT:
+ if (state->input_col > 0)
+ {
+ state->input_col--;
+ state->redraw = 1;
+ }
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "SDLK_LEFT: player_name = {%s} [%d]",
+ state->player_name, state->player_name_length);
+ break;
+ case SDLK_RIGHT:
+ if (state->input_col < state->player_name_length)
+ {
+ state->input_col++;
+ state->redraw = 1;
+ }
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "SDLK_RIGHT: player_name = {%s} [%d]",
+ state->player_name, state->player_name_length);
+ break;
+ default:
+ if (state->player_name_length < HI_SCORE_NAME_MAX
+ && event->key.key >= SDLK_SPACE
+ && event->key.key <= SDLK_TILDE)
+ {
+ for (i = state->player_name_length;
+ i > state->input_col; i--)
+ state->player_name[i]
+ = state->player_name[i - 1];
+ state->player_name[state->input_col++]
+ = event->key.mod & SDL_KMOD_SHIFT
+ ? ascii_shift[event->key.key]
+ : event->key.key;
+ state->player_name_length++;
+ state->player_name[state->player_name_length] = 0;
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
- "Dialog shown: %s",
- state->dialog_shown ? "YES" : "NO");
- break;
- case SDLK_RETURN:
- if (!(event->key.mod & SDL_KMOD_ALT))
- break;
- state->full_screen = !state->full_screen;
+ "handle_input: event->key.key = %d",
+ event->key.key);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
- "Set fullscreen state: %s",
- state->full_screen ? "ON" : "OFF");
- SDL_SetWindowFullscreen(state->window,
- state->full_screen);
- SDL_SetWindowBordered(state->window,
- !state->full_screen);
- break;
- case SDLK_ESCAPE:
- if (state->dialog_shown
- && state->mode == STATE_GAME_OVER)
- break;
- state->dialog_shown = 0;
- state->dialog_text = NULL;
- assign_point_xyII(-1, -1, &state->dialog_dims);
+ "handle_input (after): state->player_name = "
+ "{%s} [%d], %d",
+ state->player_name, state->player_name_length,
+ state->input_col);
state->redraw = 1;
+ }
+ }
+}
+
+void
+handle_key_down(struct State* state, SDL_Event* event)
+{
+ if (state->input_shown)
+ {
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "handle_key_down (before): player = {%s} [%d]",
+ state->player_name, state->player_name_length);
+ handle_input(state, event);
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "handle_key_down (after): player = {%s} [%d]",
+ state->player_name, state->player_name_length);
+ return;
+ }
+
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "Got Keydown, key = %X, mod = %X", event->key.key,
+ event->key.mod);
+
+ switch (event->key.key)
+ {
+ case SDLK_F1:
+ if (event->key.mod & SDL_KMOD_CTRL)
+ {
+ game_over(state);
break;
- case SDLK_Q:
- if (event->key.mod & SDL_KMOD_CTRL)
- state->running = 0;
+ }
+
+ if (state->dialog_shown)
break;
- default:
- SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
- "Handle keyboard event: switch fallthrough");
+ prepare_dialog(state, HELP_DIALOG_WIDTH, HELP_DIALOG_HEIGHT,
+ help_text, 0, 1);
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Dialog shown: %s",
+ state->dialog_shown ? "YES" : "NO");
+ break;
+ case SDLK_F2:
+ if (state->dialog_shown && state->dialog_text == help_text)
+ break;
+ reset(state);
+ fill_triplet(state);
+ break;
+ case SDLK_F3:
+ if (state->dialog_shown)
+ break;
+ prepare_hof_dialog(state, 1);
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Dialog shown: %s",
+ state->dialog_shown ? "YES" : "NO");
+ break;
+ case SDLK_RETURN:
+ if (!(event->key.mod & SDL_KMOD_ALT))
+ break;
+ state->full_screen = !state->full_screen;
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "Set fullscreen state: %s",
+ state->full_screen ? "ON" : "OFF");
+ SDL_SetWindowFullscreen(state->window, state->full_screen);
+ SDL_SetWindowBordered(state->window, !state->full_screen);
+ break;
+ case SDLK_ESCAPE:
+ if (state->dialog_shown && state->mode == STATE_GAME_OVER)
+ break;
+ state->dialog_shown = 0;
+ state->dialog_text = NULL;
+ state->query_shown = 0;
+ // assign_point_xyII(-1, -1, &state->dialog_dims);
+ state->redraw = 1;
+ break;
+ case SDLK_Y:
+ if (state->query_shown)
+ {
+ state->dialog_shown = 0;
+ state->dialog_text = NULL;
+ state->query_shown = 0;
+ state->redraw = 1;
+ if (state->query_callback)
+ state->query_callback(state);
}
break;
- case SDL_EVENT_MOUSE_BUTTON_UP:
- handle_click(state);
+ case SDLK_N:
+ if (state->query_shown)
+ {
+ state->dialog_shown = 0;
+ state->dialog_text = NULL;
+ state->query_callback = NULL;
+ state->query_shown = 0;
+ state->redraw = 1;
+ }
break;
- case SDL_EVENT_MOUSE_MOTION:
- state->mouse.x = event->motion.x;
- state->mouse.y = event->motion.y;
+ case SDLK_Q:
+ if (event->key.mod & SDL_KMOD_CTRL)
+ really_quit(state);
+ // state->running = 0;
break;
+ default:
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "Handle keyboard event: switch fallthrough");
}
}
@@ -987,22 +1173,27 @@ init_state(struct State* state)
state->full_screen = 1;
state->hall_of_fame = NULL;
// state->hof_text = NULL;
+ state->input_callback = NULL;
+ state->input_col = 0;
+ state->input_shown = 0;
state->location_pointer = 0;
state->location_stack = NULL;
state->mode = STATE_IDLE;
state->moveno = 1;
state->nfree = GRID_WIDTH * GRID_HEIGHT;
assign_point_xyIF(0, 0, &state->mouse);
- state->path_start = NULL;
- state->path_end = NULL;
- state->player_name = NULL;
- state->player_name_len = -1;
- state->redraw = 1;
- state->renderer = NULL;
- state->running = 1;
- state->screen_width = DEFAULT_WIDTH;
- state->screen_height = DEFAULT_HEIGHT;
- state->score = 0;
+ state->path_start = NULL;
+ state->path_end = NULL;
+ state->player_name[0] = 0;
+ state->player_name_length = 0;
+ state->query_shown = 0;
+ state->query_callback = NULL;
+ state->redraw = 1;
+ state->renderer = NULL;
+ state->running = 1;
+ state->screen_width = DEFAULT_WIDTH;
+ state->screen_height = DEFAULT_HEIGHT;
+ state->score = 0;
assign_point_xyIF(-1, -1, &state->selection_start);
assign_point_xyIF(-1, -1, &state->selection_end);
state->sprites = NULL;
@@ -1011,6 +1202,35 @@ init_state(struct State* state)
state->window = NULL;
}
+void
+input_name(struct State* state)
+{
+ state->input_shown = 1;
+ state->query_shown = 0;
+ state->input_col = 0;
+ state->player_name_length = 0;
+ state->player_name[0] = 0;
+ state->input_callback = &input_name_callback;
+ prepare_dialog(state, INPUT_WIDTH, INPUT_HEIGHT, name_text, 0, 1);
+}
+
+void
+input_name_callback(struct State* state)
+{
+ int i;
+ assert(state != NULL);
+ state->input_callback = NULL;
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
+ "input_name_callback: player_name = %s", state->player_name);
+ for (i = 0; i < state->player_name_length; i++)
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "%d",
+ state->player_name[i]);
+ hs_add(&state->hall_of_fame, state->player_name,
+ state->player_name_length, state->score);
+ prepare_dialog(state, GAME_OVER_DIALOG_WIDTH, GAME_OVER_DIALOG_HEIGHT,
+ game_over_text, 0, 1);
+}
+
int
load_textures(struct State* state)
{
@@ -1124,7 +1344,7 @@ mark_path(struct Cell* c)
}
int
-num_size(const int num)
+num_size(const unsigned int num)
{
if (num > 999999999)
return 10;
@@ -1168,12 +1388,28 @@ pop_strings(struct State* state)
}
void
+prepare_dialog(struct State* state, const int w, const int h, const char** text,
+ const int dx, const int show)
+{
+ assert((state != NULL) && (text != NULL));
+
+ assign_point_xyII(w, h, &state->dialog_dims);
+ state->dialog_text_origin.x = dx;
+ state->dialog_text = text;
+ state->dialog_shown = show;
+ if (show)
+ state->redraw = 1;
+}
+
+#define HOF_SCORES_START_IDX 2
+
+void
prepare_hof_dialog(struct State* state, const int show)
{
- struct HiScoreEntry* hof = NULL;
- static char** hof_text = NULL;
- static int hof_size = HI_SCORE_MAX + 3 + 2 + 1;
- char* dots = NULL;
+ struct HiScoreEntry* e = NULL;
+ static char** hof_text = NULL;
+ static int hof_size = HI_SCORE_MAX + 2 + 2 + 1;
+ char* dots = NULL;
int i;
assert(state != NULL);
@@ -1182,32 +1418,39 @@ prepare_hof_dialog(struct State* state, const int show)
if (!(dots = malloc(HOF_DIALOG_MAX_LINE_LEN + 1)))
goto prepare_hof_dialog_malloc_error;
- if (hof_text)
+ /*if (hof_text)
for (i = 3; i < hof_size - 3; i++)
free(hof_text[i]);
- free(hof_text);
+ free(hof_text);*/
- if (!(hof_text = calloc(hof_size, sizeof(struct HiScoreEntry*))))
- goto prepare_hof_dialog_malloc_error;
+ if (!hof_text)
+ {
+ if (!(hof_text = calloc(hof_size, sizeof(char*))))
+ goto prepare_hof_dialog_malloc_error;
- hof_text[0] = "\1HALL OF FAME\2";
- hof_text[1] = "\1============\2";
- hof_text[2] = "";
+ hof_text[0] = "\3==== \1HALL OF FAME\2 ====";
+ hof_text[1] = "";
+ hof_text[hof_size - 3] = "";
+ hof_text[hof_size - 2] = "\3Press \1Esc\2 to close";
+ hof_text[hof_size - 1] = NULL;
+ }
for (i = 0; i < HI_SCORE_MAX; i++)
{
- if (!(hof_text[3 + i] = malloc(HOF_DIALOG_MAX_LINE_LEN + 1)))
- goto prepare_hof_dialog_malloc_error;
- hof = &state->hall_of_fame[i];
+ if (!(hof_text[HOF_SCORES_START_IDX + i]))
+ {
+ if (!(hof_text[HOF_SCORES_START_IDX + i]
+ = malloc(HOF_DIALOG_MAX_LINE_LEN + 1)))
+ goto prepare_hof_dialog_malloc_error;
+ }
+ e = &state->hall_of_fame[i];
repeat_char(&dots, '.',
- HOF_DIALOG_MAX_LINE_LEN - 4 - hof->name_len
- - num_size(hof->score));
- snprintf(hof_text[3 + i], HOF_DIALOG_MAX_LINE_LEN,
- "%2d. %s%s%d", i + 1, hof->name, dots, hof->score);
+ HOF_DIALOG_MAX_LINE_LEN - 4 - e->name_len
+ - num_size(e->score) - 1);
+ snprintf(hof_text[HOF_SCORES_START_IDX + i],
+ HOF_DIALOG_MAX_LINE_LEN, "%2d. %s%s%u", i + 1, e->name,
+ dots, e->score);
}
- hof_text[hof_size - 3] = "";
- hof_text[hof_size - 2] = "Press \1Esc\2 to close";
- hof_text[hof_size - 1] = NULL;
prepare_dialog(state, HOF_DIALOG_WIDTH, HOF_DIALOG_HEIGHT,
(const char**)hof_text, HOF_DIALOG_TEXT_ORIGIN_X, show);
@@ -1216,22 +1459,27 @@ prepare_hof_dialog(struct State* state, const int show)
return;
prepare_hof_dialog_malloc_error:
- perror("malloc");
+ SDL_LogError(SDL_LOG_CATEGORY_ERROR, "malloc failed");
exit(1);
}
void
-prepare_dialog(struct State* state, const int w, const int h, const char** text,
- const int dx, const int show)
+quit_callback(struct State* state)
{
- assert((state != NULL) && (text != NULL));
+ assert(state != NULL);
+ UNUSED(state);
+ state->query_callback = NULL;
+ state->running = 0;
+}
- assign_point_xyII(w, h, &state->dialog_dims);
- state->dialog_text_origin.x = dx;
- state->dialog_text = text;
- state->dialog_shown = show;
- if (show)
- state->redraw = 1;
+void
+really_quit(struct State* state)
+{
+ assert(state != NULL);
+ state->query_shown = 1;
+ state->query_callback = quit_callback;
+ prepare_dialog(state, QUIT_MSGBOX_WIDTH, QUIT_MSGBOX_HEIGHT,
+ quit_msgbox_text, 0, 1);
}
void
@@ -1407,10 +1655,10 @@ void
render_dialog(struct State* state)
{
const char** ptext = NULL;
- SDL_FRect dialog_rect;
+ SDL_FRect dialog_rect, input_rect, cursor_rect;
float tsf;
int w, h;
- int sx, sy, dx;
+ int sx, sy, dx, _sx;
assert(state != NULL);
assert(state->dialog_text != NULL);
@@ -1450,14 +1698,46 @@ render_dialog(struct State* state)
while (*ptext)
{
- render_text(state, sx + dx + tsf * (2 * TER12_WIDTH),
+ _sx = sx + dx + tsf * (2 * TER12_WIDTH);
+ // SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "1. _sx=%d", _sx);
+ if (strchr(*ptext, CENTER_LINE))
+ _sx += w / 2 - dx
+ - tsf * TER12_WIDTH
+ * (2 + strlen_visible(*ptext) / 2);
+ // SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "2. _sx=%d", _sx);
+
+ render_text(state, _sx,
sy
+ (ptext - state->dialog_text + 1) * tsf
* (TER12_HEIGHT + 2),
- TER12_WIDTH, TER12_HEIGHT, state->ter12_texture,
+ TER12_WIDTH, TER12_HEIGHT, state->ter12_texture, "%s",
*ptext);
ptext++;
}
+
+ if (state->input_shown)
+ {
+ input_rect.w = tsf * TER12_WIDTH * (HI_SCORE_NAME_MAX + 2);
+ input_rect.h = tsf * TER12_HEIGHT;
+ input_rect.x = sx + w / 2
+ - tsf * TER12_WIDTH * HI_SCORE_NAME_MAX / 2;
+ input_rect.y = sy + h - tsf * 2 * TER12_HEIGHT;
+
+ cursor_rect.w = TER12_WIDTH;
+ cursor_rect.h = 3;
+
+ SDL_SetRenderDrawBlendMode(state->renderer, SDL_BLENDMODE_BLEND);
+ SDL_SetRenderDrawColor(state->renderer, 55, 55, 55, .75 * 255);
+ SDL_RenderFillRect(state->renderer, &input_rect);
+ _sx = input_rect.x + tsf * TER12_WIDTH;
+
+ cursor_rect.x = _sx + tsf * TER12_WIDTH * state->input_col;
+ cursor_rect.y
+ = input_rect.y + tsf * TER12_HEIGHT - cursor_rect.h;
+ SDL_SetRenderDrawColor(state->renderer, 255, 255, 255,
+ SDL_ALPHA_OPAQUE);
+ SDL_RenderFillRect(state->renderer, &cursor_rect);
+ }
}
void
@@ -1572,6 +1852,11 @@ render_text(struct State* state, const int x, const int y, const int font_width,
xstart = 1 + index % chars_per_row * (font_width + 1);
ystart = 1 + index / chars_per_row * (font_height + 1);
}
+ else if (*pbuf == CENTER_LINE)
+ {
+ pbuf++;
+ continue;
+ }
else if (*pbuf == BOLD_START)
{
opacity = TEXT_OPACITY_BOLD;
@@ -1822,6 +2107,25 @@ step_animation(struct State* state)
state->animation.active ? "ACTIVE" : "INACTIVE");
}
+int
+strlen_visible(const char* s)
+{
+ int result = 0;
+ const char* ps = NULL;
+
+ assert(s != NULL);
+ ps = s;
+ while (*ps)
+ {
+ if (*ps != CENTER_LINE && *ps != BOLD_START && *ps != BOLD_END)
+ result++;
+ ps++;
+ }
+ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "strlen_visible(%s)=%d\n", s,
+ result);
+ return result;
+}
+
SDL_Texture*
try_load(SDL_Renderer* renderer, const char* filename)
{
@@ -1860,7 +2164,7 @@ main(int argc, char** argv)
struct Cell* c = NULL;
struct State state;
struct HiScoreEntry* hof = NULL;
- struct HiScoreEntry* p = NULL;
+ // struct HiScoreEntry* p = NULL;
struct timespec now;
SDL_FPoint coords;
float px, py;
@@ -1875,20 +2179,6 @@ main(int argc, char** argv)
hs_init(&hof);
state.hall_of_fame = hof;
- /*
- for (p = hof; p < hof + HI_SCORE_MAX; p++)
- printf("%s (%d) -> %d\n", p->name, p->name_len, p->score);
-
- hs_add(&hof, "Player 2 with a very long name",
- sizeof("Player 2 with a very long name"), 2);
- hs_add(&hof, "Player 1", sizeof("Player 1"), 50);
- hs_add(&hof, "Strajder", sizeof("Strajder"), 250);
- hs_add(&hof, "Player 3", sizeof("Player 3"), 44);
-
- for (p = hof; p < hof + HI_SCORE_MAX; p++)
- printf("%s (%d) -> %d\n", p->name, p->name_len, p->score);
-
- return 0;*/
if (!SDL_Init(SDL_INIT_VIDEO))
{