From 3db42f1700523edc3f9a93e8358d19c85657eff3 Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 10 Apr 2022 00:30:47 -0700 Subject: [PATCH] Allow coop mods to use the backup save slot independently of the normal one --- autogen/lua_constants/built-in.lua | 14 +- autogen/lua_definitions/constants.lua | 12 + autogen/lua_definitions/functions.lua | 6 + autogen/lua_definitions/manual.lua | 57 --- data/dynos_mgr_lvl.cpp | 2 +- docs/lua/functions.md | 21 ++ src/game/save_file.c | 80 ++--- src/game/text_save.inc.h | 334 ------------------ src/pc/lua/smlua_constants_autogen.c | 11 + src/pc/lua/smlua_functions_autogen.c | 12 + src/pc/lua/utils/smlua_misc_utils.c | 5 + src/pc/lua/utils/smlua_misc_utils.h | 1 + src/pc/network/network.c | 3 + src/pc/network/packets/packet_collect_star.c | 26 +- src/pc/network/packets/packet_save_file.c | 12 +- src/pc/network/packets/packet_save_set_flag.c | 22 +- 16 files changed, 156 insertions(+), 462 deletions(-) delete mode 100644 src/game/text_save.inc.h diff --git a/autogen/lua_constants/built-in.lua b/autogen/lua_constants/built-in.lua index 687307d2c..ad0af2704 100644 --- a/autogen/lua_constants/built-in.lua +++ b/autogen/lua_constants/built-in.lua @@ -269,6 +269,10 @@ function SOUND_ARG_LOAD(bank, soundID, priority, flags) return (bank << 28) | (soundID << 16) | (priority << 8) | flags | SOUND_STATUS_WAITING end +------------- +-- courses -- +------------- + --- @type integer COURSE_NONE = 0 --- @type integer @@ -320,4 +324,12 @@ COURSE_WMOTR = 23 --- @type integer COURSE_SA = 24 --- @type integer -COURSE_CAKE_END = 25 \ No newline at end of file +COURSE_CAKE_END = 25 +--- @type integer +COURSE_END = 26 +--- @type integer +COURSE_MAX = 25 +--- @type integer +COURSE_COUNT = 25 +--- @type integer +COURSE_MIN = 1 \ No newline at end of file diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index ed9a9f542..f13105b55 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -271,6 +271,10 @@ function SOUND_ARG_LOAD(bank, soundID, priority, flags) return (bank << 28) | (soundID << 16) | (priority << 8) | flags | SOUND_STATUS_WAITING end +------------- +-- courses -- +------------- + --- @type integer COURSE_NONE = 0 --- @type integer @@ -323,6 +327,14 @@ COURSE_WMOTR = 23 COURSE_SA = 24 --- @type integer COURSE_CAKE_END = 25 +--- @type integer +COURSE_END = 26 +--- @type integer +COURSE_MAX = 25 +--- @type integer +COURSE_COUNT = 25 +--- @type integer +COURSE_MIN = 1 --- @class BehaviorId diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 799a3d29f..584253127 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -7107,6 +7107,12 @@ function movtexqc_register(name, level, area, type) -- ... end +--- @param usingBackupSlot boolean +--- @return nil +function save_file_set_using_backup_slot(usingBackupSlot) + -- ... +end + --- @param index integer --- @param value integer --- @return nil diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index c1778e72f..dc6e94b3e 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -34,63 +34,6 @@ gLevelValues = {} --- @type BehaviorValues gBehaviorValues = {} ---------------- --- constants -- ---------------- - ---- @type integer -COURSE_NONE = 0 ---- @type integer -COURSE_BOB = 1 ---- @type integer -COURSE_WF = 2 ---- @type integer -COURSE_JRB = 3 ---- @type integer -COURSE_CCM = 4 ---- @type integer -COURSE_BBH = 5 ---- @type integer -COURSE_HMC = 6 ---- @type integer -COURSE_LLL = 7 ---- @type integer -COURSE_SSL = 8 ---- @type integer -COURSE_DDD = 9 ---- @type integer -COURSE_SL = 10 ---- @type integer -COURSE_WDW = 11 ---- @type integer -COURSE_TTM = 12 ---- @type integer -COURSE_THI = 13 ---- @type integer -COURSE_TTC = 14 ---- @type integer -COURSE_RR = 15 ---- @type integer -COURSE_BITDW = 16 ---- @type integer -COURSE_BITFS = 17 ---- @type integer -COURSE_BITS = 18 ---- @type integer -COURSE_PSS = 19 ---- @type integer -COURSE_COTMC = 20 ---- @type integer -COURSE_TOTWC = 21 ---- @type integer -COURSE_VCUTM = 22 ---- @type integer -COURSE_WMOTR = 23 ---- @type integer -COURSE_SA = 24 ---- @type integer -COURSE_CAKE_END = 25 - ----------- -- hooks -- ----------- diff --git a/data/dynos_mgr_lvl.cpp b/data/dynos_mgr_lvl.cpp index cce61b5fa..28b0c7b72 100644 --- a/data/dynos_mgr_lvl.cpp +++ b/data/dynos_mgr_lvl.cpp @@ -45,7 +45,7 @@ void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aPackFolder, const char *aL sDynosCustomLevelScripts.Add({ levelName, _Node }); // Override vanilla script - auto& newScripts = _Node->mLevelScripts; // DO NOT COMMIT + auto& newScripts = _Node->mLevelScripts; auto& newScriptNode = newScripts[newScripts.Count() - 1]; const void* originalScript = DynOS_Builtin_ScriptPtr_GetFromName(newScriptNode->mName.begin()); if (originalScript == NULL) { diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 6969e1d15..ab1f91590 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1321,6 +1321,7 @@ - [hud_hide](#hud_hide) - [hud_show](#hud_show) - [movtexqc_register](#movtexqc_register) + - [save_file_set_using_backup_slot](#save_file_set_using_backup_slot) - [set_environment_region](#set_environment_region) - [warp_exit_level](#warp_exit_level) - [warp_restart_level](#warp_restart_level) @@ -24841,6 +24842,26 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
+## [save_file_set_using_backup_slot](#save_file_set_using_backup_slot) + +### Lua Example +`save_file_set_using_backup_slot(usingBackupSlot)` + +### Parameters +| Field | Type | +| ----- | ---- | +| usingBackupSlot | `boolean` | + +### Returns +- None + +### C Prototype +`void save_file_set_using_backup_slot(bool usingBackupSlot);` + +[:arrow_up_small:](#) + +
+ ## [set_environment_region](#set_environment_region) ### Lua Example diff --git a/src/game/save_file.c b/src/game/save_file.c index a02901eab..a51e7e8c7 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -14,9 +14,6 @@ #include "pc/ini.h" #include "pc/network/network.h" -// note: force-disable TEXTSAVES until it's synchronized -#undef TEXTSAVES - #define MENU_DATA_MAGIC 0x4849 #define SAVE_FILE_MAGIC 0x4441 @@ -36,6 +33,7 @@ u8 gGotFileCoinHiScore = FALSE; u8 gCurrCourseStarFlags = 0; u8 gSpecialTripleJump = FALSE; +u8 gSaveFileUsingBackupSlot = FALSE; #define STUB_LEVEL(_0, _1, courseenum, _3, _4, _5, _6, _7, _8) courseenum, #define DEFINE_LEVEL(_0, _1, courseenum, _3, _4, _5, _6, _7, _8, _9, _10) courseenum, @@ -49,12 +47,6 @@ s8 gLevelToCourseNumTable[] = { STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1, "change this array if you are adding levels"); -#ifdef TEXTSAVES - -#include "text_save.inc.h" - -#endif - // This was probably used to set progress to 100% for debugging, but // it was removed from the release ROM. static void stub_save_file_1(void) { @@ -354,24 +346,14 @@ void save_file_do_save(s32 fileIndex, s8 forceSave) { if (fileIndex < 0 || fileIndex >= NUM_SAVE_FILES) return; -#ifdef TEXTSAVES - if (gSaveFileModified && gNetworkType != NT_CLIENT) { - // Write to text file - write_text_save(fileIndex); - gSaveFileModified = FALSE; - gMainMenuDataModified = FALSE; - return; - } -#endif - if (gSaveFileModified) { // Compute checksum add_save_block_signature(&gSaveBuffer.files[fileIndex][0], sizeof(gSaveBuffer.files[fileIndex][0]), SAVE_FILE_MAGIC); // Copy to backup slot - bcopy(&gSaveBuffer.files[fileIndex][0], &gSaveBuffer.files[fileIndex][1], - sizeof(gSaveBuffer.files[fileIndex][1])); + //bcopy(&gSaveBuffer.files[fileIndex][0], &gSaveBuffer.files[fileIndex][1], + //sizeof(gSaveBuffer.files[fileIndex][1])); // Write to EEPROM write_eeprom_savefile(fileIndex, 0, 2); @@ -387,6 +369,7 @@ void save_file_erase(s32 fileIndex) { touch_high_score_ages(fileIndex); bzero(&gSaveBuffer.files[fileIndex][0], sizeof(gSaveBuffer.files[fileIndex][0])); + bzero(&gSaveBuffer.files[fileIndex][1], sizeof(gSaveBuffer.files[fileIndex][1])); gSaveFileModified = TRUE; save_file_do_save(fileIndex, TRUE); @@ -400,24 +383,15 @@ BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex) { touch_high_score_ages(destFileIndex); bcopy(&gSaveBuffer.files[srcFileIndex][0], &gSaveBuffer.files[destFileIndex][0], sizeof(gSaveBuffer.files[destFileIndex][0])); + bcopy(&gSaveBuffer.files[srcFileIndex][1], &gSaveBuffer.files[destFileIndex][1], + sizeof(gSaveBuffer.files[destFileIndex][1])); gSaveFileModified = TRUE; save_file_do_save(destFileIndex, TRUE); } -#ifdef TEXTSAVES -static void save_file_load_textsaves(void) { - for (s32 file = 0; file < NUM_SAVE_FILES; file++) { - read_text_save(file); - } - gSaveFileModified = TRUE; - gMainMenuDataModified = TRUE; - stub_save_file_1(); -} -#endif - void save_file_load_all(UNUSED u8 reload) { - s32 file; + //s32 file; gMainMenuDataModified = FALSE; gSaveFileModified = FALSE; @@ -430,6 +404,7 @@ void save_file_load_all(UNUSED u8 reload) { save_file_bswap(&gSaveBuffer); // Verify the main menu data and create a backup copy if only one of the slots is valid. + /* Disable this so the 'backup' slot can be used s32 validSlots; validSlots = verify_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC); validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]),MENU_DATA_MAGIC) << 1; @@ -461,6 +436,7 @@ void save_file_load_all(UNUSED u8 reload) { break; } } + */ stub_save_file_1(); } @@ -471,11 +447,11 @@ void save_file_load_all(UNUSED u8 reload) { */ void save_file_reload(void) { // Copy save file data from backup - bcopy(&gSaveBuffer.files[gCurrSaveFileNum - 1][1], &gSaveBuffer.files[gCurrSaveFileNum - 1][0], + /*bcopy(&gSaveBuffer.files[gCurrSaveFileNum - 1][1], &gSaveBuffer.files[gCurrSaveFileNum - 1][0], sizeof(gSaveBuffer.files[gCurrSaveFileNum - 1][0])); // Copy main menu data from backup - bcopy(&gSaveBuffer.menuData[1], &gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0])); + bcopy(&gSaveBuffer.menuData[1], &gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]));*/ gMainMenuDataModified = FALSE; gSaveFileModified = FALSE; @@ -509,7 +485,7 @@ void save_file_collect_star_or_key(s16 coinScore, s16 starIndex, u8 fromNetwork) } if (coinScore > save_file_get_course_coin_score(fileIndex, courseIndex)) { - gSaveBuffer.files[fileIndex][0].courseCoinScores[courseIndex] = coinScore; + gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].courseCoinScores[courseIndex] = coinScore; touch_coin_score_age(fileIndex, courseIndex); gGotFileCoinHiScore = TRUE; @@ -602,14 +578,14 @@ void save_file_set_flags(u32 flags) { flags &= ~(SAVE_FLAG_CAP_ON_GROUND | SAVE_FLAG_CAP_ON_KLEPTO | SAVE_FLAG_CAP_ON_MR_BLIZZARD | SAVE_FLAG_CAP_ON_UKIKI); if (flags == 0) { return; } - gSaveBuffer.files[gCurrSaveFileNum - 1][0].flags |= (flags | SAVE_FLAG_FILE_EXISTS); + gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].flags |= (flags | SAVE_FLAG_FILE_EXISTS); gSaveFileModified = TRUE; network_send_save_set_flag(gCurrSaveFileNum - 1, 0, 0, (flags | SAVE_FLAG_FILE_EXISTS)); } void save_file_clear_flags(u32 flags) { - gSaveBuffer.files[gCurrSaveFileNum - 1][0].flags &= ~flags; - gSaveBuffer.files[gCurrSaveFileNum - 1][0].flags |= SAVE_FLAG_FILE_EXISTS; + gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].flags &= ~flags; + gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].flags |= SAVE_FLAG_FILE_EXISTS; gSaveFileModified = TRUE; } @@ -617,7 +593,7 @@ u32 save_file_get_flags(void) { if (gCurrCreditsEntry != NULL || gCurrDemoInput != NULL) { return 0; } - return gSaveBuffer.files[gCurrSaveFileNum - 1][0].flags; + return gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].flags; } /** @@ -628,9 +604,9 @@ u32 save_file_get_star_flags(s32 fileIndex, s32 courseIndex) { u32 starFlags; if (courseIndex == -1) { - starFlags = SAVE_FLAG_TO_STAR_FLAG(gSaveBuffer.files[fileIndex][0].flags); + starFlags = SAVE_FLAG_TO_STAR_FLAG(gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].flags); } else { - starFlags = gSaveBuffer.files[fileIndex][0].courseStars[courseIndex] & 0x7F; + starFlags = gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].courseStars[courseIndex] & 0x7F; } return starFlags; @@ -642,40 +618,40 @@ u32 save_file_get_star_flags(s32 fileIndex, s32 courseIndex) { */ void save_file_set_star_flags(s32 fileIndex, s32 courseIndex, u32 starFlags) { if (courseIndex == -1) { - gSaveBuffer.files[fileIndex][0].flags |= STAR_FLAG_TO_SAVE_FLAG(starFlags); + gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].flags |= STAR_FLAG_TO_SAVE_FLAG(starFlags); network_send_save_set_flag(fileIndex, courseIndex, 0, (STAR_FLAG_TO_SAVE_FLAG(starFlags) | SAVE_FLAG_FILE_EXISTS)); } else { - gSaveBuffer.files[fileIndex][0].courseStars[courseIndex] |= starFlags; + gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].courseStars[courseIndex] |= starFlags; network_send_save_set_flag(fileIndex, courseIndex, starFlags, SAVE_FLAG_FILE_EXISTS); } - gSaveBuffer.files[fileIndex][0].flags |= SAVE_FLAG_FILE_EXISTS; + gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].flags |= SAVE_FLAG_FILE_EXISTS; gSaveFileModified = TRUE; } s32 save_file_get_course_coin_score(s32 fileIndex, s32 courseIndex) { - return gSaveBuffer.files[fileIndex][0].courseCoinScores[courseIndex]; + return gSaveBuffer.files[fileIndex][gSaveFileUsingBackupSlot].courseCoinScores[courseIndex]; } /** * Return TRUE if the cannon is unlocked in the current course. */ s32 save_file_is_cannon_unlocked(void) { - return (gSaveBuffer.files[gCurrSaveFileNum - 1][0].courseStars[gCurrCourseNum] & 0x80) != 0; + return (gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].courseStars[gCurrCourseNum] & 0x80) != 0; } /** * Sets the cannon status to unlocked in the current course. */ void save_file_set_cannon_unlocked(void) { - gSaveBuffer.files[gCurrSaveFileNum - 1][0].courseStars[gCurrCourseNum] |= 0x80; - gSaveBuffer.files[gCurrSaveFileNum - 1][0].flags |= SAVE_FLAG_FILE_EXISTS; + gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].courseStars[gCurrCourseNum] |= 0x80; + gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].flags |= SAVE_FLAG_FILE_EXISTS; gSaveFileModified = TRUE; network_send_save_set_flag(gCurrSaveFileNum - 1, gCurrCourseNum, 0x80, SAVE_FLAG_FILE_EXISTS); } void save_file_set_cap_pos(s16 x, s16 y, s16 z) { - struct SaveFile *saveFile = &gSaveBuffer.files[gCurrSaveFileNum - 1][0]; + struct SaveFile *saveFile = &gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot]; saveFile->capLevel = gCurrLevelNum; saveFile->capArea = gCurrAreaIndex; @@ -684,7 +660,7 @@ void save_file_set_cap_pos(s16 x, s16 y, s16 z) { } s32 save_file_get_cap_pos(Vec3s capPos) { - struct SaveFile *saveFile = &gSaveBuffer.files[gCurrSaveFileNum - 1][0]; + struct SaveFile *saveFile = &gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot]; s32 flags = save_file_get_flags(); if (saveFile->capLevel == gCurrLevelNum && saveFile->capArea == gCurrAreaIndex @@ -709,7 +685,7 @@ u16 save_file_get_sound_mode(void) { void save_file_move_cap_to_default_location(void) { if (save_file_get_flags() & SAVE_FLAG_CAP_ON_GROUND) { - switch (gSaveBuffer.files[gCurrSaveFileNum - 1][0].capLevel) { + switch (gSaveBuffer.files[gCurrSaveFileNum - 1][gSaveFileUsingBackupSlot].capLevel) { case LEVEL_SSL: save_file_set_flags(SAVE_FLAG_CAP_ON_KLEPTO); break; diff --git a/src/game/text_save.inc.h b/src/game/text_save.inc.h deleted file mode 100644 index a9ce6c2aa..000000000 --- a/src/game/text_save.inc.h +++ /dev/null @@ -1,334 +0,0 @@ -#include -#include -#include -#include "course_table.h" -#include "pc/ini.h" -#include "pc/platform.h" -#include "pc/fs/fs.h" - -#define FILENAME_FORMAT "%s/sm64_save_file_%d.sav" -#define NUM_COURSES 15 -#define NUM_BONUS_COURSES 10 -#define NUM_FLAGS 21 -#define NUM_CAP_ON 4 - -const char *sav_flags[NUM_FLAGS] = { - "file_exists", "wing_cap", "metal_cap", "vanish_cap", "key_1", "key_2", - "basement_door", "upstairs_door", "ddd_moved_back", "moat_drained", - "pps_door", "wf_door", "ccm_door", "jrb_door", "bitdw_door", - "bitfs_door", "", "", "", "", "50star_door" // 4 Cap flags are processed in their own section -}; - -const char *sav_courses[NUM_COURSES] = { - "bob", "wf", "jrb", "ccm", "bbh", "hmc", "lll", - "ssl", "ddd", "sl", "wdw", "ttm", "thi", "ttc", "rr" -}; - -const char *sav_bonus_courses[NUM_BONUS_COURSES] = { - "bitdw", "bitfs", "bits", "pss", "cotmc", - "totwc", "vcutm", "wmotr", "sa", "hub" // hub is Castle Grounds -}; - -const char *cap_on_types[NUM_CAP_ON] = { - "ground", "klepto", "ukiki", "mrblizzard" -}; - -const char *sound_modes[3] = { - "stereo", "mono", "headset" -}; - -/* Get current timestamp string */ -static void get_timestamp(char* buffer) { - time_t timer; - struct tm* tm_info; - - timer = time(NULL); - tm_info = localtime(&timer); - - strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info); -} - -/* Convert 'binary' integer to decimal integer */ -static u32 bin_to_int(u32 n) { - s32 dec = 0, i = 0, rem; - while (n != 0) { - rem = n % 10; - n /= 10; - dec += rem * (1 << i); - ++i; - } - return dec; -} - -/* Convert decimal integer to 'binary' integer */ -static u32 int_to_bin(u32 n) { - s32 bin = 0, rem, i = 1; - while (n != 0) { - rem = n % 2; - n /= 2; - bin += rem * i; - i *= 10; - } - return bin; -} - -/** - * Write SaveFile and MainMenuSaveData structs to a text-based savefile - */ -static s32 write_text_save(s32 fileIndex) { - FILE* file; - struct SaveFile *savedata; - struct MainMenuSaveData *menudata; - char filename[SYS_MAX_PATH] = { 0 }; - char value[64]; - u32 i, bit, flags, coins, stars, starFlags; - - if (snprintf(filename, sizeof(filename), FILENAME_FORMAT, fs_writepath, fileIndex) < 0) - return -1; - - file = fopen(filename, "wt"); - if (file == NULL) { - printf("Savefile '%s' not found!\n", filename); - return -1; - } else - printf("Saving updated progress to '%s'\n", filename); - - fprintf(file, "# Super Mario 64 save file\n"); - fprintf(file, "# Comment starts with #\n"); - fprintf(file, "# True = 1, False = 0\n"); - - get_timestamp(value); - fprintf(file, "# %s\n", value); - - menudata = &gSaveBuffer.menuData[0]; - fprintf(file, "\n[menu]\n"); - fprintf(file, "coin_score_age = %d\n", menudata->coinScoreAges[fileIndex]); - - if (menudata->soundMode == 0) { - fprintf(file, "sound_mode = %s\n", sound_modes[0]); // stereo - } - else if (menudata->soundMode == 3) { - fprintf(file, "sound_mode = %s\n", sound_modes[1]); // mono - } - else if (menudata->soundMode == 1) { - fprintf(file, "sound_mode = %s\n", sound_modes[2]); // headset - } - else { - printf("Undefined sound mode!"); - return -1; - } - - fprintf(file, "\n[flags]\n"); - for (i = 1; i < NUM_FLAGS; i++) { - if (strcmp(sav_flags[i], "")) { - flags = save_file_get_flags(); - flags = (flags & (1 << i)); // Get 'star' flag bit - flags = (flags) ? 1 : 0; - - fprintf(file, "%s = %d\n", sav_flags[i], flags); - } - } - - fprintf(file, "\n[courses]\n"); - for (i = 0; i < NUM_COURSES; i++) { - stars = save_file_get_star_flags(fileIndex, i); - coins = save_file_get_course_coin_score(fileIndex, i); - starFlags = int_to_bin(stars); // 63 -> 111111 - - fprintf(file, "%s = \"%d, %07d\"\n", sav_courses[i], coins, starFlags); - } - - fprintf(file, "\n[bonus]\n"); - for (i = 0; i < NUM_BONUS_COURSES; i++) { - char *format; - - if (i == NUM_BONUS_COURSES-1) { - // Process Castle Grounds - stars = save_file_get_star_flags(fileIndex, -1); - format = "%05d"; - } else if (i == 3) { - // Process Princess's Secret Slide - stars = save_file_get_star_flags(fileIndex, 18); - format = "%02d"; - } else { - // Process bonus courses - stars = save_file_get_star_flags(fileIndex, i+15); - format = "%d"; - } - - starFlags = int_to_bin(stars); - if (sprintf(value, format, starFlags) < 0) - return -1; - fprintf(file, "%s = %s\n", sav_bonus_courses[i], value); - } - - fprintf(file, "\n[cap]\n"); - for (i = 0; i < NUM_CAP_ON; i++) { - flags = save_file_get_flags(); - bit = (1 << (i+16)); // Determine current flag - flags = (flags & bit); // Get 'cap' flag bit - flags = (flags) ? 1 : 0; - if (flags) { - fprintf(file, "type = %s\n", cap_on_types[i]); - break; - } - } - - savedata = &gSaveBuffer.files[fileIndex][0]; - switch(savedata->capLevel) { - case COURSE_SSL: - fprintf(file, "level = %s\n", "ssl"); - break; - case COURSE_SL: - fprintf(file, "level = %s\n", "sl"); - break; - case COURSE_TTM: - fprintf(file, "level = %s\n", "ttm"); - break; - default: - break; - } - if (savedata->capLevel) { - fprintf(file, "area = %d\n", savedata->capArea); - } - - // Backup is nessecary for saving recent progress after gameover - bcopy(&gSaveBuffer.files[fileIndex][0], &gSaveBuffer.files[fileIndex][1], - sizeof(gSaveBuffer.files[fileIndex][1])); - - fclose(file); - return 1; -} - -/** - * Read gSaveBuffer data from a text-based savefile - */ -static s32 read_text_save(s32 fileIndex) { - char filename[SYS_MAX_PATH] = { 0 }; - const char *value; - ini_t *savedata; - - u32 i, flag, coins, stars, starFlags; - u32 capArea; - - if (snprintf(filename, sizeof(filename), FILENAME_FORMAT, fs_writepath, fileIndex) < 0) - return -1; - - savedata = ini_load(filename); - if (savedata == NULL) { - return -1; - } else { - printf("Loading savefile from '%s'\n", filename); - } - - ini_sget(savedata, "menu", "coin_score_age", "%d", - &gSaveBuffer.menuData[0].coinScoreAges[fileIndex]); - - value = ini_get(savedata, "menu", "sound_mode"); - if (value) { - if (strcmp(value, sound_modes[0]) == 0) { - gSaveBuffer.menuData[0].soundMode = 0; // stereo - } - else if (strcmp(value, sound_modes[1]) == 0) { - gSaveBuffer.menuData[0].soundMode = 3; // mono - } - else if (strcmp(value, sound_modes[2]) == 0) { - gSaveBuffer.menuData[0].soundMode = 1; // headset - } - } - else { - printf("Invalid 'menu:sound_mode' flag!\n"); - return -1; - } - - for (i = 1; i < NUM_FLAGS; i++) { - value = ini_get(savedata, "flags", sav_flags[i]); - if (value) { - flag = value[0] - '0'; // Flag should be 0 or 1 - if (flag) { - flag = 1 << i; // Flags defined in 'save_file' header - gSaveBuffer.files[fileIndex][0].flags |= flag; - } - } - } - - for (i = 0; i < NUM_COURSES; i++) { - value = ini_get(savedata, "courses", sav_courses[i]); - if (value) { - sscanf(value, "%d, %d", &coins, &stars); - starFlags = bin_to_int(stars); // 111111 -> 63 - - save_file_set_star_flags(fileIndex, i, starFlags); - gSaveBuffer.files[fileIndex][0].courseCoinScores[i] = coins; - } - } - - for (i = 0; i < NUM_BONUS_COURSES; i++) { - value = ini_get(savedata, "bonus", sav_bonus_courses[i]); - if (value) { - sscanf(value, "%d", &stars); - starFlags = bin_to_int(stars); - - if (strlen(value) == 5) { - // Process Castle Grounds - save_file_set_star_flags(fileIndex, -1, starFlags); - } else if (strlen(value) == 2) { - // Process Princess's Secret Slide - save_file_set_star_flags(fileIndex, 18, starFlags); - } else { - // Process bonus courses - save_file_set_star_flags(fileIndex, i+15, starFlags); - } - } - } - - for (i = 0; i < NUM_CAP_ON; i++) { - value = ini_get(savedata, "cap", "type"); - if (value) { - if (!strcmp(value, cap_on_types[i])) { - flag = (1 << (16 + i)); - gSaveBuffer.files[fileIndex][0].flags |= flag; - break; - } - } - } - - value = ini_get(savedata, "cap", "level"); - if (value) { - if (strcmp(value, "ssl") == 0) { - gSaveBuffer.files[fileIndex][0].capLevel = COURSE_SSL; // ssl - } - else if (strcmp(value, "sl") == 0) { - gSaveBuffer.files[fileIndex][0].capLevel = COURSE_SL; // sl - } - else if (strcmp(value, "ttm") == 0) { - gSaveBuffer.files[fileIndex][0].capLevel = COURSE_TTM; // ttm - } - else { - printf("Invalid 'cap:level' flag!\n"); - return -1; - } - } - - value = ini_get(savedata, "cap", "area"); - if (value) { - sscanf(value, "%d", &capArea); - if (capArea > 1 && capArea < 2) { - printf("Invalid 'cap:area' flag: %d!\n", capArea); - return -1; - } - else { - gSaveBuffer.files[fileIndex][0].capArea = capArea; - } - } - - // Good, file exists for gSaveBuffer - gSaveBuffer.files[fileIndex][0].flags |= SAVE_FLAG_FILE_EXISTS; - - // Backup is nessecary for saving recent progress after gameover - bcopy(&gSaveBuffer.files[fileIndex][0], &gSaveBuffer.files[fileIndex][1], - sizeof(gSaveBuffer.files[fileIndex][1])); - - ini_free(savedata); - return 0; -} diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 39970956d..fcd938b2f 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -244,6 +244,9 @@ char gSmluaConstants[] = "" " if flags == nil then flags = 0 end\n" " return (bank << 28) | (soundID << 16) | (priority << 8) | flags | SOUND_STATUS_WAITING\n" "end\n" +"-------------\n" +"-- courses --\n" +"-------------\n" "--- @type integer\n" "COURSE_NONE = 0\n" "--- @type integer\n" @@ -296,6 +299,14 @@ char gSmluaConstants[] = "" "COURSE_SA = 24\n" "--- @type integer\n" "COURSE_CAKE_END = 25\n" +"--- @type integer\n" +"COURSE_END = 26\n" +"--- @type integer\n" +"COURSE_MAX = 25\n" +"--- @type integer\n" +"COURSE_COUNT = 25\n" +"--- @type integer\n" +"COURSE_MIN = 1\n" "id_bhv1Up = 0\n" "id_bhv1upJumpOnApproach = 1\n" "id_bhv1upRunningAway = 2\n" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index d358f4a80..be9a12710 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -14771,6 +14771,17 @@ int smlua_func_movtexqc_register(lua_State* L) { return 1; } +int smlua_func_save_file_set_using_backup_slot(lua_State* L) { + if(!smlua_functions_valid_param_count(L, 1)) { return 0; } + + bool usingBackupSlot = smlua_to_boolean(L, 1); + if (!gSmLuaConvertSuccess) { return 0; } + + save_file_set_using_backup_slot(usingBackupSlot); + + return 1; +} + int smlua_func_set_environment_region(lua_State* L) { if(!smlua_functions_valid_param_count(L, 2)) { return 0; } @@ -16925,6 +16936,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "hud_hide", smlua_func_hud_hide); smlua_bind_function(L, "hud_show", smlua_func_hud_show); smlua_bind_function(L, "movtexqc_register", smlua_func_movtexqc_register); + smlua_bind_function(L, "save_file_set_using_backup_slot", smlua_func_save_file_set_using_backup_slot); smlua_bind_function(L, "set_environment_region", smlua_func_set_environment_region); smlua_bind_function(L, "warp_exit_level", smlua_func_warp_exit_level); smlua_bind_function(L, "warp_restart_level", smlua_func_warp_restart_level); diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index 6b3f55edb..7173cc4a5 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -87,6 +87,11 @@ s16 get_current_save_file_num(void) { return gCurrSaveFileNum; } +void save_file_set_using_backup_slot(bool usingBackupSlot) { + extern u8 gSaveFileUsingBackupSlot; + gSaveFileUsingBackupSlot = usingBackupSlot ? 1 : 0; +} + /// void movtexqc_register(const char* name, s16 level, s16 area, s16 type) { diff --git a/src/pc/lua/utils/smlua_misc_utils.h b/src/pc/lua/utils/smlua_misc_utils.h index c1fc65a98..d72f349f5 100644 --- a/src/pc/lua/utils/smlua_misc_utils.h +++ b/src/pc/lua/utils/smlua_misc_utils.h @@ -23,6 +23,7 @@ f32 get_hand_foot_pos_y(struct MarioState* m, u8 index); f32 get_hand_foot_pos_z(struct MarioState* m, u8 index); s16 get_current_save_file_num(void); +void save_file_set_using_backup_slot(bool usingBackupSlot); void movtexqc_register(const char* name, s16 level, s16 area, s16 type); f32 get_environment_region(u8 index); diff --git a/src/pc/network/network.c b/src/pc/network/network.c index f6ad16ecf..d4412299f 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -109,6 +109,9 @@ bool network_init(enum NetworkType inNetworkType) { gNetworkType = inNetworkType; if (gNetworkType == NT_SERVER) { + extern s16 gCurrSaveFileNum; + gCurrSaveFileNum = configHostSaveSlot; + mods_activate(&gLocalMods); smlua_init(); diff --git a/src/pc/network/packets/packet_collect_star.c b/src/pc/network/packets/packet_collect_star.c index 0ac3047d2..a0fc2c45b 100644 --- a/src/pc/network/packets/packet_collect_star.c +++ b/src/pc/network/packets/packet_collect_star.c @@ -12,6 +12,7 @@ extern s16 gCurrSaveFileNum; extern s16 gCurrCourseNum; +extern u8 gSaveFileUsingBackupSlot; static f32 dist_to_pos(struct Object* o, f32* pos) { f32 x = o->oPosX - pos[0]; x *= x; @@ -58,6 +59,7 @@ void network_send_collect_star(struct Object* o, s16 coinScore, s16 starIndex) { packet_write(&p, &behaviorId, sizeof(u32)); packet_write(&p, &coinScore, sizeof(s16)); packet_write(&p, &starIndex, sizeof(s16)); + packet_write(&p, &gSaveFileUsingBackupSlot, sizeof(u8)); network_send(&p); } @@ -71,6 +73,7 @@ void network_receive_collect_star(struct Packet* p) { s16 lastStarActNum = gCurrActStarNum; s16 lastLevelNum = gCurrLevelNum; s16 lastAreaIndex = gCurrAreaIndex; + u8 lastBackupSlot = gSaveFileUsingBackupSlot; packet_read(p, &gCurrSaveFileNum, sizeof(s16)); packet_read(p, &gCurrCourseNum, sizeof(s16)); @@ -81,16 +84,13 @@ void network_receive_collect_star(struct Packet* p) { packet_read(p, &behaviorId, sizeof(u32)); packet_read(p, &coinScore, sizeof(s16)); packet_read(p, &starIndex, sizeof(s16)); + packet_read(p, &gSaveFileUsingBackupSlot, sizeof(u8)); + if (gSaveFileUsingBackupSlot != 0) { gSaveFileUsingBackupSlot = 1; } const void* behavior = get_behavior_from_id(behaviorId); save_file_collect_star_or_key(coinScore, starIndex, 1); - s32 numStars = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1); - for (s32 i = 0; i < MAX_PLAYERS; i++) { - gMarioStates[i].numStars = numStars; - } - struct NetworkPlayer* np = gNetworkPlayerLocal; bool levelAreaMismatch = ((np == NULL) || np->currCourseNum != gCurrCourseNum @@ -98,11 +98,17 @@ void network_receive_collect_star(struct Packet* p) { || np->currLevelNum != gCurrLevelNum || np->currAreaIndex != gCurrAreaIndex); - gCurrSaveFileNum = lastSaveFileNum; - gCurrCourseNum = lastCourseNum; - gCurrActStarNum = lastStarActNum; - gCurrLevelNum = lastLevelNum; - gCurrAreaIndex = lastAreaIndex; + gCurrSaveFileNum = lastSaveFileNum; + gCurrCourseNum = lastCourseNum; + gCurrActStarNum = lastStarActNum; + gCurrLevelNum = lastLevelNum; + gCurrAreaIndex = lastAreaIndex; + gSaveFileUsingBackupSlot = lastBackupSlot; + + s32 numStars = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1); + for (s32 i = 0; i < MAX_PLAYERS; i++) { + gMarioStates[i].numStars = numStars; + } if (!levelAreaMismatch) { struct Object* star = find_nearest_star(behavior, pos, 500); diff --git a/src/pc/network/packets/packet_save_file.c b/src/pc/network/packets/packet_save_file.c index 394c56eff..36c94d5de 100644 --- a/src/pc/network/packets/packet_save_file.c +++ b/src/pc/network/packets/packet_save_file.c @@ -3,18 +3,28 @@ #include "game/save_file.h" #include "pc/debuglog.h" +extern u8 gSaveFileUsingBackupSlot; + void network_send_save_file(s32 fileIndex) { if (gNetworkPlayerServer == NULL) { return; } SOFT_ASSERT(gNetworkType == NT_CLIENT); struct Packet p = { 0 }; packet_init(&p, PACKET_SAVE_FILE, true, PLMT_NONE); - packet_write(&p, &fileIndex, sizeof(s32)); + packet_write(&p, &fileIndex, sizeof(s32)); + packet_write(&p, &gSaveFileUsingBackupSlot, sizeof(u8)); network_send_to(gNetworkPlayerServer->localIndex, &p); } void network_receive_save_file(struct Packet* p) { if (gNetworkType != NT_SERVER) { return; } s32 fileIndex = 0; + u8 lastBackupSlot = gSaveFileUsingBackupSlot; packet_read(p, &fileIndex, sizeof(s32)); + packet_read(p, &gSaveFileUsingBackupSlot, sizeof(u8)); + + if (gSaveFileUsingBackupSlot != 0) { gSaveFileUsingBackupSlot = 1; } + save_file_do_save(fileIndex, FALSE); + + gSaveFileUsingBackupSlot = lastBackupSlot; } diff --git a/src/pc/network/packets/packet_save_set_flag.c b/src/pc/network/packets/packet_save_set_flag.c index 2384cf7a5..a1a67d538 100644 --- a/src/pc/network/packets/packet_save_set_flag.c +++ b/src/pc/network/packets/packet_save_set_flag.c @@ -4,13 +4,16 @@ #include "buffers/buffers.h" #include "pc/debuglog.h" +extern u8 gSaveFileUsingBackupSlot; + void network_send_save_set_flag(s32 fileIndex, s32 courseIndex, u8 courseStars, u32 flags) { struct Packet p = { 0 }; packet_init(&p, PACKET_SAVE_SET_FLAG, true, PLMT_NONE); - packet_write(&p, &fileIndex, sizeof(s32)); - packet_write(&p, &courseIndex, sizeof(s32)); - packet_write(&p, &courseStars, sizeof(u8)); - packet_write(&p, &flags, sizeof(u32)); + packet_write(&p, &fileIndex, sizeof(s32)); + packet_write(&p, &courseIndex, sizeof(s32)); + packet_write(&p, &courseStars, sizeof(u8)); + packet_write(&p, &flags, sizeof(u32)); + packet_write(&p, &gSaveFileUsingBackupSlot, sizeof(u8)); network_send(&p); } @@ -19,10 +22,12 @@ void network_receive_save_set_flag(struct Packet* p) { s32 courseIndex; u8 courseStars; u32 flags; + u8 backupSlot; packet_read(p, &fileIndex, sizeof(s32)); packet_read(p, &courseIndex, sizeof(s32)); packet_read(p, &courseStars, sizeof(u8)); packet_read(p, &flags, sizeof(u32)); + packet_read(p, &backupSlot, sizeof(u8)); if (fileIndex >= NUM_SAVE_FILES) { LOG_ERROR("Invalid fileIndex: %d", fileIndex); @@ -34,7 +39,12 @@ void network_receive_save_set_flag(struct Packet* p) { return; } - gSaveBuffer.files[fileIndex][0].courseStars[courseIndex] |= courseStars; - gSaveBuffer.files[fileIndex][0].flags |= flags; + if (backupSlot > 1) { + LOG_ERROR("Invalid backupSlot: %d", backupSlot); + return; + } + + gSaveBuffer.files[fileIndex][backupSlot].courseStars[courseIndex] |= courseStars; + gSaveBuffer.files[fileIndex][backupSlot].flags |= flags; gSaveFileModified = TRUE; }