From 0e7e7ba3b64e6bccfcca85d4120f2f60f1fe05c3 Mon Sep 17 00:00:00 2001 From: James Haley Date: Thu, 10 Feb 2011 20:45:00 +0000 Subject: Restarted work on hub save code. Brought in multiple filepath handling routines from Eternity. Subversion-branch: /branches/strife-branch Subversion-revision: 2252 --- src/strife/d_main.c | 51 +------- src/strife/doomdef.h | 4 +- src/strife/g_game.c | 47 ++++---- src/strife/m_saves.c | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/strife/m_saves.h | 8 ++ src/strife/p_enemy.c | 4 +- src/strife/s_sound.c | 4 +- 7 files changed, 358 insertions(+), 83 deletions(-) diff --git a/src/strife/d_main.c b/src/strife/d_main.c index 12c64016..8ffcc2ad 100644 --- a/src/strife/d_main.c +++ b/src/strife/d_main.c @@ -58,6 +58,7 @@ #include "m_controls.h" #include "m_misc.h" #include "m_menu.h" +#include "m_saves.h" // haleyjd [STRIFE] #include "p_saveg.h" #include "i_endoom.h" @@ -80,7 +81,6 @@ #include "p_setup.h" #include "r_local.h" - #include "d_main.h" // @@ -793,53 +793,6 @@ static char *GetGameName(char *gamename) return gamename; } -// -// haleyjd: STRIFE-FIXME: Temporary? -// Code borrowed from Eternity, and modified to return separator char -// -char M_GetFilePath(const char *fn, char *dest, size_t len) -{ - boolean found_slash = false; - char *p; - char sepchar = '\0'; - - memset(dest, 0, len); - - p = dest + len - 1; - - strncpy(dest, fn, len); - - while(p >= dest) - { - if(*p == '/' || *p == '\\') - { - sepchar = *p; - found_slash = true; // mark that the path ended with a slash - *p = '\0'; - break; - } - *p = '\0'; - p--; - } - - // haleyjd: in the case that no slash was ever found, yet the - // path string is empty, we are dealing with a file local to the - // working directory. The proper path to return for such a string is - // not "", but ".", since the format strings add a slash now. When - // the string is empty but a slash WAS found, we really do want to - // return the empty string, since the path is relative to the root. - if(!found_slash && *dest == '\0') - *dest = '.'; - - // if a separator is not found, default to forward, because Windows - // supports that too. - if(sepchar == '\0') - sepchar = '/'; - - return sepchar; -} - - // // Find out what version of Doom is playing. // @@ -978,6 +931,8 @@ static void SetSaveGameDir(char *iwad_filename) basefile, DIR_SEPARATOR); M_MakeDirectory(savegamedir); + + // haleyjd 20110210: Create Strife hub save folders } // Check if the IWAD file is the Chex Quest IWAD. diff --git a/src/strife/doomdef.h b/src/strife/doomdef.h index 52cfc587..459c43dd 100644 --- a/src/strife/doomdef.h +++ b/src/strife/doomdef.h @@ -246,8 +246,8 @@ enum QF_QUEST1 = (1 << tk_quest1), // Obtained Beldin's ring QF_QUEST2 = (1 << tk_quest2), // Stole the Chalice QF_QUEST3 = (1 << tk_quest3), // Permission to visit Irale (visited Macil) - QF_QUEST4 = (1 << tk_quest4), - QF_QUEST5 = (1 << tk_quest5), + QF_QUEST4 = (1 << tk_quest4), // Accepted Gov. Mourel's "messy" chore + QF_QUEST5 = (1 << tk_quest5), // Accepted Gov. Mourel's "bloody" chore QF_QUEST6 = (1 << tk_quest6), // Destroyed the Power Coupling QF_QUEST7 = (1 << tk_quest7), // Killed Blue Acolytes ("Scanning Team") QF_QUEST8 = (1 << tk_quest8), diff --git a/src/strife/g_game.c b/src/strife/g_game.c index 225891bd..257becef 100644 --- a/src/strife/g_game.c +++ b/src/strife/g_game.c @@ -23,8 +23,6 @@ // //----------------------------------------------------------------------------- - - #include #include #include @@ -41,6 +39,7 @@ #include "m_controls.h" #include "m_misc.h" #include "m_menu.h" +#include "m_saves.h" // STRIFE #include "m_random.h" #include "i_system.h" #include "i_timer.h" @@ -53,7 +52,6 @@ #include "hu_stuff.h" #include "st_stuff.h" #include "am_map.h" -#include "m_misc.h" // STRIFE // Needs access to LFB. #include "v_video.h" @@ -117,17 +115,17 @@ angle_t riftangle; // player angle saved during exit int timelimit; boolean paused; -boolean sendpause; // send a pause event next tic -boolean sendsave; // send a save event next tic +boolean sendpause; // send a pause event next tic +boolean sendsave; // send a save event next tic boolean usergame; // ok to save / end game boolean timingdemo; // if true, exit with report on completion boolean nodrawers; // for comparative timing purposes -int starttime; // for comparative timing purposes +int starttime; // for comparative timing purposes boolean viewactive; -boolean deathmatch; // only if started as net death +boolean deathmatch; // only if started as net death boolean netgame; // only true if packets are broadcast boolean playeringame[MAXPLAYERS]; player_t players[MAXPLAYERS]; @@ -149,15 +147,15 @@ boolean netdemo; byte* demobuffer; byte* demo_p; byte* demoend; -boolean singledemo; // quit after playing a demo from cmdline +boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start boolean testcontrols = false; // Invoked by setup to test controls -wbstartstruct_t wminfo; // parms for world map / intermission +wbstartstruct_t wminfo; // parms for world map / intermission -byte consistancy[MAXPLAYERS][BACKUPTICS]; +byte consistancy[MAXPLAYERS][BACKUPTICS]; #define MAXPLMOVE (forwardmove[1]) @@ -1341,23 +1339,23 @@ G_CheckSpot void G_DeathMatchSpawnPlayer (int playernum) { int i,j; - int selections; - + int selections; + selections = deathmatch_p - deathmatchstarts; if (selections < 4) - I_Error ("Only %i deathmatch spots, 4 required", selections); - + I_Error ("Only %i deathmatch spots, 4 required", selections); + for (j=0 ; j<20 ; j++) { - i = P_Random() % selections; - if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) - { - deathmatchstarts[i].type = playernum+1; - P_SpawnPlayer (&deathmatchstarts[i]); - return; - } + i = P_Random() % selections; + if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) + { + deathmatchstarts[i].type = playernum+1; + P_SpawnPlayer (&deathmatchstarts[i]); + return; + } } - + // no good spot, so the player will probably get stuck P_SpawnPlayer (&playerstarts[playernum]); } @@ -1819,14 +1817,15 @@ boolean G_WriteSaveName() dword_86280 = eax0; - // STRIFE-TODO: yeah good luck making THIS work on Linux. - if(M_CheckParm(DEH_String("-cdrom"))) +#ifdef _WIN32 + if(M_CheckParm("-cdrom") > 0) { sprintf(savepath2, "c:\\strife.cd\\strfsav%d.ssg\\", 6); v5 = dword_86280; dirstr = "c:\\strife.cd\\strfsav%d.ssg\\"; } else +#endif { sprintf(savepath2, "strfsav%d.ssg\\", 6); v5 = dword_86280; diff --git a/src/strife/m_saves.c b/src/strife/m_saves.c index f845598e..6b99a7a8 100644 --- a/src/strife/m_saves.c +++ b/src/strife/m_saves.c @@ -37,14 +37,28 @@ #else #error Need an include for dirent.h! #endif +#include +#include +#include #include "z_zone.h" #include "i_system.h" #include "d_player.h" #include "deh_str.h" +#include "doomstat.h" #include "m_misc.h" +#include "m_saves.h" #include "p_dialog.h" +// +// File Paths +// +// Strife maintains multiple file paths related to savegames. +// +char *savepath; +char *savepath2; +char *loadpath; + // // ClearTmp // @@ -52,6 +66,32 @@ // void ClearTmp(void) { + DIR *sp2dir = NULL; + struct dirent *f = NULL; + + if(savepath2 == NULL) + I_Error("you fucked up savedir man!"); + + if(!(sp2dir = opendir(savepath2))) + I_Error("ClearTmp: Couldn't open dir %s", savepath2); + + while((f = readdir(sp2dir))) + { + char *filepath = NULL; + + // haleyjd: skip "." and ".." without assuming they're the + // first two entries like the original code did. + if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, "..")) + continue; + + // haleyjd: use M_SafeFilePath, not sprintf + filepath = M_SafeFilePath(savepath2, f->d_name); + remove(filepath); + + Z_Free(filepath); + } + + closedir(sp2dir); } // @@ -61,16 +101,50 @@ void ClearTmp(void) // void ClearSlot(void) { + if(savepath == NULL) + I_Error("userdir is fucked up man!"); + + // STRIFE-TODO } // // FromCurr // -// Moving files from one directory to another... -// STRIFE-TODO: figure out exactly what this is for. +// Copying files from savepath2 to savepath // void FromCurr(void) { + DIR *sp2dir = NULL; + struct dirent *f = NULL; + + if(!(sp2dir = opendir(savepath2))) + I_Error("FromCurr: Couldn't open dir %s", savepath2); + + while((f = readdir(sp2dir))) + { + byte *filebuffer = NULL; + int filelen = 0; + char *srcfilename = NULL; + char *dstfilename = NULL; + + // haleyjd: skip "." and ".." without assuming they're the + // first two entries like the original code did. + if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, "..")) + continue; + + // haleyjd: use M_SafeFilePath, NOT sprintf. + srcfilename = M_SafeFilePath(savepath2, f->d_name); + dstfilename = M_SafeFilePath(savepath, f->d_name); + + filelen = M_ReadFile(srcfilename, &filebuffer); + M_WriteFile(dstfilename, filebuffer, filelen); + + Z_Free(filebuffer); + Z_Free(srcfilename); + Z_Free(dstfilename); + } + + closedir(sp2dir); } // @@ -80,6 +154,7 @@ void FromCurr(void) // void sub_1B2F4(void) { + // STRIFE-TODO } // @@ -89,6 +164,27 @@ void sub_1B2F4(void) // void M_SaveMoveMapToHere(void) { + char *mapsave = NULL; + char *heresave = NULL; + char tmpnum[33]; + + // haleyjd: no itoa available... + memset(tmpnum, 0, sizeof(tmpnum)); + sprintf(tmpnum, "%d", gamemap); + + // haleyjd: use M_SafeFilePath, not sprintf + mapsave = M_SafeFilePath(savepath, tmpnum); + heresave = M_SafeFilePath(savepath, "here"); + + // haleyjd: use M_FileExists, not access + if(M_FileExists(mapsave)) + { + remove(heresave); + rename(mapsave, heresave); + } + + Z_Free(mapsave); + Z_Free(heresave); } // @@ -98,6 +194,25 @@ void M_SaveMoveMapToHere(void) // void M_SaveMoveHereToMap(void) { + char *mapsave = NULL; + char *heresave = NULL; + char tmpnum[33]; + + // haleyjd: no itoa available... + memset(tmpnum, 0, sizeof(tmpnum)); + sprintf(tmpnum, "%d", gamemap); + + mapsave = M_SafeFilePath(savepath2, tmpnum); + heresave = M_SafeFilePath(savepath2, "here"); + + if(M_FileExists(heresave)) + { + remove(mapsave); + rename(heresave, mapsave); + } + + Z_Free(mapsave); + Z_Free(heresave); } // @@ -107,10 +222,15 @@ void M_SaveMoveHereToMap(void) // boolean M_SaveMisObj(const char *path) { - char destpath[100]; // WARNING: not large enough for modern file paths! + boolean result; + char *destpath = NULL; + + // haleyjd 20110210: use M_SafeFilePath, not sprintf + destpath = M_SafeFilePath(path, "mis_obj"); + result = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN); - DEH_snprintf(destpath, sizeof(destpath), "%smis_obj", path); - return M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN); + Z_Free(destpath); + return result; } // @@ -120,6 +240,199 @@ boolean M_SaveMisObj(const char *path) // void M_ReadMisObj(void) { + FILE *f = NULL; + char *srcpath = NULL; + + // haleyjd: use M_SafeFilePath, not sprintf + srcpath = M_SafeFilePath(savepath2, "mis_obj"); + + if((f = fopen(srcpath, "rb"))) + { + fread(mission_objective, 1, 300, f); + fclose(f); + } + + Z_Free(srcpath); +} + +//============================================================================= +// +// Original Routines +// +// haleyjd - None of the below code is derived from Strife itself, but has been +// adapted or created in order to provide secure, portable filepath handling +// for the purposes of savegame support. This is partially needed to allow for +// differences in Choco due to it being multiplatform. The rest exists because +// I cannot stand programming in an impoverished ANSI C environment that +// calls sprintf on fixed-size buffers. :P +// + +// +// M_Calloc +// +// haleyjd 20110210 - original routine +// Because Choco doesn't have Z_Calloc O_o +// +void *M_Calloc(size_t n1, size_t n2) +{ + return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL; +} + +// +// M_StringAlloc +// +// haleyjd: This routine takes any number of strings and a number of extra +// characters, calculates their combined length, and calls Z_Alloca to create +// a temporary buffer of that size. This is extremely useful for allocation of +// file paths, and is used extensively in d_main.c. The pointer returned is +// to a temporary Z_Alloca buffer, which lives until the next main loop +// iteration, so don't cache it. Note that this idiom is not possible with the +// normal non-standard alloca function, which allocates stack space. +// +// [STRIFE] - haleyjd 20110210 +// This routine is taken from the Eternity Engine and adapted to do without +// Z_Alloca. I need secure string concatenation for filepath handling. The +// only difference from use in EE is that the pointer returned in *str must +// be manually freed. +// +int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...) +{ + va_list args; + size_t len = extra; + + if(numstrs < 1) + I_Error("M_StringAlloc: invalid input\n"); + + len += strlen(str1); + + --numstrs; + + if(numstrs != 0) + { + va_start(args, str1); + + while(numstrs != 0) + { + const char *argstr = va_arg(args, const char *); + + len += strlen(argstr); + + --numstrs; + } + + va_end(args); + } + + ++len; + + *str = (char *)(M_Calloc(1, len)); + + return len; +} + +// +// M_NormalizeSlashes +// +// Remove trailing slashes, translate backslashes to slashes +// The string to normalize is passed and returned in str +// +// killough 11/98: rewritten +// +// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect +// the DIR_SEPARATOR define used by Choco Doom. This routine originated in +// BOOM. +// +void M_NormalizeSlashes(char *str) +{ + char *p; + + // Convert all slashes/backslashes to DIR_SEPARATOR + for(p = str; *p; p++) + { + if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR) + *p = DIR_SEPARATOR; + } + + // Remove trailing slashes + while(p > str && *--p == DIR_SEPARATOR) + *p = 0; + + // Collapse multiple slashes + for(p = str; (*str++ = *p); ) + if(*p++ == DIR_SEPARATOR) + while(*p == DIR_SEPARATOR) + p++; +} + +// +// M_SafeFilePath +// +// haleyjd 20110210 - original routine. +// This routine performs safe, portable concatenation of a base file path +// with another path component or file name. The returned string is Z_Malloc'd +// and should be freed when it has exhausted its usefulness. +// +char *M_SafeFilePath(const char *basepath, const char *newcomponent) +{ + int newstrlen = 0; + char *newstr = NULL; + + // Always throw in a slash. M_NormalizeSlashes will remove it in the case + // that either basepath or newcomponent includes a redundant slash at the + // end or beginning respectively. + newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent); + snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent); + M_NormalizeSlashes(newstr); + + return newstr; +} + +// +// M_GetFilePath +// +// haleyjd: STRIFE-FIXME: Temporary? +// Code borrowed from Eternity, and modified to return separator char +// +char M_GetFilePath(const char *fn, char *dest, size_t len) +{ + boolean found_slash = false; + char *p; + char sepchar = '\0'; + + memset(dest, 0, len); + + p = dest + len - 1; + + strncpy(dest, fn, len); + + while(p >= dest) + { + if(*p == '/' || *p == '\\') + { + sepchar = *p; + found_slash = true; // mark that the path ended with a slash + *p = '\0'; + break; + } + *p = '\0'; + p--; + } + + // haleyjd: in the case that no slash was ever found, yet the + // path string is empty, we are dealing with a file local to the + // working directory. The proper path to return for such a string is + // not "", but ".", since the format strings add a slash now. When + // the string is empty but a slash WAS found, we really do want to + // return the empty string, since the path is relative to the root. + if(!found_slash && *dest == '\0') + *dest = '.'; + + // if a separator is not found, default to forward, because Windows + // supports that too. + if(sepchar == '\0') + sepchar = '/'; + + return sepchar; } // EOF diff --git a/src/strife/m_saves.h b/src/strife/m_saves.h index 9b587c81..b55ffa12 100644 --- a/src/strife/m_saves.h +++ b/src/strife/m_saves.h @@ -31,8 +31,16 @@ #ifndef M_SAVES_H__ #define M_SAVES_H__ +// Strife Savegame Functions boolean M_SaveMisObj(const char *path); +// Custom Utilities for Filepath Handling +void *M_Calloc(size_t n1, size_t n2); +void M_NormalizeSlashes(char *str); +int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...); +char *M_SafeFilePath(const char *basepath, const char *newcomponent); +char M_GetFilePath(const char *fn, char *dest, size_t len); + #endif // EOF diff --git a/src/strife/p_enemy.c b/src/strife/p_enemy.c index 4bfceefe..9cbaf3ed 100644 --- a/src/strife/p_enemy.c +++ b/src/strife/p_enemy.c @@ -315,7 +315,7 @@ boolean P_CheckMissileRange(mobj_t* actor) actor->y-actor->target->y) - 64*FRACUNIT; if (!actor->info->meleestate) - dist -= 128*FRACUNIT; // no melee attack, so fire more + dist -= 128*FRACUNIT; // no melee attack, so fire more dist >>= 16; @@ -669,7 +669,7 @@ void P_NewRandomDir(mobj_t* actor) dir = DI_SOUTHEAST; while(1) { - // haleyjd 09/05/10: P_TryWalk -> P_Move, missing random code. + // haleyjd 09/05/10: missing random code. if(dir != opposite[actor->movedir]) { actor->movedir = dir; diff --git a/src/strife/s_sound.c b/src/strife/s_sound.c index bedde12c..c29ce392 100644 --- a/src/strife/s_sound.c +++ b/src/strife/s_sound.c @@ -538,7 +538,8 @@ static unsigned int S_voiceHash(const char *str) ++c; } - return h;} + return h; +} static voiceinfo_t *voices[NUMVOICECHAINS]; @@ -619,7 +620,6 @@ void I_StartVoice(const char *lumpname) strncpy(lumpnamedup, lumpname, 9); lumpnamedup[8] = '\0'; - if((lumpnum = W_CheckNumForName(lumpnamedup)) != -1) { // haleyjd: Choco-specific: get a voice structure -- cgit v1.2.3