From 6842f4650923e87849459b1ca035368e9c7cd2f6 Mon Sep 17 00:00:00 2001 From: Cong Date: Thu, 4 Jul 2013 22:27:29 +1000 Subject: [PATCH] Autosave last password (#107) Fix random seed not being used bug (fixes #118) --- .gitignore | 1 + src/CMakeLists.txt | 2 + src/autosave.c | 112 ++++++++++++++++++++++++++++++++++++++ src/autosave.h | 52 ++++++++++++++++++ src/cdogs.c | 23 ++++---- src/json/json.c | 6 +- src/password.c | 1 + src/password.h | 17 ++---- src/tests/CMakeLists.txt | 6 ++ src/tests/autosave_test.c | 60 ++++++++++++++++++++ 10 files changed, 255 insertions(+), 25 deletions(-) create mode 100644 src/autosave.c create mode 100644 src/autosave.h create mode 100644 src/tests/autosave_test.c diff --git a/.gitignore b/.gitignore index 3c6bc6934..55a64474f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ cdogs-sdl *.exe cdogs-sdl-editor libcdogs.a +autosave_test config_test tmp libjson.a diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afba7d5a8..7de33fd82 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,7 @@ add_subdirectory(json) add_subdirectory(tests) set(CDOGS_SDL_SOURCES + autosave.c campaigns.c cdogs.c credits.c @@ -124,6 +125,7 @@ set(CDOGS_SDL_SOURCES password.c prep.c) set(CDOGS_SDL_HEADERS + autosave.h campaigns.h credits.h mainmenu.h diff --git a/src/autosave.c b/src/autosave.c new file mode 100644 index 000000000..76ebfeeb9 --- /dev/null +++ b/src/autosave.c @@ -0,0 +1,112 @@ +/* + C-Dogs SDL + A port of the legendary (and fun) action/arcade cdogs. + + Copyright (c) 2013, Cong Xu + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ +#include "autosave.h" + +#include +#include +#include + +#include + +#include + + +void AutosaveInit(Autosave *autosave) +{ + strcpy(autosave->LastMission.CampaignPath, ""); + strcpy(autosave->LastMission.Password, ""); +} + +static void LoadLastMissionNode(MissionSave *lm, json_t *node) +{ + strcpy(lm->CampaignPath, json_find_first_label(node, "CampaignPath")->child->text); + strcpy(lm->Password, json_find_first_label(node, "Password")->child->text); +} +static void AddLastMissionNode(MissionSave *lm, json_t *root) +{ + json_t *subConfig = json_new_object(); + json_insert_pair_into_object( + subConfig, "CampaignPath", json_new_string(lm->CampaignPath)); + json_insert_pair_into_object( + subConfig, "Password", json_new_string(lm->Password)); + json_insert_pair_into_object(root, "LastMission", subConfig); +} + +void AutosaveLoad(Autosave *autosave, const char *filename) +{ + FILE *f = fopen(filename, "r"); + json_t *root = NULL; + + if (f == NULL) + { + printf("Error loading autosave '%s'\n", filename); + goto bail; + } + + if (json_stream_parse(f, &root) != JSON_OK) + { + printf("Error parsing autosave '%s'\n", filename); + goto bail; + } + LoadLastMissionNode(&autosave->LastMission, json_find_first_label(root, "LastMission")->child); + +bail: + json_free_value(&root); + if (f != NULL) + { + fclose(f); + } +} + +void AutosaveSave(Autosave *autosave, const char *filename) +{ + FILE *f = fopen(filename, "w"); + char *text = NULL; + json_t *root; + + if (f == NULL) + { + printf("Error saving config '%s'\n", filename); + return; + } + + setlocale(LC_ALL, ""); + + root = json_new_object(); + json_insert_pair_into_object(root, "Version", json_new_number("1")); + AddLastMissionNode(&autosave->LastMission, root); + + json_tree_to_string(root, &text); + fputs(json_format_string(text), f); + + // clean up + free(text); + json_free_value(&root); + + fclose(f);} diff --git a/src/autosave.h b/src/autosave.h new file mode 100644 index 000000000..2edfc189d --- /dev/null +++ b/src/autosave.h @@ -0,0 +1,52 @@ +/* + C-Dogs SDL + A port of the legendary (and fun) action/arcade cdogs. + + Copyright (c) 2013, Cong Xu + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _autosave +#define _autosave + +#include + +#define PASSWORD_MAX 16 +#define AUTOSAVE_FILE "autosave.json" + +typedef struct +{ + char CampaignPath[CDOGS_PATH_MAX]; + char Password[PASSWORD_MAX + 1]; +} MissionSave; + +typedef struct +{ + MissionSave LastMission; +} Autosave; + +void AutosaveInit(Autosave *autosave); +void AutosaveLoad(Autosave *autosave, const char *filename); +void AutosaveSave(Autosave *autosave, const char *filename); + +#endif diff --git a/src/cdogs.c b/src/cdogs.c index 944eb6dc7..c27297da3 100644 --- a/src/cdogs.c +++ b/src/cdogs.c @@ -76,6 +76,7 @@ #include #include +#include "autosave.h" #include "campaigns.h" #include "credits.h" #include "mainmenu.h" @@ -83,7 +84,7 @@ #include "prep.h" -static char lastPassword[PASSWORD_MAX + 1] = ""; +Autosave gAutosave; void DrawObjectiveInfo(int index, int x, int y, struct Mission *mission) @@ -222,10 +223,9 @@ void MissionBriefing(void *bkg) if (gMission.index) { char str[512]; - - strcpy(lastPassword, MakePassword(gMission.index)); - - sprintf(str, "Password: %s", lastPassword); + strcpy(gAutosave.LastMission.Password, MakePassword(gMission.index)); + AutosaveSave(&gAutosave, GetConfigFilePath(AUTOSAVE_FILE)); + sprintf(str, "Password: %s", gAutosave.LastMission.Password); CDogsTextStringSpecial(str, TEXT_TOP | TEXT_XCENTER, 0, (y - 15)); } @@ -261,11 +261,10 @@ void Summary(int x, struct PlayerData *data, int character) char s[50]; int y = gGraphicsDevice.cachedConfig.ResolutionHeight / 3; - if (lastPassword[0]) + if (strlen(gAutosave.LastMission.Password) > 0) { char s1[512]; - - sprintf(s1, "Last password: %s", lastPassword); + sprintf(s1, "Last password: %s", gAutosave.LastMission.Password); CDogsTextStringSpecial( s1, TEXT_BOTTOM | TEXT_XCENTER, @@ -759,9 +758,9 @@ int Campaign(void *bkg) if (IsPasswordAllowed(gCampaign.mode)) { - mission = EnterPassword(bkg, lastPassword); + mission = EnterPassword(bkg, gAutosave.LastMission.Password); } - lastPassword[0] = 0; + strcpy(gAutosave.LastMission.Password, ""); return Game(bkg, mission); } @@ -836,6 +835,7 @@ void *MakeBkg(void) CFREE(buffer); KillAllObjects(); FreeTriggersAndWatches(); + gCampaign.seed = gConfig.Game.RandomSeed; p = bkg; SetPaletteRanges(15, 12, 10, 0); @@ -966,6 +966,8 @@ int main(int argc, char *argv[]) ConfigLoadDefault(&gConfig); ConfigLoad(&gConfig, GetConfigFilePath(CONFIG_FILE)); LoadCredits(&creditsDisplayer, &tablePurple, &tableDarker); + AutosaveInit(&gAutosave); + AutosaveLoad(&gAutosave, GetConfigFilePath(AUTOSAVE_FILE)); for (i = 1; i < argc; i++) { if ((strlen(argv[i]) > 1 && *(argv[i]) == '-') || *(argv[i]) == '/') { @@ -1109,6 +1111,7 @@ int main(int argc, char *argv[]) GraphicsTerminate(&gGraphicsDevice); + AutosaveSave(&gAutosave, GetConfigFilePath(AUTOSAVE_FILE)); ConfigSave(&gConfig, GetConfigFilePath(CONFIG_FILE)); SaveTemplates(); FreeSongs(&gMenuSongs); diff --git a/src/json/json.c b/src/json/json.c index ee98b8cf5..fb928d406 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -434,8 +434,10 @@ json_free_value (json_t ** value) { json_t *cursor = *value; - assert (value); - assert (*value); + if (value == NULL || *value == NULL) + { + return; + } while (*value) { diff --git a/src/password.c b/src/password.c index 5b87c4bd2..8c6067358 100644 --- a/src/password.c +++ b/src/password.c @@ -64,6 +64,7 @@ #include #include +#include "autosave.h" #include "menu.h" #define DONE "Done" diff --git a/src/password.h b/src/password.h index 14109b5dd..cca38c3a8 100644 --- a/src/password.h +++ b/src/password.h @@ -18,20 +18,11 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -------------------------------------------------------------------------------- - - password.h - - - Author: $Author$ - Rev: $Revision$ - URL: $HeadURL$ - ID: $Id$ - */ - -#define PASSWORD_MAX 16 - +#ifndef __password +#define __password const char *MakePassword(int mission); int EnterPassword(void *bkg, const char *password); + +#endif diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 72eaa937d..826df5f51 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -9,6 +9,12 @@ add_subdirectory(cbehave) include_directories(. ../cdogs) +add_executable(autosave_test + autosave_test.c + ../autosave.h + ../autosave.c) +target_link_libraries(autosave_test cbehave json ${EXTRA_LIBRARIES}) + add_executable(config_test config_test.c ../cdogs/config.h diff --git a/src/tests/autosave_test.c b/src/tests/autosave_test.c new file mode 100644 index 000000000..98a5e5e88 --- /dev/null +++ b/src/tests/autosave_test.c @@ -0,0 +1,60 @@ +#include + +#include + +#include + + +FEATURE(1, "Initialise autosave") + SCENARIO("Initialise autosave") + { + Autosave autosave1, autosave2; + GIVEN("two autosaves") + GIVEN_END + + WHEN("I initialise both") + AutosaveInit(&autosave1); + AutosaveInit(&autosave2); + WHEN_END + + THEN("they should equal each other"); + SHOULD_STR_EQUAL(autosave1.LastMission.CampaignPath, autosave2.LastMission.CampaignPath); + SHOULD_STR_EQUAL(autosave1.LastMission.Password, autosave2.LastMission.Password); + THEN_END + } + SCENARIO_END +FEATURE_END + +FEATURE(2, "Save and load") + SCENARIO("Save and load") + { + Autosave autosave1, autosave2; + GIVEN("an autosave with some values, and I save it to file") + AutosaveInit(&autosave1); + strcpy(autosave1.LastMission.CampaignPath, "path/to/file"); + strcpy(autosave1.LastMission.Password, "password"); + AutosaveSave(&autosave1, "tmp"); + GIVEN_END + + WHEN("I load a second autosave from that file") + AutosaveLoad(&autosave2, "tmp"); + WHEN_END + + THEN("they should equal each other"); + SHOULD_STR_EQUAL(autosave1.LastMission.CampaignPath, autosave2.LastMission.CampaignPath); + SHOULD_STR_EQUAL(autosave1.LastMission.Password, autosave2.LastMission.Password); + THEN_END + } + SCENARIO_END +FEATURE_END + +int main(void) +{ + cbehave_feature features[] = + { + {feature_idx(1)}, + {feature_idx(2)} + }; + + return cbehave_runner("Autosave features are:", features); +}