diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 1b0280452..8233164c5 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -1823,6 +1823,7 @@ void LoadGameLevel(BOOL firstflag, int lvldir) dFlags[i][j] |= BFLAG_LIT; } + LoadHotkeys(); InitTowners(); InitItems(); InitMissiles(); diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 1b23750f6..557cf7083 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -14,6 +14,98 @@ int giNumberOfLevels; int giNumberQuests; int giNumberOfSmithPremiumItems; +class LoadHelper { + Uint8 *m_buffer; + Uint32 m_bufferPtr = 0; + Uint32 m_bufferLen; + +public: + LoadHelper(const char *szFileName) + { + m_buffer = pfile_read(szFileName, &m_bufferLen); + } + + bool isValid(Uint32 len = 1) + { + return m_buffer != nullptr + && m_bufferLen >= (m_bufferPtr + len); + } + + Uint8 nextByte() + { + if (!this->isValid(1)) + return 0; + + Uint8 value = m_buffer[m_bufferPtr]; + m_bufferPtr++; + + return value; + } + + Uint32 nextLE32() + { + if (!this->isValid(4)) + return 0; + + Uint32 value; + memcpy(&value, &m_buffer[m_bufferPtr], 4); + m_bufferPtr += 4; + + return SDL_SwapLE32(value); + } + + ~LoadHelper() + { + mem_free_dbg(m_buffer); + } +}; + +class SaveHelper { + const char *m_szFileName; + Uint8 *m_buffer; + Uint32 m_bufferPtr = 0; + Uint32 m_bufferLen; + +public: + SaveHelper(const char *szFileName, size_t bufferLen) + { + m_szFileName = szFileName; + m_bufferLen = bufferLen; + m_buffer = DiabloAllocPtr(codec_get_encoded_len(m_bufferLen)); + } + + bool isValid(Uint32 len = 1) + { + return m_buffer != nullptr + && m_bufferLen >= (m_bufferPtr + len); + } + + void writeByte(Uint8 value) + { + if (!this->isValid(1)) + return; + + m_buffer[m_bufferPtr] = SDL_SwapLE32(value); + m_bufferPtr++; + } + + void writeLE32(Uint32 value) + { + if (!this->isValid(4)) + return; + + Uint32 temp = SDL_SwapLE32(value); + memcpy(&m_buffer[m_bufferPtr], &temp, 4); + m_bufferPtr += 4; + } + + ~SaveHelper() + { + pfile_write_save_file(m_szFileName, m_buffer, m_bufferPtr, codec_get_encoded_len(m_bufferPtr)); + mem_free_dbg(m_buffer); + } +}; + static char BLoad() { return *tbuff++; @@ -824,6 +916,36 @@ void ConvertLevels() tbuff = _tbuff; } +void LoadHotkeys() +{ + LoadHelper file("hotkeys"); + if (!file.isValid()) + return; + + for (size_t i = 0; i < sizeof(plr[myplr]._pSplHotKey) / sizeof(plr[myplr]._pSplHotKey[0]); i++) { + plr[myplr]._pSplHotKey[i] = file.nextLE32(); + } + for (size_t i = 0; i < sizeof(plr[myplr]._pSplTHotKey) / sizeof(plr[myplr]._pSplTHotKey[0]); i++) { + plr[myplr]._pSplTHotKey[i] = file.nextByte(); + } + plr[myplr]._pRSpell = file.nextLE32(); + plr[myplr]._pRSplType = file.nextByte(); +} + +void SaveHotkeys() +{ + SaveHelper file("hotkeys", sizeof(plr[myplr]._pSplHotKey) + sizeof(plr[myplr]._pSplTHotKey) + 5); + + for (size_t i = 0; i < sizeof(plr[myplr]._pSplHotKey) / sizeof(plr[myplr]._pSplHotKey[0]); i++) { + file.writeLE32(plr[myplr]._pSplHotKey[i]); + } + for (size_t i = 0; i < sizeof(plr[myplr]._pSplTHotKey) / sizeof(plr[myplr]._pSplTHotKey[0]); i++) { + file.writeByte(plr[myplr]._pSplTHotKey[i]); + } + file.writeLE32(plr[myplr]._pRSpell); + file.writeByte(plr[myplr]._pRSplType); +} + /** * @brief Load game state * @param firstflag Can be set to false if we are simply reloading the current game @@ -838,6 +960,9 @@ void LoadGame(BOOL firstflag) FreeGameMem(); pfile_remove_temp_files(); LoadBuff = pfile_read("game", &dwLen); + if (LoadBuff == NULL) + app_fatal("Unable to open save file archive"); + tbuff = LoadBuff; if (!IsHeaderValid(ILoad())) @@ -1911,6 +2036,8 @@ void LoadLevel() GetPermLevelNames(szName); LoadBuff = pfile_read(szName, &dwLen); + if (LoadBuff == NULL) + app_fatal("Unable to open save file archive"); tbuff = LoadBuff; if (leveltype != DTYPE_TOWN) { diff --git a/Source/loadsave.h b/Source/loadsave.h index cadbc2ee7..c4fb373ff 100644 --- a/Source/loadsave.h +++ b/Source/loadsave.h @@ -18,7 +18,9 @@ extern int giNumberOfLevels; int RemapItemIdxFromDiablo(int i); int RemapItemIdxToDiablo(int i); bool IsHeaderValid(int magicNumber); +void LoadHotkeys(); void LoadGame(BOOL firstflag); +void SaveHotkeys(); void SaveGame(); void SaveLevel(); void LoadLevel(); diff --git a/Source/pfile.cpp b/Source/pfile.cpp index d5f3ed98c..fd49acd11 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -184,6 +184,7 @@ void pfile_write_hero() if (pfile_open_archive(save_num)) { PackPlayer(&pkplr, myplr, !gbIsMultiplayer); pfile_encode_hero(&pkplr); + SaveHotkeys(); pfile_flush(!gbIsMultiplayer, save_num); } } @@ -546,12 +547,12 @@ BYTE *pfile_read(const char *pszName, DWORD *pdwLen) save_num = pfile_get_save_num_from_name(plr[myplr]._pName); archive = pfile_open_save_archive(save_num); if (archive == NULL) - app_fatal("Unable to open save file archive"); + return NULL; buf = pfile_read_archive(archive, pszName, pdwLen); pfile_SFileCloseArchive(archive); if (buf == NULL) - app_fatal("Invalid %s file", pszName); + return NULL; return buf; }