diff --git a/src/defs.h b/src/defs.h index 68cd0ef..7053e21 100644 --- a/src/defs.h +++ b/src/defs.h @@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PI 3.14159265358979323846 #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) +#define CAROLINE(a,b) MIN(a,b) #define STRNCPY(dest, src, n) strncpy(dest, src, n); dest[n - 1] = '\0' #define TO_RAIDANS(angleDegrees) (angleDegrees * PI / 180.0) #define TO_DEGREES(angleRadians) (angleRadians * 180.0 / PI) @@ -51,8 +52,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define NUM_TEXT_BUCKETS 64 #define TEXT_TTL (1000 * 20) -#define MAX_WIDGETS 48 - #define MAX_NAME_LENGTH 32 #define MAX_DESCRIPTION_LENGTH 512 #define MAX_LINE_LENGTH 1024 diff --git a/src/game/game.c b/src/game/game.c index e90c63e..1cd0911 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void loadMetaInfo(void); static void addKeyToStash(Item *item); static int sortItems(const void *a, const void *b); +void destroyGame(void); void initGame(void) { @@ -37,6 +38,8 @@ void initGame(void) game.stats[STAT_TIME_PLAYED] = 0; loadMetaInfo(); + + loadTrophyData(); } int addItem(Item *item, int num) @@ -269,6 +272,10 @@ void loadGame(void) int i; Tuple *t; Trophy *trophy; + + destroyGame(); + + initGame(); sprintf(filename, "%s/%d/game.json", app.saveDir, game.saveSlot); @@ -439,6 +446,72 @@ void restoreGameState(void) free(text); } +char *getSaveWidgetLabel(char *filename) +{ + static char label[MAX_NAME_LENGTH]; + cJSON *root, *statsJSON; + char *text, *statName; + int i, gameDone, gameTotal, stats[STAT_MAX]; + + strcpy(label, ""); + + sprintf(filename, "%s/%d/game.json", app.saveDir, game.saveSlot); + + text = readFile(filename); + + root = cJSON_Parse(text); + + statsJSON = cJSON_GetObjectItem(root, "stats"); + + memset(stats, 0, sizeof(int) * STAT_MAX); + + for (i = 0 ; i < STAT_MAX ; i++) + { + statName = getLookupName("STAT_", i); + + if (cJSON_GetObjectItem(statsJSON, statName)) + { + stats[i] = cJSON_GetObjectItem(statsJSON, statName)->valueint; + } + } + + cJSON_Delete(root); + + free(text); + + gameDone = stats[STAT_MISSIONS_COMPLETE] + stats[STAT_MIAS_RESCUED] + stats[STAT_TARGETS_DEFEATED] + stats[STAT_KEYS_FOUND] + stats[STAT_HEARTS_FOUND] + stats[STAT_CELLS_FOUND]; + gameTotal = game.totalMissions + game.totalMIAs + game.totalTargets + game.totalKeys + game.totalHearts + game.totalCells; + + sprintf(label, "%d%% - %s", getPercent(gameDone, gameTotal), timeToString(stats[STAT_TIME_PLAYED], 1)); + + return label; +} + +void deleteSaveSlot(int slot) +{ + int i, numFiles; + char path[MAX_FILENAME_LENGTH], **filenames; + + sprintf(path, "%s/%d", app.saveDir, slot); + + filenames = getFileList(path, &numFiles); + + for (i = 0 ; i < numFiles ; i++) + { + sprintf(path, "%s/%d/%s", app.saveDir, i, filenames[i]); + + if (!deleteFile(path)) + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Failed to delete save file '%s'", path); + exit(1); + } + + free(filenames[i]); + } + + free(filenames); +} + static int sortItems(const void *a, const void *b) { Entity *e1 = *((Entity**)a); @@ -460,4 +533,26 @@ static int sortItems(const void *a, const void *b) void destroyGame(void) { + Tuple *t; + Trophy *trophy; + + memset(game.keys, 0, sizeof(Tuple) * MAX_KEY_TYPES); + + while (game.missionStatusHead.next) + { + t = game.missionStatusHead.next; + + game.missionStatusHead.next = t->next; + + free(t); + } + + while (game.trophyHead.next) + { + trophy = game.trophyHead.next; + + game.trophyHead.next = trophy->next; + + free(trophy); + } } diff --git a/src/game/game.h b/src/game/game.h index 08da853..0571142 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -28,6 +28,11 @@ extern Trophy *getTrophy(char *id); extern int lookup(char *name); extern char *readFile(const char *filename); extern int writeFile(const char *filename, const char *data); +extern char *timeToString(int seconds, int showHours); +extern int getPercent(float current, float total); +extern char **getFileList(const char *dir, int *count); +extern int deleteFile(char *path); +extern void loadTrophyData(void); extern App app; extern Entity *self; diff --git a/src/game/title.c b/src/game/title.c index 69e37c7..3c895ac 100644 --- a/src/game/title.c +++ b/src/game/title.c @@ -23,16 +23,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void logic(void); static void draw(void); static int getRecentSave(void); +static void populateSaveSlotWidgets(void); +static void doNewGame(void); +static void doLoadGame(void); +static void doContinueGame(void); +static void doOptions(void); +static void doCredits(void); +static void doQuit(void); +static void doSaveSlot(void); +static void doLoadCancel(void); +static void doOK(void); +static void doCancel(void); static Texture *atlasTexture; static Atlas *title; static int recentSaveSlot; +static int saveAction; static Widget *newGame; -static Widget *loadGame; +static Widget *load; static Widget *continueGame; static Widget *options; static Widget *credits; static Widget *quit; +static Widget *save[MAX_SAVE_SLOTS]; +static Widget *loadCancel; +static Widget *ok; +static Widget *cancel; void initTitle(void) { @@ -43,11 +59,33 @@ void initTitle(void) title = getImageFromAtlas("gfx/main/title.png"); newGame = getWidget("new", "title"); - loadGame = getWidget("load", "title"); + newGame->action = &doNewGame; + + load = getWidget("load", "title"); + load->action = &doLoadGame; + continueGame = getWidget("continue", "title"); + continueGame->action = &doContinueGame; + options = getWidget("options", "title"); + options->action = &doOptions; + credits = getWidget("credits", "title"); + credits->action = &doCredits; + quit = getWidget("exit", "title"); + quit->action = &doQuit; + + populateSaveSlotWidgets(); + + loadCancel = getWidget("cancel", "load"); + loadCancel->action = doLoadCancel; + + ok = getWidget("ok", "destroy"); + ok->action = doOK; + + cancel = getWidget("cancel", "destroy"); + cancel->action = doCancel; recentSaveSlot = getRecentSave(); @@ -59,7 +97,7 @@ void initTitle(void) } else { - loadGame->disabled = 1; + load->disabled = 1; continueGame->disabled = 1; } @@ -78,8 +116,8 @@ static void draw(void) { blitRect(atlasTexture->texture, SCREEN_WIDTH / 2, 175, &title->rect, 1); - drawText(10, SCREEN_HEIGHT - 30, 18, TA_LEFT, colors.white, "Copyright 2014, 2018 Parallel Realities"); - drawText(SCREEN_WIDTH - 10, SCREEN_HEIGHT - 30, 18, TA_RIGHT, colors.white, "Version %.2f.%d", VERSION, REVISION); + drawText(10, SCREEN_HEIGHT - 30, 16, TA_LEFT, colors.white, "Copyright 2014, 2018 Parallel Realities"); + drawText(SCREEN_WIDTH - 10, SCREEN_HEIGHT - 30, 16, TA_RIGHT, colors.white, "Version %.2f.%d", VERSION, REVISION); drawWidgets(); } @@ -110,3 +148,108 @@ static int getRecentSave(void) return slot; } + +static void populateSaveSlotWidgets(void) +{ + int i; + char name[MAX_NAME_LENGTH], filename[MAX_FILENAME_LENGTH]; + + for (i = 0 ; i < MAX_SAVE_SLOTS ; i++) + { + sprintf(name, "save%d", i); + + save[i] = getWidget(name, "saveSlot"); + + sprintf(filename, "%s/%d/game.json", app.saveDir, i); + + if (fileExists(filename)) + { + strcpy(save[i]->label, getSaveWidgetLabel(filename)); + save[i]->value[0] = 1; + } + else + { + strcpy(save[i]->label, "(empty)"); + save[i]->value[0] = 0; + } + + save[i]->value[1] = i; + + save[i]->action = &doSaveSlot; + } +} + +static void doNewGame(void) +{ + saveAction = SA_DELETE; + + destroyGame(); +} + +static void doLoadGame(void) +{ + saveAction = SA_LOAD; + + showWidgetGroup("saveSlot"); + + loadCancel->visible = 1; +} + +static void doContinueGame(void) +{ + game.saveSlot = continueGame->value[1]; + + loadGame(); + + initHub(); +} + +static void doOptions(void) +{ + +} + +static void doCredits(void) +{ + +} + +static void doQuit(void) +{ + exit(1); +} + +static void doSaveSlot(void) +{ + Widget *w; + + w = getSelectedWidget(); + + game.saveSlot = w->value[1]; + + if (saveAction == SA_LOAD) + { + loadGame(); + + initHub(); + } + else if (saveAction == SA_DELETE) + { + + } +} + +static void doLoadCancel(void) +{ + showWidgetGroup("title"); +} + +static void doOK(void) +{ + +} + +static void doCancel(void) +{ + +} diff --git a/src/game/title.h b/src/game/title.h index 5d390fa..95fdb58 100644 --- a/src/game/title.h +++ b/src/game/title.h @@ -20,6 +20,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" +enum +{ + SA_LOAD, + SA_DELETE +}; + extern void blitRect(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, int center); extern void doWidgets(void); extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); @@ -35,6 +41,12 @@ extern void startSectionTransition(void); extern long getFileModTime(char *filename); extern int fileExists(const char *filename); extern void setSelectedWidget(char *name, char *group); +extern char *getSaveWidgetLabel(char *filename); +extern Widget *getSelectedWidget(void); +extern void loadGame(void); +extern void initHub(void); +extern void destroyGame(void); extern App app; extern Colors colors; +extern Game game; diff --git a/src/game/trophies.c b/src/game/trophies.c index 0543ac8..93c518f 100644 --- a/src/game/trophies.c +++ b/src/game/trophies.c @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "trophies.h" static void setSparkleColor(Trophy *t); -static void loadTrophyData(void); static void resetAlert(void); static void nextAlert(void); @@ -67,12 +66,6 @@ void initTrophies(void) savedScreenshot = 0; page = 0; - - loadTrophyData(); - - maxPages = numTrophies; - maxPages /= TROPHIES_PER_PAGE; - maxPages = ceil(maxPages); resetAlert(); } @@ -351,7 +344,7 @@ void saveTrophyScreenshot(void) } } -static void loadTrophyData(void) +void loadTrophyData(void) { cJSON *root, *node; char *text; @@ -395,6 +388,10 @@ static void loadTrophyData(void) cJSON_Delete(root); free(text); + + maxPages = numTrophies; + maxPages /= TROPHIES_PER_PAGE; + maxPages = ceil(maxPages); } static void setSparkleColor(Trophy *t) diff --git a/src/system/io.c b/src/system/io.c index 5540e60..80f5b81 100644 --- a/src/system/io.c +++ b/src/system/io.c @@ -195,6 +195,11 @@ char **getFileList(const char *dir, int *count) return filenames; } +int deleteFile(char *path) +{ + return unlink(path); +} + static int stringComparator(const void *a, const void *b) { char **s1 = (char **)a; diff --git a/src/system/widgets.c b/src/system/widgets.c index 11cae5c..c0599a1 100644 --- a/src/system/widgets.c +++ b/src/system/widgets.c @@ -299,7 +299,25 @@ Widget *getWidget(char *name, char *group) void setSelectedWidget(char *name, char *group) { - selectedWidget = getWidget(name, group); + Widget *w; + int i; + + for (i = 0 ; i < numWidgets ; i++) + { + w = &widgets[i]; + + if (strcmp(w->name, name) == 0 && strcmp(w->group, group) == 0) + { + widgetIndex = i; + selectedWidget = w; + return; + } + } +} + +Widget *getSelectedWidget(void) +{ + return selectedWidget; } Widget *selectWidgetAt(int x, int y) diff --git a/src/system/widgets.h b/src/system/widgets.h index 9907263..d0f9e35 100644 --- a/src/system/widgets.h +++ b/src/system/widgets.h @@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" #include "../json/cJSON.h" +#define MAX_WIDGETS 64 + extern void clearControl(int type); extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); extern void drawOutlineRect(int x, int y, int w, int h, int r, int g, int b, int a);