Completes game saving and resuming
This commit is contained in:
parent
b385f6e73a
commit
5a9335576a
|
@ -192,6 +192,7 @@ add_executable(breakhack
|
|||
src/util
|
||||
src/event
|
||||
src/player
|
||||
src/save
|
||||
src/map
|
||||
src/map_lua
|
||||
src/camera
|
||||
|
|
135
src/main.c
135
src/main.c
|
@ -58,6 +58,7 @@
|
|||
#include "sprite_util.h"
|
||||
#include "event.h"
|
||||
#include "config.h"
|
||||
#include "save.h"
|
||||
|
||||
#ifdef STEAM_BUILD
|
||||
#include "checksum.h"
|
||||
|
@ -420,6 +421,56 @@ goToCharacterMenu(void *unused)
|
|||
gGameState = CHARACTER_MENU;
|
||||
}
|
||||
|
||||
static void
|
||||
choose_music(void)
|
||||
{
|
||||
if (cLevel > (unsigned int) (quickGame ? 11 : 19)) {
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
} else if (cLevel % (quickGame ? 3 : 5) == 0) {
|
||||
gui_log("You sense something powerful in the vicinity");
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
} else {
|
||||
mixer_play_music(GAME_MUSIC0 + get_random(2));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
continueGame(void *unused)
|
||||
{
|
||||
(void) unused;
|
||||
const Save *save = save_get();
|
||||
quickGame = save->quickGame;
|
||||
arcadeGame = save->arcadeGame;
|
||||
|
||||
playerClass = save->player_class;
|
||||
cLevel = save->map_level;
|
||||
set_random_seed(save->seed);
|
||||
debug("Loading seed: %d", save->seed);
|
||||
debug("Loading map level: %d", save->map_level);
|
||||
|
||||
gGameState = PLAYING;
|
||||
if (gPlayer)
|
||||
player_destroy(gPlayer);
|
||||
gPlayer = player_create(playerClass, gCamera);
|
||||
|
||||
// Load player from save
|
||||
gPlayer->daggers = save->player_daggers;
|
||||
gPlayer->xp = save->player_xp;
|
||||
gPlayer->stateData = save->player_state;
|
||||
gPlayer->stats = save->player_stats;
|
||||
gPlayer->stat_data = save->player_player_stats;
|
||||
gPlayer->potion_sips = save->player_potion_sips;
|
||||
gPlayer->equipment = save->player_equipment;
|
||||
gPlayer->gold = save->player_gold;
|
||||
|
||||
choose_music();
|
||||
resetGame();
|
||||
skillbar_reset(gSkillBar);
|
||||
gui_clear_message_log();
|
||||
gui_log("The Dungeon Crawl continues!");
|
||||
gui_event_message("Welcome back!");
|
||||
}
|
||||
|
||||
static void
|
||||
startRegularGame(void *unused)
|
||||
{
|
||||
|
@ -459,6 +510,7 @@ static void
|
|||
goToMainMenu(void *unused)
|
||||
{
|
||||
UNUSED(unused);
|
||||
save_load();
|
||||
gui_clear_message_log();
|
||||
gGameState = MENU;
|
||||
menu_destroy(inGameMenu);
|
||||
|
@ -474,37 +526,47 @@ static void
|
|||
goToGameSelectMenu(void *unused)
|
||||
{
|
||||
UNUSED(unused);
|
||||
static TEXT_MENU_ITEM menuItems[] = {
|
||||
{
|
||||
"STANDARD GAME",
|
||||
"Standard 20 level game, recommended for new players",
|
||||
startRegularGame
|
||||
},
|
||||
int item_count = 3;
|
||||
#ifdef STEAM_BUILD
|
||||
{
|
||||
"WEEKLY CHALLENGE",
|
||||
"Quick game with weekly leaderboards at breakhack.net",
|
||||
startWeeklyGame
|
||||
},
|
||||
item_count += 1;
|
||||
#endif
|
||||
{
|
||||
"QUICK GAME",
|
||||
"Shorter 12 level game, with more action earlier in the game",
|
||||
startQuickGame
|
||||
},
|
||||
{
|
||||
"ARCADE GAME",
|
||||
"One big level with lots of action",
|
||||
startArcadeGame
|
||||
}
|
||||
if (save_exists()) {
|
||||
item_count += 1;
|
||||
}
|
||||
TEXT_MENU_ITEM *menuItems = ec_malloc(item_count * sizeof(TEXT_MENU_ITEM));
|
||||
int i = 0;
|
||||
if (save_exists()) {
|
||||
menuItems[i++] = (TEXT_MENU_ITEM) {
|
||||
"CONTINUE",
|
||||
"Continue your last session",
|
||||
continueGame,
|
||||
};
|
||||
}
|
||||
menuItems[i++] = (TEXT_MENU_ITEM) {
|
||||
"STANDARD GAME",
|
||||
"Standard 20 level game, recommended for new players",
|
||||
startRegularGame
|
||||
};
|
||||
#ifdef STEAM_BUILD
|
||||
menuItems[i++] = (TEXT_MENU_ITEM) {
|
||||
"WEEKLY CHALLENGE",
|
||||
"Quick game with weekly leaderboards at breakhack.net",
|
||||
startWeeklyGame
|
||||
};
|
||||
#endif
|
||||
menuItems[i++] = (TEXT_MENU_ITEM) {
|
||||
"QUICK GAME",
|
||||
"Shorter 12 level game, with more action earlier in the game",
|
||||
startQuickGame
|
||||
};
|
||||
menuItems[i++] = (TEXT_MENU_ITEM) {
|
||||
"ARCADE GAME",
|
||||
"One big level with lots of action",
|
||||
startArcadeGame
|
||||
};
|
||||
|
||||
#ifdef STEAM_BUILD
|
||||
int count = 4;
|
||||
#else
|
||||
int count = 3;
|
||||
#endif
|
||||
menu_create_text_menu(&gameSelectMenu, &menuItems[0], count, gRenderer);
|
||||
menu_create_text_menu(&gameSelectMenu, menuItems, item_count, gRenderer);
|
||||
free(menuItems);
|
||||
gGameState = GAME_SELECT;
|
||||
}
|
||||
|
||||
|
@ -691,6 +753,7 @@ init(void)
|
|||
event_register_listener(on_event_callback);
|
||||
|
||||
settings_init();
|
||||
save_init();
|
||||
hiscore_init();
|
||||
initMainMenu();
|
||||
|
||||
|
@ -874,17 +937,17 @@ check_next_level(void)
|
|||
return;
|
||||
}
|
||||
if (tile->levelExit) {
|
||||
mixer_play_effect(NEXT_LEVEL);
|
||||
++cLevel;
|
||||
if (cLevel > (unsigned int) (quickGame ? 11 : 19)) {
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
} else if (cLevel % (quickGame ? 3 : 5) == 0) {
|
||||
gui_log("You sense something powerful in the vicinity");
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
} else {
|
||||
mixer_play_music(GAME_MUSIC0 + get_random(2));
|
||||
if (!weeklyGame) {
|
||||
save_save(get_random_seed(),
|
||||
cLevel,
|
||||
quickGame,
|
||||
arcadeGame,
|
||||
gPlayer);
|
||||
}
|
||||
|
||||
mixer_play_effect(NEXT_LEVEL);
|
||||
choose_music();
|
||||
if (!gameCompleted()) {
|
||||
resetGame();
|
||||
}
|
||||
|
@ -1116,6 +1179,7 @@ run_game(void)
|
|||
camera_shake(VECTOR2D_RIGHT, 800);
|
||||
gui_log("The dungeon consumed you");
|
||||
gui_event_message("You died!");
|
||||
save_clear();
|
||||
end_game_details();
|
||||
mixer_play_effect(SPLAT);
|
||||
gGameState = GAME_OVER;
|
||||
|
@ -1349,6 +1413,7 @@ void close(void)
|
|||
texturecache_close();
|
||||
settings_close();
|
||||
hiscore_close();
|
||||
save_close();
|
||||
|
||||
#ifdef STEAM_BUILD
|
||||
steam_shutdown();
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
#include "sprite.h"
|
||||
|
||||
typedef struct TEXT_MENU_ITEM {
|
||||
char label[20];
|
||||
char description[100];
|
||||
char *label;
|
||||
char *description;
|
||||
void (*callback)(void*);
|
||||
} TEXT_MENU_ITEM;
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* BreakHack - A dungeone crawler RPG
|
||||
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "save.h"
|
||||
#include "sqlite3.h"
|
||||
#include "db.h"
|
||||
#include "defines.h"
|
||||
#include "util.h"
|
||||
|
||||
static sqlite3 *db = NULL;
|
||||
static bool loaded = false;
|
||||
static Save save;
|
||||
|
||||
static
|
||||
DbQuery MIGRATE_COMMAND = {
|
||||
"CREATE TABLE IF NOT EXISTS saves("
|
||||
"major_version INTEGER, "
|
||||
"minor_version INTEGER, "
|
||||
"patch_version INTEGER, "
|
||||
"save BLOB)",
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
static
|
||||
DbQuery CLEAR_SAVE = { "DELETE FROM saves", NULL, NULL };
|
||||
|
||||
static void
|
||||
create_table(void)
|
||||
{
|
||||
db_execute(db, &MIGRATE_COMMAND);
|
||||
}
|
||||
|
||||
void
|
||||
save_load(void)
|
||||
{
|
||||
debug("Loading save");
|
||||
const char *query =
|
||||
"SELECT save FROM saves "
|
||||
"WHERE major_version = ?"
|
||||
"AND minor_version = ?"
|
||||
"AND patch_version = ?"
|
||||
"LIMIT 1";
|
||||
|
||||
sqlite3_stmt *stmt = db_prepare(db, query);
|
||||
sqlite3_bind_int(stmt, 1, MAJOR_VERSION);
|
||||
sqlite3_bind_int(stmt, 2, MINOR_VERSION);
|
||||
sqlite3_bind_int(stmt, 3, PATCH_VERSION);
|
||||
if (SQLITE_ROW == sqlite3_step(stmt)) {
|
||||
int size = sqlite3_column_bytes(stmt, 0);
|
||||
debug("Reading save bytes: %d", size);
|
||||
memcpy(&save, sqlite3_column_blob(stmt, 0), size);
|
||||
loaded = true;
|
||||
} else {
|
||||
loaded = false;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void
|
||||
save_init(void)
|
||||
{
|
||||
if (!db_open(DB_FILE, &db)) {
|
||||
db_close(&db);
|
||||
fatal("Exiting");
|
||||
}
|
||||
create_table();
|
||||
save_load();
|
||||
}
|
||||
|
||||
const Save *
|
||||
save_get(void)
|
||||
{
|
||||
return &save;
|
||||
}
|
||||
|
||||
bool
|
||||
save_exists(void)
|
||||
{
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void
|
||||
save_save(unsigned int seed,
|
||||
unsigned int map_level,
|
||||
bool quickGame,
|
||||
bool arcadeGame,
|
||||
Player *player)
|
||||
{
|
||||
debug("Saving game, Seed: %d, Map level: %d", seed, map_level);
|
||||
save_clear();
|
||||
|
||||
save.seed = seed;
|
||||
save.map_level = map_level;
|
||||
save.quickGame = quickGame;
|
||||
save.arcadeGame = arcadeGame;
|
||||
save.player_stats = player->stats;
|
||||
save.player_daggers = player->daggers;
|
||||
save.player_gold = player->gold;
|
||||
save.player_xp = player->xp;
|
||||
save.player_potion_sips = player->potion_sips;
|
||||
save.player_player_stats = player->stat_data;
|
||||
save.player_state = player->stateData;
|
||||
save.player_class = player->class;
|
||||
save.player_equipment = player->equipment;
|
||||
|
||||
const char *query =
|
||||
"INSERT INTO saves"
|
||||
"(major_version, minor_version, patch_version, save) "
|
||||
"VALUES(?, ?, ?, ?)";
|
||||
|
||||
sqlite3_stmt *stmt = db_prepare(db, query);
|
||||
sqlite3_bind_int(stmt, 1, MAJOR_VERSION);
|
||||
sqlite3_bind_int(stmt, 2, MINOR_VERSION);
|
||||
sqlite3_bind_int(stmt, 3, PATCH_VERSION);
|
||||
sqlite3_bind_blob(stmt, 4, &save, sizeof(Save), SQLITE_STATIC);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void
|
||||
save_clear(void)
|
||||
{
|
||||
db_execute(db, &CLEAR_SAVE);
|
||||
}
|
||||
|
||||
void
|
||||
save_close(void)
|
||||
{
|
||||
db_close(&db);
|
||||
}
|
55
src/save.h
55
src/save.h
|
@ -1,16 +1,67 @@
|
|||
/*
|
||||
* BreakHack - A dungeone crawler RPG
|
||||
* Copyright (C) 2018 Linus Probert <linus.probert@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SAVE_H_
|
||||
#define SAVE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "player.h"
|
||||
#include "artifact.h"
|
||||
|
||||
typedef struct Save {
|
||||
int seed;
|
||||
bool quickGame;
|
||||
bool arcadeGame;
|
||||
unsigned int map_level;
|
||||
unsigned int player_level;
|
||||
unsigned int player_daggers;
|
||||
unsigned int player_xp;
|
||||
unsigned int player_potion_sips;
|
||||
unsigned int potion_sips;
|
||||
Stats player_stats;
|
||||
PlayerStatData player_player_stats;
|
||||
double player_gold;
|
||||
class_t class;
|
||||
PlayerStateData player_state;
|
||||
class_t player_class;
|
||||
PlayerEquipment player_equipment;
|
||||
} Save;
|
||||
|
||||
void
|
||||
save_init(void);
|
||||
|
||||
void
|
||||
save_load(void);
|
||||
|
||||
const Save *
|
||||
save_get(void);
|
||||
|
||||
bool
|
||||
save_exists(void);
|
||||
|
||||
void
|
||||
save_save(unsigned int seed,
|
||||
unsigned int map_level,
|
||||
bool quickGame,
|
||||
bool arcadeGame,
|
||||
Player *player);
|
||||
|
||||
void
|
||||
save_clear(void);
|
||||
|
||||
void
|
||||
save_close(void);
|
||||
|
||||
#endif // SAVE_H_
|
||||
|
|
|
@ -51,8 +51,6 @@ texturecache_add(const char *path)
|
|||
texture_load_from_file(tc->texture, path, renderer);
|
||||
ht_set(textures, path, tc);
|
||||
debug("Cached texture: %s", path);
|
||||
} else {
|
||||
debug("Retrieved cached texture: %s", path);
|
||||
}
|
||||
|
||||
return tc->texture;
|
||||
|
|
Loading…
Reference in New Issue