diff --git a/source/duke3d/src/events_defs.h b/source/duke3d/src/events_defs.h index d710ae29f..636b69d81 100644 --- a/source/duke3d/src/events_defs.h +++ b/source/duke3d/src/events_defs.h @@ -158,6 +158,7 @@ enum GameEvent_t { EVENT_DAMAGECEILING, EVENT_DISPLAYROOMSCAMERATILE, EVENT_RESETGOTPICS, + EVENT_VALIDATESTART, #ifdef LUNATIC EVENT_ANIMATEALLSPRITES, #endif diff --git a/source/duke3d/src/gamedef.cpp b/source/duke3d/src/gamedef.cpp index 57561d997..f007a717c 100644 --- a/source/duke3d/src/gamedef.cpp +++ b/source/duke3d/src/gamedef.cpp @@ -989,6 +989,7 @@ const char *EventNames[MAXEVENTS] = "EVENT_DAMAGECEILING", "EVENT_DISPLAYROOMSCAMERATILE", "EVENT_RESETGOTPICS", + "EVENT_VALIDATESTART", #ifdef LUNATIC "EVENT_ANIMATEALLSPRITES", #endif diff --git a/source/duke3d/src/menus.cpp b/source/duke3d/src/menus.cpp index 38eef4106..b32f388f7 100644 --- a/source/duke3d/src/menus.cpp +++ b/source/duke3d/src/menus.cpp @@ -77,9 +77,13 @@ static void mgametext(int32_t x, int32_t y, char const * t) G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1); } +static vec2_t mgametextcenterat(int32_t x, int32_t y, char const * t, int32_t f = 0) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f|TEXT_XCENTER, 0, 0, xdim-1, ydim-1); +} static vec2_t mgametextcenter(int32_t x, int32_t y, char const * t, int32_t f = 0) { - return G_ScreenText(MF_Bluefont.tilenum, (MENU_MARGIN_CENTER<<16) + x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f|TEXT_XCENTER, 0, 0, xdim-1, ydim-1); + return mgametextcenterat((MENU_MARGIN_CENTER<<16) + x, y, t, f); } #define mminitext(x,y,t,p) minitext_(x, y, t, 0, p, 2|8|16|ROTATESPRITE_FULL16) @@ -2224,22 +2228,24 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin) if (msv.brief.isValid()) { if (waloff[TILE_LOADSHOT]) - rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536>>1,512,TILE_LOADSHOT,-32,0,4+10+64); + rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536>>1,512,TILE_LOADSHOT, msv.isOldVer?16:-32, 0,4+10+64); if (msv.isOldVer) { - menutext_centeralign(origin.x + (101<<16), origin.y + (97<<16), "Previous\nVersion"); + mgametextcenterat(origin.x + (101<<16), origin.y + (50<<16), + msv.brief.isExt ? "Previous Version,\nSequence Point Available" : "Previous Version,\nUnable to Load"); #ifndef EDUKE32_SIMPLE_MENU Bsprintf(tempbuf,"Saved: %d.%d.%d.%u %d-bit", savehead.majorver, savehead.minorver, savehead.bytever, savehead.userbytever, 8*savehead.getPtrSize()); - mgametext(origin.x + (31<<16), origin.y + (104<<16), tempbuf); + mgametext(origin.x + (25<<16), origin.y + (124<<16), tempbuf); Bsprintf(tempbuf,"Our: %d.%d.%d.%u %d-bit", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, ud.userbytever, (int32_t)(8*sizeof(intptr_t))); - mgametext(origin.x + ((31+16)<<16), origin.y + (114<<16), tempbuf); + mgametext(origin.x + ((25+16)<<16), origin.y + (134<<16), tempbuf); #endif - break; + if (msv.isUnreadable) + break; } if (savehead.numplayers > 1) @@ -2282,25 +2288,26 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin) rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536L>>1,512,TILE_SAVESHOT,-32,0,4+10+64); else if (0 < M_SAVE.currentEntry && M_SAVE.currentEntry <= (int32_t)g_nummenusaves) { - if (g_menusaves[M_SAVE.currentEntry-1].brief.isValid()) + menusave_t & msv = g_menusaves[M_SAVE.currentEntry-1]; + + if (msv.brief.isValid()) { if (waloff[TILE_LOADSHOT]) - rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536L>>1,512,TILE_LOADSHOT,-32,0,4+10+64); + rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536>>1,512,TILE_LOADSHOT, msv.isOldVer?16:-32, 0,4+10+64); - if (g_menusaves[M_SAVE.currentEntry-1].isOldVer) + if (msv.isOldVer) { - menutext_centeralign(origin.x + (101<<16), origin.y + (97<<16), "Previous\nVersion"); + mgametextcenterat(origin.x + (101<<16), origin.y + (50<<16), + msv.brief.isExt ? "Previous Version,\nSequence Point Available" : "Previous Version,\nUnable to Load"); #ifndef EDUKE32_SIMPLE_MENU Bsprintf(tempbuf,"Saved: %d.%d.%d.%u %d-bit", savehead.majorver, savehead.minorver, savehead.bytever, savehead.userbytever, 8*savehead.getPtrSize()); - mgametext(origin.x + (31<<16), origin.y + (104<<16), tempbuf); + mgametext(origin.x + (25<<16), origin.y + (124<<16), tempbuf); Bsprintf(tempbuf,"Our: %d.%d.%d.%u %d-bit", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, ud.userbytever, (int32_t)(8*sizeof(intptr_t))); - mgametext(origin.x + ((31+16)<<16), origin.y + (114<<16), tempbuf); + mgametext(origin.x + ((25+16)<<16), origin.y + (134<<16), tempbuf); #endif - - break; } } } diff --git a/source/duke3d/src/player.cpp b/source/duke3d/src/player.cpp index 1c7561788..71cc217ad 100644 --- a/source/duke3d/src/player.cpp +++ b/source/duke3d/src/player.cpp @@ -5640,7 +5640,7 @@ HORIZONLY:; #define SJSON_IMPLEMENT #include "sjson.h" -int portableBackupSave(const char * path) +int portableBackupSave(const char * path, int volume, int level) { if (!FURY) return 0; @@ -5662,8 +5662,8 @@ int portableBackupSave(const char * path) sjson_node * root = sjson_mkobject(ctx); // sjson_put_string(ctx, root, "map", currentboardfilename); - sjson_put_int(ctx, root, "volume", ud.last_stateless_volume); - sjson_put_int(ctx, root, "level", ud.last_stateless_level); + sjson_put_int(ctx, root, "volume", volume); + sjson_put_int(ctx, root, "level", level); sjson_put_int(ctx, root, "skill", ud.player_skill); { diff --git a/source/duke3d/src/player.h b/source/duke3d/src/player.h index a850f04ee..72d52ff06 100644 --- a/source/duke3d/src/player.h +++ b/source/duke3d/src/player.h @@ -426,6 +426,6 @@ static inline int P_Get(int32_t spriteNum) { return P_GetP((uspriteptr_t)&sprite } #endif -extern int portableBackupSave(const char *); +extern int portableBackupSave(const char *, int, int); #endif diff --git a/source/duke3d/src/savegame.cpp b/source/duke3d/src/savegame.cpp index 9e8915874..0d8f85d79 100644 --- a/source/duke3d/src/savegame.cpp +++ b/source/duke3d/src/savegame.cpp @@ -173,11 +173,11 @@ static void ReadSaveGameHeaders_CACHE1D(CACHE1D_FIND_REC *f) { char extfn[BMAX_PATH]; snprintf(extfn, ARRAY_SIZE(extfn), "%s.ext", fn); - buildvfs_kfd fil = kopen4loadfrommod(extfn, 0); - if (fil != buildvfs_kfd_invalid) + buildvfs_kfd extfil = kopen4loadfrommod(extfn, 0); + if (extfil != buildvfs_kfd_invalid) { msv.brief.isExt = 1; - kclose(fil); + kclose(extfil); } } } @@ -325,6 +325,17 @@ int32_t G_LoadSaveHeaderNew(char const *fn, savehead_t *saveh) OSD_Printf("G_LoadSaveHeaderNew(): failed reading screenshot in \"%s\"\n", fn); goto corrupt; } + +#if 0 + // debug code to dump the screenshot + char scrbuf[BMAX_PATH]; + if (G_ModDirSnprintf(scrbuf, sizeof(scrbuf), "%s.raw", fn) == 0) + { + buildvfs_FILE scrfil = buildvfs_fopen_write(scrbuf); + buildvfs_fwrite((char *)waloff[TILE_LOADSHOT], 320, 200, scrfil); + buildvfs_fclose(scrfil); + } +#endif } else { @@ -353,26 +364,46 @@ int32_t G_LoadPlayer(savebrief_t & sv) { if (sv.isExt) { + int volume = -1; + int level = -1; + int skill = -1; + + buildvfs_kfd const fil = kopen4loadfrommod(sv.path, 0); + + if (fil != buildvfs_kfd_invalid) + { + savehead_t h; + int status = sv_loadheader(fil, 0, &h); + if (status >= 0) + { + volume = h.volnum; + level = h.levnum; + skill = h.skill; + } + + kclose(fil); + } + char extfn[BMAX_PATH]; snprintf(extfn, ARRAY_SIZE(extfn), "%s.ext", sv.path); - buildvfs_kfd fil = kopen4loadfrommod(extfn, 0); - if (fil == buildvfs_kfd_invalid) + buildvfs_kfd extfil = kopen4loadfrommod(extfn, 0); + if (extfil == buildvfs_kfd_invalid) { return -1; } - int32_t len = kfilelength(fil); + int32_t len = kfilelength(extfil); auto text = (char *)Xmalloc(len+1); text[len] = '\0'; - if (kread_and_test(fil, text, len)) + if (kread_and_test(extfil, text, len)) { - kclose(fil); + kclose(extfil); Xfree(text); return -1; } - kclose(fil); + kclose(extfil); sjson_context * ctx = sjson_create_context(0, 0, NULL); @@ -380,9 +411,12 @@ int32_t G_LoadPlayer(savebrief_t & sv) Xfree(text); - int volume = sjson_get_int(root, "volume", -1); - int level = sjson_get_int(root, "level", -1); - int skill = sjson_get_int(root, "skill", -1); + if (volume == -1) + volume = sjson_get_int(root, "volume", volume); + if (level == -1) + level = sjson_get_int(root, "level", level); + if (skill == -1) + skill = sjson_get_int(root, "skill", skill); if (volume == -1 || level == -1 || skill == -1) { @@ -402,6 +436,12 @@ int32_t G_LoadPlayer(savebrief_t & sv) return 1; } + + ud.returnvar[0] = level; + volume = VM_OnEventWithReturn(EVENT_VALIDATESTART, g_player[myconnectindex].ps->i, myconnectindex, volume); + level = ud.returnvar[0]; + + { // CODEDUP from non-isExt branch, with simplifying assumptions @@ -782,7 +822,7 @@ int32_t G_SavePlayer(savebrief_t & sv, bool isAutoSave) VM_OnEvent(EVENT_SAVEGAME, g_player[screenpeek].ps->i, screenpeek); - portableBackupSave(sv.path); + portableBackupSave(sv.path, ud.last_stateless_volume, ud.last_stateless_level); // SAVE! sv_saveandmakesnapshot(fil, sv.name, 0, 0, 0, 0, isAutoSave);