From 4e78067f0a3b3407bb89e427d0a2b01509ec8677 Mon Sep 17 00:00:00 2001 From: user Date: Sun, 29 Nov 2020 18:15:15 +1000 Subject: [PATCH] save and load level times --- src/draw.c | 70 ++++++++++++++++++++++++++---- src/game.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/game.h | 16 ++++++- src/main.c | 82 ++++------------------------------- 4 files changed, 204 insertions(+), 87 deletions(-) diff --git a/src/draw.c b/src/draw.c index 9fe519e..f936e54 100644 --- a/src/draw.c +++ b/src/draw.c @@ -535,22 +535,71 @@ int draw_end_screen(SDL_Renderer *ren) { int margin = height / 10; // Vect position = {.x = width - width / 10, .y = height - margin}; + long fastest = get_best_time(); + int minutes = level_time / 60000; float seconds = level_time * 0.001; char time_string[250]; - snprintf(time_string, 250, "TIME: %d:%.4f", minutes, seconds); - char * end_str = "Level over."; - char * ct_str = "Press any key to continue."; - char qual_str[250]; - snprintf(qual_str, 250, "Physics quality: %d", quality); + + + + char * end_str = "level over."; Vect position = {.x = width/3, .y = height / 4}; draw_text(ren, position, colour, end_str); position.y += 40; - draw_text(ren, position, colour, time_string); + + char level_string[250]; + snprintf(level_string, 250,"course: %d", level); + draw_text(ren, position, colour, level_string); position.y += 40; + + char qual_str[250]; + snprintf(qual_str, 250, "physics quality: %d", quality); draw_text(ren, position, colour, qual_str); position.y += 40; + + + + char fastest_time[250]; + minutes = fastest / 60000; + seconds = fastest * 0.001; + if (fastest > 0) { + position.y += 40; + snprintf(fastest_time, 250, "old best time: %d:%.4f", minutes, seconds); + draw_text(ren, position, colour, fastest_time); + } + minutes = level_time / 60000; + seconds = level_time * 0.001; + if (level_time > fastest) { + // base time not set yet. + snprintf(time_string, 250, "TIME: %d:%.4f", minutes, seconds); + } else { + snprintf(time_string, 250, "NEW BEST TIME: %d:%.4f", minutes, seconds); + } + + Vect position2 = {.x = 3 * width/5, .y = 40 + height / 4}; + + if (fastest > 0) { + //position.y += 40; + long diff = level_time - fastest; + char diff_str[250]; + minutes = diff / 60000; + seconds = diff * 0.001; + if (minutes > 0) { + snprintf(diff_str, 250, "DIFF: %d:%.4f", minutes, fabs(seconds)); + } else { + snprintf(diff_str, 250, "DIFF: %.4f s", seconds); + } + + draw_text(ren, position2, colour, diff_str); + position2.y += 40; + } + + draw_text(ren, position2, colour, time_string); + + position.y += 200; + char * ct_str = "press any key to continue"; draw_text(ren, position, colour, ct_str); SDL_RenderPresent(ren); @@ -561,15 +610,20 @@ int draw_end_screen(SDL_Renderer *ren) { void draw_level_time(SDL_Renderer *ren, struct environment * e) { int margin = height / 10; - Vect position = {.x = width - width / 10, .y = height - margin}; struct colour colour = e->colours.fg1; int minutes = level_time / 60000; float seconds = level_time * 0.001; char time_string[250]; - snprintf(time_string, 250, "%d:%.4f", minutes, seconds); + snprintf(time_string, 250, "time: %d:%.4f", minutes, seconds); + + char level_string[250]; + snprintf(level_string, 250,"course: %d", level); + Vect position = {.x = margin, .y = height - margin}; + draw_text(ren, position, colour, level_string); + position.y += 40; draw_text(ren, position, colour, time_string); } diff --git a/src/game.c b/src/game.c index e64c8db..0b1a485 100644 --- a/src/game.c +++ b/src/game.c @@ -23,6 +23,8 @@ long level_time; int get_floor_ceiling(); +struct sg_times_list save_times_lst; + /* array of all the things in the world and their kinds */ //world_thing *world; @@ -69,6 +71,116 @@ void level_timer_update(bool reset) { } } + +int long_comparator(const void *a, const void *b, void *non) { + long A = *(long *)a; + long B = *(long *)b; + + return A - B; +} + +void sort_times(void) { + qsort_r(save_times_lst.times, save_times_lst.size, sizeof(long), long_comparator, NULL); +} + +long get_best_time(void) { + save_times_lst.sort(); + if (save_times_lst.size > 0) + return save_times_lst.times[0]; + return -1; +} + + + +int load_score_times(char *filename) { + + char *fn; + char lvl_str[250]; + snprintf(lvl_str, 250, "%d", level); + int fnlen = strlen(filename) + strlen(lvl_str) + 3; + fn = malloc(fnlen); + snprintf(fn, fnlen, "%s-%s", filename, lvl_str); + + printf("%d, lvl_str %s fn %s\n", level, lvl_str, fn); + + FILE *f = fopen(fn, "r"); + // unload existing score times + if (save_times_lst.times) { + write_times(); + free(save_times_lst.times); + free(save_times_lst.filename); + } + + if (f) { + // get file size + fseek(f, 0L, SEEK_END); + long sz = ftell(f); + fseek(f, 0L, SEEK_SET); + char *text = malloc((sz + 1) * (sizeof(char))); + + // read file + fread(text,sizeof(char),sz, f); + fclose(f); + + int count = 1; + for (int i = 0; i < strlen(text); i++) { + if (text[i] == '\n') { + count++; + } + } + + long *times = malloc(count * sizeof(long)); + char *saveptr; + + // extract times + char * token = strtok_r(text, "\n", &saveptr); + int i = 0; + while (token != NULL) { + if (strlen(token) > 2) { + times[i] = atol(token); + i++; + } + token = strtok_r(NULL, "\n", &saveptr); + } + save_times_lst = (struct sg_times_list){.size=i, .capacity = count, .times=times, .sort=sort_times}; + save_times_lst.sort(); + free(text); + } else { + perror("loading times"); + save_times_lst = (struct sg_times_list){.size=0, .capacity = 5, .times=calloc(5, sizeof(long)), .sort=sort_times}; + } + + save_times_lst.filename = fn; + return 0; +} + +int add_time(long time) { + if (save_times_lst.capacity == save_times_lst.size + 5) { + long newcap = save_times_lst.capacity * 2; + save_times_lst.times = realloc(save_times_lst.times, newcap); + save_times_lst.capacity = newcap; + } + save_times_lst.times[save_times_lst.size] = time; + save_times_lst.size++; + + return 0; +} + +int write_times(void) { + FILE *f = fopen(save_times_lst.filename, "w"); + if (!f) { + perror("Saving game"); + return 1; + } + for (int i = 0; i < save_times_lst.size; i++) { + fprintf(f, "%ld\n", save_times_lst.times[i]); + } + fclose(f); + return 0; +} + + + // collision poly size must be 2x shape_size + 1 void cast_update_collision_poly(Body *body) { for (int i=0; i < body->collision_shape_size; i++) { @@ -587,9 +699,10 @@ void next_level() { level *= 7;; get_floor_ceiling(); + load_score_times("saves/times"); v = world.uniques_index[ROOM_W]->room->ceil.items[2]->collision_poly[0]; - v.y -= 30; + v.y -= 15; player.physics->position = v; player.physics->next_position = v; @@ -1452,6 +1565,9 @@ void startgame(SDL_Renderer * ren) { level = 31; + save_times_lst = (struct sg_times_list){}; + load_score_times("saves/times"); + world = create_world(); SDL_GetRendererOutputSize(ren, &width, &height); @@ -1460,7 +1576,7 @@ void startgame(SDL_Renderer * ren) { get_floor_ceiling(); Vect stpos = *world.uniques_index[ROOM_W]->room->ceil.items[2]->collision_poly; - player = get_player(stpos.x + 20, stpos.y - 60); + player = get_player(stpos.x, stpos.y - 15); world_thing player_world; player_world.kind = PLAYER_W; @@ -1574,8 +1690,7 @@ int step(void) { if (player.physics->position.x > world.uniques_index[ROOM_W]->room ->floor.items[3]->position.x) { level_timer_update(false); - } else { - } + } if (in_game && !game_paused) { advance_things(); diff --git a/src/game.h b/src/game.h index 122e9a7..1a97777 100644 --- a/src/game.h +++ b/src/game.h @@ -28,13 +28,27 @@ void next_level(); int step(void); +struct sg_times_list { + long *times; + int size; + int capacity; + void (*sort)(void); + char *filename; +}; + +int load_score_times(char *filename); +long get_best_time(void); + + /* array of all the things in the world and their kinds */ +extern struct sg_times_list save_times_lst; +int add_time(long time); +int write_times(void); extern void startgame(SDL_Renderer * ren) ; extern void process_keydown(SDL_Keysym key); extern void process_keyup(SDL_Keysym key); extern player_st player; extern long level_time; - extern bool game_paused; #endif diff --git a/src/main.c b/src/main.c index 938dfd1..b21a0e1 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,10 @@ #include #include +// only for mkdirat lol +#include +#include + #include "logger.h" #include "game.h" #include "draw.h" @@ -18,16 +22,6 @@ const int screen_height = 600; SDL_sem *resume; -long int *times; - -struct sg_times_list { - long *times; - int size; - int capacity; - void (*sort)(void); -}; - -struct sg_times_list save_times_lst; struct SDL_Window* make_window(void) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { @@ -60,6 +54,8 @@ int physics_loop(void *ptr) { SDL_Delay(1000); in_game = false; SDL_SemWait(resume); + add_time(level_time); + SDL_LockMutex(player.physics->lock); game_paused = true; in_game = true; @@ -142,73 +138,11 @@ int game(void) { } -int long_comparator(const void *a, const void *b, void *non) { - long A = *(long *)a; - long B = *(long *)b; - - return A - B; -} - -void sort_times(void) { - qsort_r(save_times_lst.times, save_times_lst.size, sizeof(long), long_comparator, NULL); -} - -int load_score_times(char *filename) { - FILE *f = fopen(filename, "r"); - - if (f) { - // get file size - fseek(f, 0L, SEEK_END); - long sz = ftell(f); - fseek(f, 0L, SEEK_SET); - char *text = malloc((sz + 1) * (sizeof(char))); - - // read file - fread(text,sizeof(char),sz, f); - fclose(f); - - int count = 1; - for (int i = 0; i < strlen(text); i++) { - if (text[i] == '\n') { - count++; - } - } - - long *times = malloc(count * sizeof(long)); - char *saveptr; - - // extract times - char * token = strtok_r(text, "\n", &saveptr); - int i = 0; - while (token != NULL) { - if (strlen(token) > 2) { - times[i] = atol(token); - i++; - } - token = strtok_r(NULL, "\n", &saveptr); - } - save_times_lst = (struct sg_times_list){.size=i, .capacity = count, .times=times, .sort=sort_times}; - save_times_lst.sort(); - } else { - perror("loading times"); - save_times_lst = (struct sg_times_list){.size=0, .capacity = 5, .times=calloc(5, sizeof(long)), .sort=sort_times}; - } - for (int i = 0; i < save_times_lst.size; i++) { - printf("%ld\n", save_times_lst.times[i]); - } - - return 0; -} - - -long get_best_time(void) { - save_times_lst.sort(); - return save_times_lst.times[0]; -} int main (int argc, char** argv) { - load_score_times("savegame"); + int err = mkdirat(AT_FDCWD, "saves", 0777); + game(); SDL_Quit(); //empty_cleanup_queue();