|
|
|
|
#include "all.h"
|
|
|
|
|
#include "../3rdParty/Storm/Source/storm.h"
|
|
|
|
|
#include "../DiabloUI/diabloui.h"
|
|
|
|
|
|
|
|
|
|
#ifdef SPAWN
|
|
|
|
|
#define PASSWORD_SINGLE "adslhfb1"
|
|
|
|
|
#define PASSWORD_MULTI "lshbkfg1"
|
|
|
|
|
#else
|
|
|
|
|
#define PASSWORD_SINGLE "xrgyrkj1"
|
|
|
|
|
#define PASSWORD_MULTI "szqnlsk1"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static char hero_names[MAX_CHARACTERS][PLR_NAME_LEN];
|
|
|
|
|
BOOL gbValidSaveFile;
|
|
|
|
|
|
|
|
|
|
void pfile_init_save_directory()
|
|
|
|
|
{
|
|
|
|
|
DWORD len;
|
|
|
|
|
char Buffer[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
len = GetWindowsDirectory(Buffer, sizeof(Buffer));
|
|
|
|
|
if (len) {
|
|
|
|
|
pfile_check_available_space(Buffer);
|
|
|
|
|
len = GetModuleFileName(ghInst, Buffer, sizeof(Buffer));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
|
app_fatal("Unable to initialize save directory");
|
|
|
|
|
else
|
|
|
|
|
pfile_check_available_space(Buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_check_available_space(char *pszDir)
|
|
|
|
|
{
|
|
|
|
|
char *s;
|
|
|
|
|
BOOL hasSpace;
|
|
|
|
|
DWORD TotalNumberOfClusters;
|
|
|
|
|
DWORD NumberOfFreeClusters;
|
|
|
|
|
DWORD BytesPerSector;
|
|
|
|
|
DWORD SectorsPerCluster;
|
|
|
|
|
|
|
|
|
|
s = pszDir;
|
|
|
|
|
while (*s) {
|
|
|
|
|
if (*s++ != '\\')
|
|
|
|
|
continue;
|
|
|
|
|
*s = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hasSpace = GetDiskFreeSpace(pszDir, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
|
|
|
|
|
if (hasSpace) {
|
|
|
|
|
// 10MB is the amount hardcoded in the error dialog
|
|
|
|
|
if ((__int64)SectorsPerCluster * BytesPerSector * NumberOfFreeClusters < (__int64)(10 << 20))
|
|
|
|
|
hasSpace = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!hasSpace)
|
|
|
|
|
DiskFreeDlg(pszDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_write_hero()
|
|
|
|
|
{
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
PkPlayerStruct pkplr;
|
|
|
|
|
|
|
|
|
|
save_num = pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
if (pfile_open_archive(TRUE, save_num)) {
|
|
|
|
|
PackPlayer(&pkplr, myplr, gbMaxPlayers == 1);
|
|
|
|
|
pfile_encode_hero(&pkplr);
|
|
|
|
|
pfile_flush(gbMaxPlayers == 1, save_num);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD pfile_get_save_num_from_name(const char *name)
|
|
|
|
|
{
|
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_CHARACTERS; i++) {
|
|
|
|
|
if (!_strcmpi(hero_names[i], name))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_encode_hero(const PkPlayerStruct *pPack)
|
|
|
|
|
{
|
|
|
|
|
BYTE *packed;
|
|
|
|
|
DWORD packed_len;
|
|
|
|
|
char password[16] = PASSWORD_SINGLE;
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers > 1)
|
|
|
|
|
strcpy(password, PASSWORD_MULTI);
|
|
|
|
|
|
|
|
|
|
packed_len = codec_get_encoded_len(sizeof(*pPack));
|
|
|
|
|
packed = (BYTE *)DiabloAllocPtr(packed_len);
|
|
|
|
|
memcpy(packed, pPack, sizeof(*pPack));
|
|
|
|
|
codec_encode(packed, sizeof(*pPack), packed_len, password);
|
|
|
|
|
mpqapi_write_file("hero", packed, packed_len);
|
|
|
|
|
mem_free_dbg(packed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL pfile_open_archive(BOOL update, DWORD save_num)
|
|
|
|
|
{
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
pfile_get_save_path(FileName, sizeof(FileName), save_num);
|
|
|
|
|
if (OpenMPQ(FileName, FALSE, save_num))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (update && gbMaxPlayers > 1)
|
|
|
|
|
mpqapi_store_default_time(save_num);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_get_save_path(char *pszBuf, DWORD dwBufSize, DWORD save_num)
|
|
|
|
|
{
|
|
|
|
|
DWORD plen;
|
|
|
|
|
char *s;
|
|
|
|
|
char path[MAX_PATH];
|
|
|
|
|
#ifdef SPAWN
|
|
|
|
|
const char *fmt = "\\share_%d.sv";
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers <= 1)
|
|
|
|
|
fmt = "\\spawn%d.sv";
|
|
|
|
|
#else
|
|
|
|
|
const char *fmt = "\\multi_%d.sv";
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers <= 1)
|
|
|
|
|
fmt = "\\single_%d.sv";
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// BUGFIX: ignores dwBufSize and uses MAX_PATH instead
|
|
|
|
|
plen = GetModuleFileName(ghInst, pszBuf, MAX_PATH);
|
|
|
|
|
s = strrchr(pszBuf, '\\');
|
|
|
|
|
if (s)
|
|
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
|
|
if (!plen)
|
|
|
|
|
app_fatal("Unable to get save directory");
|
|
|
|
|
|
|
|
|
|
sprintf(path, fmt, save_num);
|
|
|
|
|
strcat(pszBuf, path);
|
|
|
|
|
_strlwr(pszBuf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_flush(BOOL is_single_player, DWORD save_num)
|
|
|
|
|
{
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
pfile_get_save_path(FileName, sizeof(FileName), save_num);
|
|
|
|
|
mpqapi_flush_and_close(FileName, is_single_player, save_num);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL pfile_create_player_description(char *dst, DWORD len)
|
|
|
|
|
{
|
|
|
|
|
char desc[128];
|
|
|
|
|
_uiheroinfo uihero;
|
|
|
|
|
|
|
|
|
|
myplr = 0;
|
|
|
|
|
pfile_read_player_from_save();
|
|
|
|
|
game_2_ui_player(plr, &uihero, gbValidSaveFile);
|
|
|
|
|
UiSetupPlayerInfo(gszHero, &uihero, GAME_ID);
|
|
|
|
|
|
|
|
|
|
if (dst != NULL && len) {
|
|
|
|
|
if (UiCreatePlayerDescription(&uihero, GAME_ID, desc) == 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
SStrCopy(dst, desc, len);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL pfile_rename_hero(const char *name_1, const char *name_2)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
_uiheroinfo uihero;
|
|
|
|
|
BOOL found = FALSE;
|
|
|
|
|
|
|
|
|
|
if (pfile_get_save_num_from_name(name_2) == MAX_CHARACTERS) {
|
|
|
|
|
for (i = 0; i != MAX_PLRS; i++) {
|
|
|
|
|
if (!_strcmpi(name_1, plr[i]._pName)) {
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
return FALSE;
|
|
|
|
|
save_num = pfile_get_save_num_from_name(name_1);
|
|
|
|
|
if (save_num == MAX_CHARACTERS)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
SStrCopy(hero_names[save_num], name_2, PLR_NAME_LEN);
|
|
|
|
|
SStrCopy(plr[i]._pName, name_2, PLR_NAME_LEN);
|
|
|
|
|
if (!_strcmpi(gszHero, name_1))
|
|
|
|
|
SStrCopy(gszHero, name_2, sizeof(gszHero));
|
|
|
|
|
game_2_ui_player(plr, &uihero, gbValidSaveFile);
|
|
|
|
|
UiSetupPlayerInfo(gszHero, &uihero, GAME_ID);
|
|
|
|
|
pfile_write_hero();
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_flush_W()
|
|
|
|
|
{
|
|
|
|
|
pfile_flush(TRUE, pfile_get_save_num_from_name(plr[myplr]._pName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void game_2_ui_player(const PlayerStruct *p, _uiheroinfo *heroinfo, BOOL bHasSaveFile)
|
|
|
|
|
{
|
|
|
|
|
memset(heroinfo, 0, sizeof(*heroinfo));
|
|
|
|
|
strncpy(heroinfo->name, p->_pName, sizeof(heroinfo->name) - 1);
|
|
|
|
|
heroinfo->name[sizeof(heroinfo->name) - 1] = '\0';
|
|
|
|
|
heroinfo->level = p->_pLevel;
|
|
|
|
|
heroinfo->heroclass = game_2_ui_class(p);
|
|
|
|
|
heroinfo->strength = p->_pStrength;
|
|
|
|
|
heroinfo->magic = p->_pMagic;
|
|
|
|
|
heroinfo->dexterity = p->_pDexterity;
|
|
|
|
|
heroinfo->vitality = p->_pVitality;
|
|
|
|
|
heroinfo->gold = p->_pGold;
|
|
|
|
|
heroinfo->hassaved = bHasSaveFile;
|
|
|
|
|
heroinfo->herorank = p->pDiabloKillLevel;
|
|
|
|
|
#ifdef SPAWN
|
|
|
|
|
heroinfo->spawned = TRUE;
|
|
|
|
|
#else
|
|
|
|
|
heroinfo->spawned = FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BYTE game_2_ui_class(const PlayerStruct *p)
|
|
|
|
|
{
|
|
|
|
|
BYTE uiclass;
|
|
|
|
|
if (p->_pClass == PC_WARRIOR)
|
|
|
|
|
uiclass = UI_WARRIOR;
|
|
|
|
|
else if (p->_pClass == PC_ROGUE)
|
|
|
|
|
uiclass = UI_ROGUE;
|
|
|
|
|
else
|
|
|
|
|
uiclass = UI_SORCERER;
|
|
|
|
|
|
|
|
|
|
return uiclass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall pfile_ui_set_hero_infos(BOOL(__stdcall *ui_add_hero_info)(_uiheroinfo *))
|
|
|
|
|
{
|
|
|
|
|
DWORD i, save_num;
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
char NewFileName[MAX_PATH];
|
|
|
|
|
BOOL showFixedMsg;
|
|
|
|
|
|
|
|
|
|
memset(hero_names, 0, sizeof(hero_names));
|
|
|
|
|
if (gbMaxPlayers > 1) {
|
|
|
|
|
for (i = 0, save_num = 0; i < MAX_CHARACTERS && save_num < MAX_CHARACTERS; i++) {
|
|
|
|
|
struct _OFSTRUCT ReOpenBuff;
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
GetSaveDirectory(FileName, sizeof(FileName), i);
|
|
|
|
|
s = strrchr(FileName, '\\') + 1;
|
|
|
|
|
if (s == (const char *)1)
|
|
|
|
|
continue;
|
|
|
|
|
if (OpenFile(FileName, &ReOpenBuff, OF_EXIST) == HFILE_ERROR)
|
|
|
|
|
continue;
|
|
|
|
|
if (!SRegLoadString("Diablo\\Converted", s, 0, NewFileName, sizeof(NewFileName))) {
|
|
|
|
|
while (save_num < MAX_CHARACTERS) {
|
|
|
|
|
pfile_get_save_path(NewFileName, sizeof(NewFileName), save_num++);
|
|
|
|
|
if (OpenFile(NewFileName, &ReOpenBuff, OF_EXIST) == HFILE_ERROR) {
|
|
|
|
|
if (CopyFile(FileName, NewFileName, TRUE)) {
|
|
|
|
|
DWORD attrib;
|
|
|
|
|
SRegSaveString("Diablo\\Converted", s, 0, NewFileName);
|
|
|
|
|
attrib = GetFileAttributes(NewFileName);
|
|
|
|
|
if (attrib != INVALID_FILE_ATTRIBUTES) {
|
|
|
|
|
attrib &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
|
|
|
|
|
SetFileAttributes(NewFileName, attrib);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
showFixedMsg = TRUE;
|
|
|
|
|
for (i = 0; i < MAX_CHARACTERS; i++) {
|
|
|
|
|
PkPlayerStruct pkplr;
|
|
|
|
|
HANDLE archive = pfile_open_save_archive(&showFixedMsg, i);
|
|
|
|
|
if (archive) {
|
|
|
|
|
if (pfile_read_hero(archive, &pkplr)) {
|
|
|
|
|
_uiheroinfo uihero;
|
|
|
|
|
strcpy(hero_names[i], pkplr.pName);
|
|
|
|
|
UnPackPlayer(&pkplr, 0, FALSE);
|
|
|
|
|
game_2_ui_player(plr, &uihero, pfile_archive_contains_game(archive, i));
|
|
|
|
|
ui_add_hero_info(&uihero);
|
|
|
|
|
}
|
|
|
|
|
pfile_SFileCloseArchive(archive);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *GetSaveDirectory(char *dst, int dst_size, DWORD save_num)
|
|
|
|
|
{
|
|
|
|
|
DWORD dirLen;
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
const char *savename;
|
|
|
|
|
|
|
|
|
|
// BUGFIX: ignores dst_size and uses MAX_PATH instead
|
|
|
|
|
if (gbMaxPlayers > 1) {
|
|
|
|
|
#ifdef SPAWN
|
|
|
|
|
savename = "\\slinfo_%d.drv";
|
|
|
|
|
#else
|
|
|
|
|
savename = "\\dlinfo_%d.drv";
|
|
|
|
|
#endif
|
|
|
|
|
dirLen = GetWindowsDirectory(dst, MAX_PATH);
|
|
|
|
|
} else {
|
|
|
|
|
char *s;
|
|
|
|
|
#ifdef SPAWN
|
|
|
|
|
savename = "\\spawn_%d.sv";
|
|
|
|
|
#else
|
|
|
|
|
savename = "\\single_%d.sv";
|
|
|
|
|
#endif
|
|
|
|
|
dirLen = GetModuleFileName(ghInst, dst, MAX_PATH);
|
|
|
|
|
s = strrchr(dst, '\\');
|
|
|
|
|
if (s)
|
|
|
|
|
*s = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dirLen)
|
|
|
|
|
app_fatal("Unable to get save directory");
|
|
|
|
|
|
|
|
|
|
sprintf(FileName, savename, save_num);
|
|
|
|
|
strcat(dst, FileName);
|
|
|
|
|
return _strlwr(dst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack)
|
|
|
|
|
{
|
|
|
|
|
HANDLE file;
|
|
|
|
|
BOOL decoded;
|
|
|
|
|
DWORD dwlen, nSize;
|
|
|
|
|
BYTE *buf;
|
|
|
|
|
|
|
|
|
|
if (!SFileOpenFileEx(archive, "hero", 0, &file)) {
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
char password[16] = PASSWORD_SINGLE;
|
|
|
|
|
nSize = 16;
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers > 1)
|
|
|
|
|
strcpy(password, PASSWORD_MULTI);
|
|
|
|
|
|
|
|
|
|
dwlen = SFileGetFileSize(file, NULL);
|
|
|
|
|
if (dwlen) {
|
|
|
|
|
DWORD read;
|
|
|
|
|
buf = DiabloAllocPtr(dwlen);
|
|
|
|
|
if (SFileReadFile(file, buf, dwlen, &read, NULL)) {
|
|
|
|
|
decoded = TRUE;
|
|
|
|
|
read = codec_decode(buf, dwlen, password);
|
|
|
|
|
if (!read && gbMaxPlayers > 1) {
|
|
|
|
|
GetComputerName(password, &nSize);
|
|
|
|
|
if (SFileSetFilePointer(file, 0, NULL, FILE_BEGIN) || !SFileReadFile(file, buf, dwlen, &read, NULL))
|
|
|
|
|
decoded = FALSE;
|
|
|
|
|
else
|
|
|
|
|
read = codec_decode(buf, dwlen, password);
|
|
|
|
|
}
|
|
|
|
|
if (decoded && read == sizeof(*pPack)) {
|
|
|
|
|
memcpy(pPack, buf, sizeof(*pPack));
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (buf)
|
|
|
|
|
mem_free_dbg(buf);
|
|
|
|
|
}
|
|
|
|
|
SFileCloseFile(file);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param showFixedMsg Display a dialog if a save file was corrected (deprecated)
|
|
|
|
|
*/
|
|
|
|
|
HANDLE pfile_open_save_archive(BOOL *showFixedMsg, DWORD save_num)
|
|
|
|
|
{
|
|
|
|
|
char SrcStr[MAX_PATH];
|
|
|
|
|
HANDLE archive;
|
|
|
|
|
|
|
|
|
|
pfile_get_save_path(SrcStr, sizeof(SrcStr), save_num);
|
|
|
|
|
if (SFileOpenArchive(SrcStr, 0x7000, FS_PC, &archive))
|
|
|
|
|
return archive;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_SFileCloseArchive(HANDLE hsArchive)
|
|
|
|
|
{
|
|
|
|
|
SFileCloseArchive(hsArchive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL pfile_archive_contains_game(HANDLE hsArchive, DWORD save_num)
|
|
|
|
|
{
|
|
|
|
|
HANDLE file;
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers != 1)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (!SFileOpenFileEx(hsArchive, "game", 0, &file))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
SFileCloseFile(file);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats)
|
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
|
|
c = pfile_get_player_class(player_class_nr);
|
|
|
|
|
class_stats->strength = StrengthTbl[c];
|
|
|
|
|
class_stats->magic = MagicTbl[c];
|
|
|
|
|
class_stats->dexterity = DexterityTbl[c];
|
|
|
|
|
class_stats->vitality = VitalityTbl[c];
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char pfile_get_player_class(unsigned int player_class_nr)
|
|
|
|
|
{
|
|
|
|
|
char pc_class;
|
|
|
|
|
|
|
|
|
|
if (player_class_nr == UI_WARRIOR)
|
|
|
|
|
pc_class = PC_WARRIOR;
|
|
|
|
|
else if (player_class_nr == UI_ROGUE)
|
|
|
|
|
pc_class = PC_ROGUE;
|
|
|
|
|
else
|
|
|
|
|
pc_class = PC_SORCERER;
|
|
|
|
|
return pc_class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall pfile_ui_save_create(_uiheroinfo *heroinfo)
|
|
|
|
|
{
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
char cl;
|
|
|
|
|
PkPlayerStruct pkplr;
|
|
|
|
|
|
|
|
|
|
save_num = pfile_get_save_num_from_name(heroinfo->name);
|
|
|
|
|
if (save_num == MAX_CHARACTERS) {
|
|
|
|
|
for (save_num = 0; save_num < MAX_CHARACTERS; save_num++) {
|
|
|
|
|
if (!hero_names[save_num][0])
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (save_num == MAX_CHARACTERS)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (!pfile_open_archive(FALSE, save_num))
|
|
|
|
|
return FALSE;
|
|
|
|
|
mpqapi_remove_hash_entries(pfile_get_file_name);
|
|
|
|
|
strncpy(hero_names[save_num], heroinfo->name, PLR_NAME_LEN);
|
|
|
|
|
hero_names[save_num][PLR_NAME_LEN - 1] = '\0';
|
|
|
|
|
cl = pfile_get_player_class(heroinfo->heroclass);
|
|
|
|
|
CreatePlayer(0, cl);
|
|
|
|
|
strncpy(plr[0]._pName, heroinfo->name, PLR_NAME_LEN);
|
|
|
|
|
plr[0]._pName[PLR_NAME_LEN - 1] = '\0';
|
|
|
|
|
PackPlayer(&pkplr, 0, TRUE);
|
|
|
|
|
pfile_encode_hero(&pkplr);
|
|
|
|
|
game_2_ui_player(&plr[0], heroinfo, FALSE);
|
|
|
|
|
pfile_flush(TRUE, save_num);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall pfile_get_file_name(DWORD lvl, char *dst)
|
|
|
|
|
{
|
|
|
|
|
const char *fmt;
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers > 1) {
|
|
|
|
|
if (lvl)
|
|
|
|
|
return FALSE;
|
|
|
|
|
fmt = "hero";
|
|
|
|
|
} else {
|
|
|
|
|
if (lvl < 17)
|
|
|
|
|
fmt = "perml%02d";
|
|
|
|
|
else if (lvl < 34) {
|
|
|
|
|
lvl -= 17;
|
|
|
|
|
fmt = "perms%02d";
|
|
|
|
|
} else if (lvl == 34)
|
|
|
|
|
fmt = "game";
|
|
|
|
|
else if (lvl == 35)
|
|
|
|
|
fmt = "hero";
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
sprintf(dst, fmt, lvl);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall pfile_delete_save(_uiheroinfo *hero_info)
|
|
|
|
|
{
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
save_num = pfile_get_save_num_from_name(hero_info->name);
|
|
|
|
|
if (save_num < MAX_CHARACTERS) {
|
|
|
|
|
hero_names[save_num][0] = '\0';
|
|
|
|
|
pfile_get_save_path(FileName, sizeof(FileName), save_num);
|
|
|
|
|
DeleteFile(FileName);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_read_player_from_save()
|
|
|
|
|
{
|
|
|
|
|
HANDLE archive;
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
PkPlayerStruct pkplr;
|
|
|
|
|
|
|
|
|
|
save_num = pfile_get_save_num_from_name(gszHero);
|
|
|
|
|
archive = pfile_open_save_archive(NULL, save_num);
|
|
|
|
|
if (archive == NULL)
|
|
|
|
|
app_fatal("Unable to open archive");
|
|
|
|
|
if (!pfile_read_hero(archive, &pkplr))
|
|
|
|
|
app_fatal("Unable to load character");
|
|
|
|
|
|
|
|
|
|
UnPackPlayer(&pkplr, myplr, FALSE);
|
|
|
|
|
gbValidSaveFile = pfile_archive_contains_game(archive, save_num);
|
|
|
|
|
pfile_SFileCloseArchive(archive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetTempLevelNames(char *szTemp)
|
|
|
|
|
{
|
|
|
|
|
// BUGFIX: function call has no purpose
|
|
|
|
|
pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
if (setlevel)
|
|
|
|
|
sprintf(szTemp, "temps%02d", setlvlnum);
|
|
|
|
|
else
|
|
|
|
|
sprintf(szTemp, "templ%02d", currlevel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetPermLevelNames(char *szPerm)
|
|
|
|
|
{
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
BOOL has_file;
|
|
|
|
|
|
|
|
|
|
save_num = pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
GetTempLevelNames(szPerm);
|
|
|
|
|
if (!pfile_open_archive(FALSE, save_num))
|
|
|
|
|
app_fatal("Unable to read to save file archive");
|
|
|
|
|
|
|
|
|
|
has_file = mpqapi_has_file(szPerm);
|
|
|
|
|
pfile_flush(TRUE, save_num);
|
|
|
|
|
if (!has_file) {
|
|
|
|
|
if (setlevel)
|
|
|
|
|
sprintf(szPerm, "perms%02d", setlvlnum);
|
|
|
|
|
else
|
|
|
|
|
sprintf(szPerm, "perml%02d", currlevel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_get_game_name(char *dst)
|
|
|
|
|
{
|
|
|
|
|
// BUGFIX: function call with no purpose
|
|
|
|
|
pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
strcpy(dst, "game");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_remove_temp_files()
|
|
|
|
|
{
|
|
|
|
|
if (gbMaxPlayers <= 1) {
|
|
|
|
|
DWORD save_num = pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
if (!pfile_open_archive(FALSE, save_num))
|
|
|
|
|
app_fatal("Unable to write to save file archive");
|
|
|
|
|
mpqapi_remove_hash_entries(GetTempSaveNames);
|
|
|
|
|
pfile_flush(TRUE, save_num);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall GetTempSaveNames(DWORD dwIndex, char *szTemp)
|
|
|
|
|
{
|
|
|
|
|
const char *fmt;
|
|
|
|
|
|
|
|
|
|
if (dwIndex < 17)
|
|
|
|
|
fmt = "templ%02d";
|
|
|
|
|
else if (dwIndex < 34) {
|
|
|
|
|
dwIndex -= 17;
|
|
|
|
|
fmt = "temps%02d";
|
|
|
|
|
} else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
sprintf(szTemp, fmt, dwIndex);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_rename_temp_to_perm()
|
|
|
|
|
{
|
|
|
|
|
DWORD dwChar, dwIndex;
|
|
|
|
|
BOOL bResult;
|
|
|
|
|
char szTemp[MAX_PATH];
|
|
|
|
|
char szPerm[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
dwChar = pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
/// ASSERT: assert(dwChar < MAX_CHARACTERS);
|
|
|
|
|
/// ASSERT: assert(gbMaxPlayers == 1);
|
|
|
|
|
if (!pfile_open_archive(FALSE, dwChar))
|
|
|
|
|
app_fatal("Unable to write to save file archive");
|
|
|
|
|
|
|
|
|
|
dwIndex = 0;
|
|
|
|
|
while (GetTempSaveNames(dwIndex, szTemp)) {
|
|
|
|
|
bResult = GetPermSaveNames(dwIndex, szPerm);
|
|
|
|
|
/// ASSERT: assert(bResult);
|
|
|
|
|
dwIndex++;
|
|
|
|
|
if (mpqapi_has_file(szTemp)) {
|
|
|
|
|
if (mpqapi_has_file(szPerm))
|
|
|
|
|
mpqapi_remove_hash_entry(szPerm);
|
|
|
|
|
mpqapi_rename(szTemp, szPerm);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// ASSERT: assert(! GetPermSaveNames(dwIndex,szPerm));
|
|
|
|
|
GetPermSaveNames(dwIndex, szPerm); // BUGFIX: function call has no purpose
|
|
|
|
|
pfile_flush(TRUE, dwChar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL __stdcall GetPermSaveNames(DWORD dwIndex, char *szPerm)
|
|
|
|
|
{
|
|
|
|
|
const char *fmt;
|
|
|
|
|
|
|
|
|
|
if (dwIndex < 17)
|
|
|
|
|
fmt = "perml%02d";
|
|
|
|
|
else if (dwIndex < 34) {
|
|
|
|
|
dwIndex -= 17;
|
|
|
|
|
fmt = "perms%02d";
|
|
|
|
|
} else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
sprintf(szPerm, fmt, dwIndex);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_write_save_file(const char *pszName, BYTE *pbData, DWORD dwLen, DWORD qwLen)
|
|
|
|
|
{
|
|
|
|
|
DWORD save_num;
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
pfile_strcpy(FileName, pszName);
|
|
|
|
|
save_num = pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
{
|
|
|
|
|
char password[16] = PASSWORD_SINGLE;
|
|
|
|
|
if (gbMaxPlayers > 1)
|
|
|
|
|
strcpy(password, PASSWORD_MULTI);
|
|
|
|
|
|
|
|
|
|
codec_encode(pbData, dwLen, qwLen, password);
|
|
|
|
|
}
|
|
|
|
|
if (!pfile_open_archive(FALSE, save_num))
|
|
|
|
|
app_fatal("Unable to write so save file archive");
|
|
|
|
|
mpqapi_write_file(FileName, pbData, qwLen);
|
|
|
|
|
pfile_flush(TRUE, save_num);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_strcpy(char *dst, const char *src)
|
|
|
|
|
{
|
|
|
|
|
strcpy(dst, src);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BYTE *pfile_read(const char *pszName, DWORD *pdwLen)
|
|
|
|
|
{
|
|
|
|
|
DWORD save_num, nread;
|
|
|
|
|
char FileName[MAX_PATH];
|
|
|
|
|
HANDLE archive, save;
|
|
|
|
|
BYTE *buf;
|
|
|
|
|
|
|
|
|
|
pfile_strcpy(FileName, pszName);
|
|
|
|
|
save_num = pfile_get_save_num_from_name(plr[myplr]._pName);
|
|
|
|
|
archive = pfile_open_save_archive(NULL, save_num);
|
|
|
|
|
if (archive == NULL)
|
|
|
|
|
app_fatal("Unable to open save file archive");
|
|
|
|
|
|
|
|
|
|
if (!SFileOpenFileEx(archive, FileName, 0, &save))
|
|
|
|
|
app_fatal("Unable to open save file");
|
|
|
|
|
|
|
|
|
|
*pdwLen = SFileGetFileSize(save, NULL);
|
|
|
|
|
if (*pdwLen == 0)
|
|
|
|
|
app_fatal("Invalid save file");
|
|
|
|
|
|
|
|
|
|
buf = (BYTE *)DiabloAllocPtr(*pdwLen);
|
|
|
|
|
if (!SFileReadFile(save, buf, *pdwLen, &nread, NULL))
|
|
|
|
|
app_fatal("Unable to read save file");
|
|
|
|
|
SFileCloseFile(save);
|
|
|
|
|
pfile_SFileCloseArchive(archive);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char password[16] = PASSWORD_SINGLE;
|
|
|
|
|
DWORD nSize = 16;
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers > 1)
|
|
|
|
|
strcpy(password, PASSWORD_MULTI);
|
|
|
|
|
|
|
|
|
|
*pdwLen = codec_decode(buf, *pdwLen, password);
|
|
|
|
|
if (*pdwLen == 0) {
|
|
|
|
|
// BUGFIFX: *pdwLen has already been overwritten with zero and the savefile has been closed
|
|
|
|
|
// there is no way this can work correctly
|
|
|
|
|
if (gbMaxPlayers > 1) {
|
|
|
|
|
GetComputerName(password, &nSize);
|
|
|
|
|
if (SFileSetFilePointer(save, 0, NULL, FILE_BEGIN))
|
|
|
|
|
app_fatal("Unable to read save file");
|
|
|
|
|
|
|
|
|
|
if (!SFileReadFile(save, buf, *pdwLen, &nread, NULL))
|
|
|
|
|
app_fatal("Unable to read save file");
|
|
|
|
|
*pdwLen = codec_decode(buf, *pdwLen, password);
|
|
|
|
|
}
|
|
|
|
|
if (*pdwLen == 0)
|
|
|
|
|
app_fatal("Invalid save file");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pfile_update(BOOL force_save)
|
|
|
|
|
{
|
|
|
|
|
// BUGFIX: these tick values should be treated as unsigned to handle overflows correctly
|
|
|
|
|
static int save_prev_tc;
|
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers != 1) {
|
|
|
|
|
int tick = GetTickCount();
|
|
|
|
|
if (force_save || tick - save_prev_tc > 60000) {
|
|
|
|
|
save_prev_tc = tick;
|
|
|
|
|
pfile_write_hero();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|