чување 332a5c17d976bc0eaba96a04b9c2cdc7a181339c
родитељ ca58f46524a0bf0ee04eb4ea7957e0e1c3a7b999
Аутор: Страхиња Радић <sr@strahinja.org>
Датум: Tue, 25 Aug 2026 18:40:30 +0000
Add timestamps to hall of fame (backwards incompatible with HOF file)
Diffstat:
измењених датотека: 4, додавања: 89(+), брисања: 15(-)
diff --git a/TODO.done b/TODO.done
@@ -1,6 +1,8 @@
Done or canceled todos
======================
+[x] Add timestamps to hall of fame
+
[x] High score?
[x] Updating high score
[x] Saving high score to a file
diff --git a/hiscore.c b/hiscore.c
@@ -13,15 +13,16 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <time.h>
int
hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
- const unsigned long int score)
+ const unsigned long int score, const char* timestamp)
{
struct HiScoreEntry* p = NULL;
struct HiScoreEntry* q = NULL;
- assert((table != NULL) && (*table != NULL));
+ assert((table != NULL) && (*table != NULL) && (timestamp != NULL));
p = *table;
while (p < *table + HI_SCORE_MAX)
@@ -35,7 +36,7 @@ hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
hs_assign_ss(q - 1, q);
q--;
}
- hs_assign_ps(name, name_len, score, p);
+ hs_assign_ps(name, name_len, score, timestamp, p);
break;
}
p++;
@@ -45,13 +46,43 @@ hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
}
int
+hs_add_now(struct HiScoreEntry** table, const char* name, const int name_len,
+ const unsigned long int score)
+{
+ struct tm* ns = NULL;
+ char sn[TIMESTAMP_MAX];
+ time_t nt;
+ nt = time(NULL);
+ if (!(ns = gmtime(&nt)))
+ {
+ SDL_LogError(SDL_LOG_CATEGORY_ERROR, "gmtime: %s",
+ strerror(errno));
+ return 1;
+ }
+ if (!strftime(sn, TIMESTAMP_MAX, "%Y-%m-%d %H:%M", ns))
+ {
+ SDL_LogError(SDL_LOG_CATEGORY_ERROR, "strftime failed");
+ return 1;
+ }
+ return hs_add(table, name, name_len, score, sn);
+}
+
+int
hs_assign_ps(const char* name, const int name_len,
- const unsigned long int score, struct HiScoreEntry* dest)
+ const unsigned long int score, const char* timestamp,
+ struct HiScoreEntry* dest)
{
char* new_name = NULL;
assert(dest != NULL);
+ if (!timestamp)
+ {
+ SDL_LogError(SDL_LOG_CATEGORY_ERROR,
+ "hs_asssign_ps: timestamp is null!");
+ return 1;
+ }
+
if (!name || !name_len)
goto hs_assign_ps_skip_name;
@@ -66,6 +97,7 @@ hs_assign_ps(const char* name, const int 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);*/
@@ -73,6 +105,8 @@ hs_assign_ps(const char* name, const int name_len,
hs_assign_ps_skip_name:
dest->name_len = name_len;
dest->score = score;
+ if (!memccpy(dest->timestamp, timestamp, 0, TIMESTAMP_MAX))
+ dest->timestamp[TIMESTAMP_MAX - 1] = 0;
return 0;
}
@@ -83,6 +117,10 @@ hs_assign_ss(const struct HiScoreEntry* source, struct HiScoreEntry* dest)
assert((source != NULL) && (dest != NULL));
+ if (!*source->timestamp)
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
+ "hs_asssign_ss: timestamp is empty!");
+
if (!source->name)
goto hs_assign_ss_skip_name;
@@ -101,6 +139,8 @@ hs_assign_ss(const struct HiScoreEntry* source, struct HiScoreEntry* dest)
hs_assign_ss_skip_name:
dest->name_len = source->name_len;
dest->score = source->score;
+ if (!memccpy(dest->timestamp, source->timestamp, 0, TIMESTAMP_MAX))
+ dest->timestamp[TIMESTAMP_MAX - 1] = 0;
return 0;
}
@@ -123,6 +163,7 @@ hs_init(struct HiScoreEntry** table)
memccpy(p->name, HI_SCORE_DEFAULT_NAME, 0, HI_SCORE_NAME_MAX);
p->name_len = len - 1;
p->score = 0;
+ memccpy(p->timestamp, DEFAULT_TIMESTAMP, 0, TIMESTAMP_MAX);
}
return 0;
@@ -190,6 +231,8 @@ hs_get_hofdir_error:
* | name (HI_SCORE_NAME_MAX unsigned chars) |
* |-----------------------------------------------------------|
* | score 4-byte unsigned long int BE |
+ * |-----------------------------------------------------------|
+ * | timestamp (TIMESTAMP_MAX unsigned chars) |
* `-----------------------------------------------------------'
*/
int
@@ -197,7 +240,8 @@ hs_load(struct HiScoreEntry** table, const char* hofdir)
{
FILE* infile = NULL;
char* filename = NULL;
- char name[HI_SCORE_NAME_MAX + 1];
+ char name[HI_SCORE_NAME_MAX];
+ char timestamp[TIMESTAMP_MAX];
int filename_size = PATH_MAX + 1;
int name_len, i, ib;
unsigned long int score;
@@ -247,7 +291,17 @@ hs_load(struct HiScoreEntry** table, const char* hofdir)
}
score |= SETBYTENOF4(byte, ib);
}
- hs_add(table, name, name_len, score);
+ if (fread(timestamp, TIMESTAMP_MAX, 1, infile) < 1)
+ {
+ if (feof(infile))
+ continue;
+ else
+ {
+ fclose(infile);
+ goto hs_load_error;
+ }
+ }
+ hs_add(table, name, name_len, score, timestamp);
i++;
}
@@ -307,6 +361,16 @@ hs_write(struct HiScoreEntry* table, const char* hofdir)
goto hs_write_error;
}
}
+ for (i = 0; i < TIMESTAMP_MAX; i++)
+ {
+ errno = 0;
+ byte = p->timestamp[i];
+ if (fwrite(&byte, 1, 1, outfile) < 1)
+ {
+ fclose(outfile);
+ goto hs_write_error;
+ }
+ }
}
if (fclose(outfile) == EOF)
goto hs_write_error;
diff --git a/hiscore.h b/hiscore.h
@@ -2,9 +2,11 @@
* any later version. Copyright (C) 2025 Страхиња Радић.
* See the file LICENSE for exact copyright and license details. */
+#define DEFAULT_TIMESTAMP "1970-01-01 00:00"
#define HI_SCORE_DEFAULT_NAME "Unknown player"
#define HI_SCORE_MAX 10
#define HI_SCORE_NAME_MAX 40
+#define TIMESTAMP_MAX 17
#ifndef PATH_MAX
#define PATH_MAX _POSIX_PATH_MAX
@@ -17,15 +19,19 @@
struct HiScoreEntry {
char* name;
int name_len;
+ char timestamp[TIMESTAMP_MAX];
unsigned long int score;
};
int hs_add(struct HiScoreEntry** table, const char* name, const int name_len,
- const unsigned long int score);
+ const unsigned long int score, const char* timestamp);
+int hs_add_now(struct HiScoreEntry** table, const char* name,
+ const int name_len, const unsigned long 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 unsigned long int score, struct HiScoreEntry* dest);
+ const unsigned long int score, const char* timestamp,
+ struct HiScoreEntry* dest);
+int hs_assign_ss(const struct HiScoreEntry* source, struct HiScoreEntry* dest);
char* hs_get_hofdir(void);
int hs_init(struct HiScoreEntry** table);
int hs_load(struct HiScoreEntry** table, const char* hofdir);
diff --git a/linije.c b/linije.c
@@ -1265,7 +1265,7 @@ input_name_callback(struct State* state)
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,
+ hs_add_now(&state->hall_of_fame, state->player_name,
state->player_name_length, state->score);
if (hs_write(state->hall_of_fame, hs_get_hofdir()))
@@ -1504,11 +1504,11 @@ prepare_hof_dialog(struct State* state, const int show)
e = &state->hall_of_fame[i];
repeat_char(&dots, '.',
HOF_DIALOG_MAX_LINE_LEN - 4 - e->name_len
- - num_size(e->score) - 1);
+ - num_size(e->score) - 1 - TIMESTAMP_MAX - 1);
/* +4 is the number of special characters (the number of visible
* characters remains HOF_DIALOG_MAX_LINE_LEN) */
- hof_line_len = HOF_DIALOG_MAX_LINE_LEN + 4;
+ hof_line_len = HOF_DIALOG_MAX_LINE_LEN + 5;
/* For the first HOF_STANDOUT_ENTRIES entries, the number of
* special characters increases by 1 */
@@ -1516,9 +1516,11 @@ prepare_hof_dialog(struct State* state, const int show)
hof_line_len++;
snprintf(hof_text[HOF_SCORES_START_IDX + i], hof_line_len,
- "\4%2d. %s%s\4%s\2%s%lu", i + 1,
+ "\4%2d. %s%s\4%s\2%s%lu %s%s", i + 1,
i < HOF_STANDOUT_ENTRIES ? "\1" : "\2", e->name, dots,
- i < HOF_STANDOUT_ENTRIES ? "\1" : "", e->score);
+ i < HOF_STANDOUT_ENTRIES ? "\1" : "", e->score,
+ i < HOF_STANDOUT_ENTRIES ? "\2" : "\4",
+ e->timestamp);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"HOF[%d] = \"%s\" (%ld [vis=%d])\n", i,
@@ -1879,7 +1881,7 @@ render_text(struct State* state, const int x, const int y, const int font_width,
float tex_w, tex_h;
float opacity = TEXT_OPACITY_NORMAL;
- assert((font_tex != NULL) && (text != NULL));
+ assert((state != NULL) && (font_tex != NULL) && (text != NULL));
assert(state->text_scale_factor != 0.0f);
assert(font_width != -1);