diff --git a/Source/engine/demomode.cpp b/Source/engine/demomode.cpp index fa5409652..3626a93a4 100644 --- a/Source/engine/demomode.cpp +++ b/Source/engine/demomode.cpp @@ -279,7 +279,7 @@ void NotifyGameLoopEnd() gbRunGameResult = false; gbRunGame = false; - HeroCompareResult compareResult = pfile_compare_hero_demo(DemoNumber); + HeroCompareResult compareResult = pfile_compare_hero_demo(DemoNumber, false); switch (compareResult.status) { case HeroCompareResult::ReferenceNotFound: SDL_Log("Timedemo: No final comparision cause reference is not present."); diff --git a/Source/pfile.cpp b/Source/pfile.cpp index fb17738da..b49d815b3 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -5,12 +5,15 @@ */ #include "pfile.h" +#include #include +#include #include #include "codec.h" #include "engine.h" +#include "engine/load_file.hpp" #include "init.h" #include "loadsave.h" #include "menu.h" @@ -188,55 +191,263 @@ bool ArchiveContainsGame(MpqArchive &hsArchive) return IsHeaderValid(hdr); } -HeroCompareResult CompareSaves(const std::string &actualSavePath, const std::string &referenceSavePath) +class MemoryBuffer : public std::basic_streambuf { +public: + MemoryBuffer(char *data, size_t byteCount) + { + setg(data, data, data + byteCount); + setp(data, data + byteCount); + } +}; + +struct CompareInfo { + std::unique_ptr &data; + size_t currentPosition; + size_t size; + bool isTownLevel; + bool dataExists; +}; + +struct CompareCounter { + int reference; + int actual; + int max() + { + return std::max(reference, actual); + } + void checkIfDataExists(int count, CompareInfo &compareInfoReference, CompareInfo &compareInfoActual) + { + if (reference == count) + compareInfoReference.dataExists = false; + if (actual == count) + compareInfoActual.dataExists = false; + } +}; + +inline bool string_ends_with(std::string const &value, std::string const &ending) +{ + if (ending.size() > value.size()) + return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +void CreateDetailDiffs(string_view prefix, string_view memoryMapFile, CompareInfo &compareInfoReference, CompareInfo &compareInfoActual, std::unordered_map &foundDiffs) { - std::vector possibleFileNamesToCheck; - possibleFileNamesToCheck.emplace_back("hero"); - possibleFileNamesToCheck.emplace_back("game"); - possibleFileNamesToCheck.emplace_back("additionalMissiles"); + // Note: Detail diffs are currently only supported in unit tests + std::string memoryMapFileAssetName = StrCat(paths::BasePath(), "/test/fixtures/memory_map/", memoryMapFile, ".txt"); + + SDL_RWops *handle = SDL_RWFromFile(memoryMapFileAssetName.c_str(), "r"); + if (handle == nullptr) { + app_fatal(StrCat("MemoryMapFile ", memoryMapFile, " is missing")); + return; + } + + size_t readBytes = SDL_RWsize(handle); + std::unique_ptr memoryMapFileData { new byte[readBytes] }; + SDL_RWread(handle, memoryMapFileData.get(), readBytes, 1); + + MemoryBuffer buffer(reinterpret_cast(memoryMapFileData.get()), readBytes); + std::istream reader(&buffer); + + std::unordered_map counter; + + auto getCounter = [&](const std::string &counterAsString) { + auto it = counter.find(counterAsString); + if (it != counter.end()) + return it->second; + int countFromMapFile = std::stoi(counterAsString); + return CompareCounter { countFromMapFile, countFromMapFile }; + }; + auto addDiff = [&](const std::string &diffKey) { + auto it = foundDiffs.find(diffKey); + if (it == foundDiffs.end()) { + foundDiffs.insert_or_assign(diffKey, 1); + } else { + foundDiffs.insert_or_assign(diffKey, it->second + 1); + } + }; + + auto compareBytes = [&](size_t countBytes) { + if (compareInfoReference.dataExists && compareInfoReference.currentPosition + countBytes > compareInfoReference.size) + app_fatal(StrCat("Comparsion failed. Too less bytes in reference to compare. Location: ", prefix)); + if (compareInfoActual.dataExists && compareInfoActual.currentPosition + countBytes > compareInfoActual.size) + app_fatal(StrCat("Comparsion failed. Too less bytes in actual to compare. Location: ", prefix)); + bool result = true; + if (compareInfoReference.dataExists && compareInfoActual.dataExists) + result = memcmp(compareInfoReference.data.get() + compareInfoReference.currentPosition, compareInfoActual.data.get() + compareInfoActual.currentPosition, countBytes) == 0; + if (compareInfoReference.dataExists) + compareInfoReference.currentPosition += countBytes; + if (compareInfoActual.dataExists) + compareInfoActual.currentPosition += countBytes; + return result; + }; + + auto read32BitInt = [&](CompareInfo &compareInfo, bool useLE) { + int32_t value = 0; + if (!compareInfo.dataExists) + return value; + if (compareInfo.currentPosition + sizeof(value) > compareInfo.size) + app_fatal("read32BitInt failed. Too less bytes to read."); + memcpy(&value, compareInfo.data.get() + compareInfo.currentPosition, sizeof(value)); + if (useLE) + value = SDL_SwapLE32(value); + else + value = SDL_SwapBE32(value); + return value; + }; + + std::string line; + while (std::getline(reader, line)) { + if (line.size() > 0 && line[line.size() - 1] == '\r') + line.resize(line.size() - 1); + if (line.size() == 0) + continue; + std::stringstream lineStream(line); + std::string command; + std::getline(lineStream, command, ' '); + + bool dataExistsReference = compareInfoReference.dataExists; + bool dataExistsActual = compareInfoActual.dataExists; + + if (string_ends_with(command, "_HF")) { + if (!gbIsHellfire) + continue; + command.resize(command.size() - 3); + } + if (string_ends_with(command, "_DA")) { + if (gbIsHellfire) + continue; + command.resize(command.size() - 3); + } + if (string_ends_with(command, "_DL")) { + if (compareInfoReference.isTownLevel && compareInfoActual.isTownLevel) + continue; + if (compareInfoReference.isTownLevel) + compareInfoReference.dataExists = false; + if (compareInfoActual.isTownLevel) + compareInfoActual.dataExists = false; + command.resize(command.size() - 3); + } + if (command == "R" || command == "LT" || command == "LC" || command == "LC_LE") { + std::string bitsAsString; + std::getline(lineStream, bitsAsString, ' '); + std::string comment; + std::getline(lineStream, comment); + + size_t bytes = static_cast(std::stoi(bitsAsString) / 8); + + if (command == "LT") { + int32_t valueReference = read32BitInt(compareInfoReference, false); + int32_t valueActual = read32BitInt(compareInfoActual, false); + assert(sizeof(valueReference) == bytes); + compareInfoReference.isTownLevel = valueReference == 0; + compareInfoActual.isTownLevel = valueActual == 0; + } + if (command == "LC" || command == "LC_LE") { + int32_t valueReference = read32BitInt(compareInfoReference, command == "LC_LE"); + int32_t valueActual = read32BitInt(compareInfoActual, command == "LC_LE"); + assert(sizeof(valueReference) == bytes); + counter.insert_or_assign(comment, CompareCounter { valueReference, valueActual }); + } + + if (!compareBytes(bytes)) { + std::string diffKey = StrCat(prefix, ".", comment); + addDiff(diffKey); + } + } else if (command == "M") { + std::string countAsString; + std::getline(lineStream, countAsString, ' '); + std::string bitsAsString; + std::getline(lineStream, bitsAsString, ' '); + std::string comment; + std::getline(lineStream, comment); + + CompareCounter count = getCounter(countAsString); + size_t bytes = static_cast(std::stoi(bitsAsString) / 8); + for (int i = 0; i < count.max(); i++) { + count.checkIfDataExists(i, compareInfoReference, compareInfoActual); + if (!compareBytes(bytes)) { + std::string diffKey = StrCat(prefix, ".", comment); + addDiff(diffKey); + } + } + } else if (command == "C") { + std::string countAsString; + std::getline(lineStream, countAsString, ' '); + std::string subMemoryMapFile; + std::getline(lineStream, subMemoryMapFile, ' '); + std::string comment; + std::getline(lineStream, comment); + + CompareCounter count = getCounter(countAsString); + subMemoryMapFile.erase(std::remove(subMemoryMapFile.begin(), subMemoryMapFile.end(), '\r'), subMemoryMapFile.end()); + for (int i = 0; i < count.max(); i++) { + count.checkIfDataExists(i, compareInfoReference, compareInfoActual); + std::string subPrefix = StrCat(prefix, ".", comment); + CreateDetailDiffs(subPrefix, subMemoryMapFile, compareInfoReference, compareInfoActual, foundDiffs); + } + } + + compareInfoReference.dataExists = dataExistsReference; + compareInfoActual.dataExists = dataExistsActual; + } +} + +struct CompareTargets { + std::string fileName; + std::string memoryMapFileName; + bool isTownLevel; +}; + +HeroCompareResult CompareSaves(const std::string &actualSavePath, const std::string &referenceSavePath, bool logDetails) +{ + std::vector possibleFileToCheck; + possibleFileToCheck.push_back({ "hero", "hero", false }); + possibleFileToCheck.push_back({ "game", "game", false }); + possibleFileToCheck.push_back({ "additionalMissiles", "additionalMissiles", false }); char szPerm[MaxMpqPathSize]; for (int i = 0; GetPermSaveNames(i, szPerm); i++) { - possibleFileNamesToCheck.emplace_back(szPerm); + possibleFileToCheck.push_back({ std::string(szPerm), "level", i == 0 }); } std::int32_t error; auto actualArchive = *MpqArchive::Open(actualSavePath.c_str(), error); auto referenceArchive = *MpqArchive::Open(referenceSavePath.c_str(), error); - for (const auto &fileName : possibleFileNamesToCheck) { - size_t fileSizeActual; - auto fileDataActual = ReadArchive(actualArchive, fileName.c_str(), &fileSizeActual); - size_t fileSizeReference; - auto fileDataReference = ReadArchive(referenceArchive, fileName.c_str(), &fileSizeReference); + bool compareResult = true; + std::string message; + for (const auto &compareTarget : possibleFileToCheck) { + size_t fileSizeActual = 0; + auto fileDataActual = ReadArchive(actualArchive, compareTarget.fileName.c_str(), &fileSizeActual); + size_t fileSizeReference = 0; + auto fileDataReference = ReadArchive(referenceArchive, compareTarget.fileName.c_str(), &fileSizeReference); if (fileDataActual.get() == nullptr && fileDataReference.get() == nullptr) { continue; } - if (fileSizeActual != fileSizeReference) { - return { HeroCompareResult::Difference, StrCat("file \"", fileName, "\" is different size. Expected: ", fileSizeReference, "Actual: ", fileSizeActual) }; - } - - const byte *reference = fileDataReference.get(); - const byte *referenceEnd = reference + fileSizeActual; - const byte *actual = fileDataActual.get(); - while (reference != referenceEnd) { - if (*reference != *actual) { - const size_t diffSize = std::min(16, referenceEnd - reference); - return { - HeroCompareResult::Difference, - fmt::format( - "file \"{}\" is different at byte {}:\n" - "Expected: ... {:02X} ...\n" - " Actual: ... {:02X} ...", - fileName, reference - fileDataReference.get(), - fmt::join(reference, reference + diffSize, " "), - fmt::join(actual, actual + diffSize, " ")) - }; - } - ++reference; - ++actual; + if (fileSizeActual == fileSizeReference && memcmp(fileDataReference.get(), fileDataActual.get(), fileSizeActual) == 0) + continue; + compareResult = false; + if (!message.empty()) + message.append("\n"); + if (fileSizeActual != fileSizeReference) + StrAppend(message, "file \"", compareTarget.fileName, "\" is different size. Expected: ", fileSizeReference, " Actual: ", fileSizeActual); + else + StrAppend(message, "file \"", compareTarget.fileName, "\" has different content."); + if (!logDetails) + continue; + std::unordered_map foundDiffs; + CompareInfo compareInfoReference = { fileDataReference, 0, fileSizeReference, compareTarget.isTownLevel, fileSizeReference != 0 }; + CompareInfo compareInfoActual = { fileDataActual, 0, fileSizeActual, compareTarget.isTownLevel, fileSizeActual != 0 }; + CreateDetailDiffs(compareTarget.fileName, compareTarget.memoryMapFileName, compareInfoReference, compareInfoActual, foundDiffs); + if (compareInfoReference.currentPosition != fileSizeReference) + app_fatal(StrCat("Comparsion failed. Uncompared bytes in reference. File: ", compareTarget.fileName)); + if (compareInfoActual.currentPosition != fileSizeActual) + app_fatal(StrCat("Comparsion failed. Uncompared bytes in actual. File: ", compareTarget.fileName)); + for (auto entry : foundDiffs) { + StrAppend(message, "\nDiff found in ", entry.first, " count: ", entry.second); } } - return { HeroCompareResult::Same, {} }; + return { compareResult ? HeroCompareResult::Same : HeroCompareResult::Difference, message }; } void pfile_write_hero(MpqWriter &saveWriter, bool writeGameData) @@ -309,7 +520,7 @@ void pfile_write_hero_demo(int demo) pfile_write_hero(saveWriter, true); } -HeroCompareResult pfile_compare_hero_demo(int demo) +HeroCompareResult pfile_compare_hero_demo(int demo, bool logDetails) { std::string referenceSavePath = GetSavePath(gSaveNumber, StrCat("demo_", demo, "_reference_")); @@ -322,7 +533,7 @@ HeroCompareResult pfile_compare_hero_demo(int demo) pfile_write_hero(saveWriter, true); } - return CompareSaves(actualSavePath, referenceSavePath); + return CompareSaves(actualSavePath, referenceSavePath, logDetails); } void sfile_write_stash() diff --git a/Source/pfile.h b/Source/pfile.h index 5aa4634f5..26bae7cbb 100644 --- a/Source/pfile.h +++ b/Source/pfile.h @@ -40,9 +40,10 @@ void pfile_write_hero_demo(int demo); /** * @brief Compares the actual game-state (savegame) with a reference game-state (save game from demo recording) * @param demo for the comparsion + * @param logDetails in case of a difference log details * @return The comparsion result. */ -HeroCompareResult pfile_compare_hero_demo(int demo); +HeroCompareResult pfile_compare_hero_demo(int demo, bool logDetails); void sfile_write_stash(); bool pfile_ui_set_hero_infos(bool (*uiAddHeroInfo)(_uiheroinfo *)); void pfile_ui_set_class_stats(unsigned int playerClass, _uidefaultstats *classStats); diff --git a/test/Fixtures.cmake b/test/Fixtures.cmake index 568bcf99f..45a126df9 100644 --- a/test/Fixtures.cmake +++ b/test/Fixtures.cmake @@ -64,6 +64,20 @@ set(devilutionx_fixtures Levels/L4Data/Vile1.DUN Levels/L4Data/Warlord.DUN Levels/L4Data/Warlord2.DUN + memory_map/additionalMissiles.txt + memory_map/game.txt + memory_map/hero.txt + memory_map/item.txt + memory_map/itemPack.txt + memory_map/level.txt + memory_map/levelSeed.txt + memory_map/lightning.txt + memory_map/missile.txt + memory_map/monster.txt + memory_map/object.txt + memory_map/player.txt + memory_map/portal.txt + memory_map/quest.txt timedemo/WarriorLevel1to2/demo_0.dmo timedemo/WarriorLevel1to2/demo_0_reference_spawn_0.sv timedemo/WarriorLevel1to2/spawn_0.sv diff --git a/test/fixtures/memory_map/additionalMissiles.txt b/test/fixtures/memory_map/additionalMissiles.txt new file mode 100644 index 000000000..1c82e1874 --- /dev/null +++ b/test/fixtures/memory_map/additionalMissiles.txt @@ -0,0 +1,3 @@ +R 32 Version +LC_LE 32 MissileCounter +C MissileCounter missile missiles diff --git a/test/fixtures/memory_map/game.txt b/test/fixtures/memory_map/game.txt new file mode 100644 index 000000000..e4cf7861f --- /dev/null +++ b/test/fixtures/memory_map/game.txt @@ -0,0 +1,55 @@ +R 32 header +R 8 setlevel +R 32 setlvlnum +R 32 currlevel +LT 32 leveltype +R 32 viewX +R 32 viewY +R 8 invflag +R 8 chrflag +LC 32 NumMonsters +LC 32 ItemCount +LC 32 NumMissiles +LC 32 NumObjects +C_DA 17 levelSeed levelSeeds +C_HF 25 levelSeed levelSeeds +C 1 player player +C_DA 16 quest quests +C_HF 24 quest quests +C 4 portal portals +M 200 32 MonsterKillCounts +M_DL 200 32 ActiveMonsters +C_DL NumMonsters monster monsters +M_DL 125 8 ActiveMissiles +M_DL 125 8 AvailableMissiles +C_DL NumMissiles missile missiles +M_DL 127 8 ActiveObjects +M_DL 127 8 AvailableObjects +C_DL NumObjects object objects +LC_DL 32 ActiveLightCount +M_DL 32 8 ActiveLights +C_DL ActiveLightCount lightning lightning +R_DL 32 VisionId +LC_DL 32 VisionCount +C_DL VisionCount lightning vision +M 127 8 ActiveItems +M 127 8 AvailableItems +C ItemCount item items +M 128 8 UniqueItemFlags +M 12544 8 dLight +M 12544 8 dFlags +M 12544 8 dPlayer +M 12544 8 dItem +M_DL 12544 32 dMonster +M_DL 12544 8 dCorpse +M_DL 12544 8 dObject +M_DL 12544 8 dLight +M_DL 12544 8 dPreLight +M_DL 1600 8 AutomapView +M_DL 12544 8 dMissile +R 32 numpremium +R 32 premiumlevel +C_DA 6 item PremiumItems +C_HF 15 item PremiumItems +R 8 AutomapActive +R 32 AutoMapScale diff --git a/test/fixtures/memory_map/hero.txt b/test/fixtures/memory_map/hero.txt new file mode 100644 index 000000000..3211f5782 --- /dev/null +++ b/test/fixtures/memory_map/hero.txt @@ -0,0 +1,49 @@ +R 32 dwLowDateTime +R 32 dwHighDateTime +R 8 destAction +R 8 destParam1 +R 8 destParam2 +R 8 plrlevel +R 8 px +R 8 py +R 8 targx +R 8 targy +R 256 _pName +R 8 pClass +R 8 pBaseStr +R 8 pBaseMag +R 8 pBaseDex +R 8 pBaseVit +R 8 pLevel +R 8 pStatPts +R 32 pExperience +R 32 pGold +R 32 pHPBase +R 32 pMaxHPBase +R 32 pManaBase +R 32 pMaxManaBase +M 37 8 pSplLvl +R 64 pMemSpells +C 7 itemPack InvBody +C 40 itemPack InvList +M 40 8 InvGrid +R 8 _pNumInv +C 8 itemPack SpdList +R 8 pTownWarps +R 8 pDungMsgs +R 8 pLvlLoad +R 8 pBattleNet +R 8 pManaShield +R 8 pDungMsgs2 +R 8 bIsHellfire +R 8 reserved +R 16 wReflections +R 16 reserved +M 10 8 pSplLvl2 +R 16 reserved +R 32 pDiabloKillLevel +R 32 pDifficulty +R 32 pDamAcFlags +R 8 friendlyMode +R 8 isOnSetLevel +M 18 8 reserved diff --git a/test/fixtures/memory_map/item.txt b/test/fixtures/memory_map/item.txt new file mode 100644 index 000000000..7f351e57d --- /dev/null +++ b/test/fixtures/memory_map/item.txt @@ -0,0 +1,75 @@ +R 32 _iSeed +R 16 _iCreateInfo +R 16 alignment +R 32 _itype +R 32 positionX +R 32 positionY +R 32 _iAnimFlag +R 32 _iAnimData +R 32 numberOfFrames +R 32 currentFrame +R 32 _iAnimWidth +R 32 _iAnimWidth2 +R 32 unused +R 8 _iSelFlag +R 24 alignment +R 32 _iPostDraw +R 32 _iIdentified +R 8 _iMagical +R 512 _iName +R 512 _iIName +R 8 _iLoc +R 8 _iClass +R 8 alignment +R 32 _iCurs +R 32 _ivalue +R 32 _iIvalue +R 32 _iMinDam +R 32 _iMaxDam +R 32 _iAC +R 32 _iFlags +R 32 _iMiscId +R 32 _iSpell +R 32 _iCharges +R 32 _iMaxCharges +R 32 _iDurability +R 32 _iMaxDur +R 32 _iPLDam +R 32 _iPLToHit +R 32 _iPLAC +R 32 _iPLStr +R 32 _iPLMag +R 32 _iPLDex +R 32 _iPLVit +R 32 _iPLFR +R 32 _iPLLR +R 32 _iPLMR +R 32 _iPLMana +R 32 _iPLHP +R 32 _iPLDamMod +R 32 _iPLGetHit +R 32 _iPLLight +R 8 _iSplLvlAdd +R 8 _iRequest +R 16 alignment +R 32 _iUid +R 32 _iFMinDam +R 32 _iFMaxDam +R 32 _iLMinDam +R 32 _iLMaxDam +R 32 _iPLEnAc +R 8 _iPrePower +R 8 _iSufPower +R 16 alignment +R 32 _iVAdd1 +R 32 _iVMult1 +R 32 _iVAdd2 +R 32 _iVMult2 +R 8 _iMinStr +R 8 _iMinMag +R 8 _iMinDex +R 8 alignment +R 32 _iStatFlag +R 32 IDidx +R 32 dwBuff +R_HF 32 _iDamAcFlags diff --git a/test/fixtures/memory_map/itemPack.txt b/test/fixtures/memory_map/itemPack.txt new file mode 100644 index 000000000..36418d264 --- /dev/null +++ b/test/fixtures/memory_map/itemPack.txt @@ -0,0 +1,10 @@ +R 32 iSeed +R 16 iCreateInfo +R 16 idx +R 8 bId +R 8 bDur +R 8 bMDur +R 8 bCh +R 8 bMCh +R 16 wValue +R 32 dwBuff diff --git a/test/fixtures/memory_map/level.txt b/test/fixtures/memory_map/level.txt new file mode 100644 index 000000000..0fc802771 --- /dev/null +++ b/test/fixtures/memory_map/level.txt @@ -0,0 +1,19 @@ +M_DL 12544 8 dCorpse +LC 32 NumMonsters +LC 32 ItemCount +LC 32 NumObjects +M_DL 200 32 ActiveMonsters +C_DL NumMonsters monster monsters +M_DL 127 8 ActiveObjects +M_DL 127 8 AvailableObjects +C_DL NumObjects object objects +M 127 8 ActiveItems +M 127 8 AvailableItems +C ItemCount item items +M 12544 8 dFlags +M 12544 8 dItem +M_DL 12544 32 dMonster +M_DL 12544 8 dObject +M_DL 12544 8 dLight +M_DL 12544 8 dPreLight +M_DL 1600 8 AutomapView diff --git a/test/fixtures/memory_map/levelSeed.txt b/test/fixtures/memory_map/levelSeed.txt new file mode 100644 index 000000000..83ab4ff6a --- /dev/null +++ b/test/fixtures/memory_map/levelSeed.txt @@ -0,0 +1,2 @@ +R 32 glSeedTbl +R 32 gnLevelTypeTbl diff --git a/test/fixtures/memory_map/lightning.txt b/test/fixtures/memory_map/lightning.txt new file mode 100644 index 000000000..0420a9eed --- /dev/null +++ b/test/fixtures/memory_map/lightning.txt @@ -0,0 +1,13 @@ +R 32 positionX +R 32 positionY +R 32 _lradius +R 32 _lid +R 32 _ldel +R 32 _lunflag +R 32 unused +R 32 oldX +R 32 oldY +R 32 oldRadius +R 32 offsetX +R 32 offsetY +R 32 _lflags diff --git a/test/fixtures/memory_map/missile.txt b/test/fixtures/memory_map/missile.txt new file mode 100644 index 000000000..40c0406bc --- /dev/null +++ b/test/fixtures/memory_map/missile.txt @@ -0,0 +1,45 @@ +R 32 _mitype +R 32 tileX +R 32 tileY +R 32 offsetX +R 32 offsetY +R 32 velocityX +R 32 velocityY +R 32 startX +R 32 startY +R 32 traveledX +R 32 traveledY +R 32 _mimfnum +R 32 _mispllvl +R 32 _miDelFlag +R 8 _miAnimType +R 24 alignment +R 32 _miAnimFlags +R 32 _miAnimData +R 32 _miAnimDelay +R 32 _miAnimLen +R 32 _miAnimWidth +R 32 _miAnimWidth2 +R 32 _miAnimCnt +R 32 _miAnimAdd +R 32 _miAnimFrame +R 32 _miDrawFlag +R 32 _miLightFlag +R 32 _miPreFlag +R 32 _miUniqTrans +R 32 _mirange +R 32 _misource +R 32 _micaster +R 32 _midam +R 32 _miHitFlag +R 32 _midist +R 32 _mlid +R 32 _mirnd +R 32 var1 +R 32 var2 +R 32 var3 +R 32 var4 +R 32 var5 +R 32 var6 +R 32 var7 +R 32 limitReached diff --git a/test/fixtures/memory_map/monster.txt b/test/fixtures/memory_map/monster.txt new file mode 100644 index 000000000..69ad2585f --- /dev/null +++ b/test/fixtures/memory_map/monster.txt @@ -0,0 +1,76 @@ +R 32 levelType +R 32 mode +R 8 goal +R 24 alignment +R 32 goalVar1 +R 32 goalVar2 +R 32 goalVar3 +R 32 unused +R 8 pathcount +R 24 alignment +R 32 tileX +R 32 tileY +R 32 futureX +R 32 futureY +R 32 oldX +R 32 oldY +R 32 offsetX +R 32 offsetY +R 32 velocityX +R 32 velocityY +R 32 direction +R 32 enemy +R 8 enemyPositionX +R 8 enemyPositionY +R 16 unused +R 32 _mAnimData +R 32 ticksPerFrame +R 32 tickCounterOfCurrentFrame +R 32 numberOfFrames +R 32 currentFrame +R 32 _meflag +R 32 isInvalid +R 32 var1 +R 32 var2 +R 32 var3 +R 32 tempPositionX +R 32 tempPositionY +R 32 offset2X +R 32 offset2Y +R 32 actionFrame +R 32 maxHitPoints +R 32 hitPoints +R 8 ai +R 8 intelligence +R 16 alignment +R 32 flags +R 8 activeForTicks +R 24 alignment +R 32 unused +R 32 lastX +R 32 lastY +R 32 rndItemSeed +R 32 aiSeed +R 32 unused +R 8 uniqueType +R 8 uniqTrans +R 8 corpseId +R 8 whoHit +R 8 level +R 8 alignment +R 16 exp +R 8 toHit +R 8 minDamage +R 8 maxDamage +R 8 toHitSpecial +R 8 minDamageSpecial +R 8 maxDamageSpecial +R 8 armorClass +R 8 alignment +R 16 resistance +R 16 alignment +R 32 talkMsg +R 8 leader +R 8 leaderRelation +R 8 packSize +R 8 lightId diff --git a/test/fixtures/memory_map/object.txt b/test/fixtures/memory_map/object.txt new file mode 100644 index 000000000..979955371 --- /dev/null +++ b/test/fixtures/memory_map/object.txt @@ -0,0 +1,32 @@ +R 32 _otype +R 32 positionX +R 32 positionY +R 32 _oLight +R 32 _oAnimFlag +R 32 _oAnimData +R 32 _oAnimDelay +R 32 _oAnimCnt +R 32 _oAnimLen +R 32 _oAnimFrame +R 32 _oAnimWidth +R 32 _oAnimWidth2 +R 32 _oDelFlag +R 8 _oBreak +R 24 alignment +R 32 _oSolidFlag +R 32 _oMissFlag +R 8 _oSelFlag +R 24 alignment +R 32 _oPreFlag +R 32 _oTrapFlag +R 32 _oDoorFlag +R 32 _olid +R 32 _oRndSeed +R 32 _oVar1 +R 32 _oVar2 +R 32 _oVar3 +R 32 _oVar4 +R 32 _oVar5 +R 32 _oVar6 +R 32 bookMessage +R 32 _oVar8 diff --git a/test/fixtures/memory_map/player.txt b/test/fixtures/memory_map/player.txt new file mode 100644 index 000000000..8159a363b --- /dev/null +++ b/test/fixtures/memory_map/player.txt @@ -0,0 +1,178 @@ +R 32 _pmode +M 25 8 walkpath +R 8 plractive +R 16 alignment +R 32 destAction +R 32 destParam1 +R 32 destParam2 +R 32 destParam3 +R 32 destParam4 +R 32 level +R 32 tileX +R 32 tileY +R 32 futureX +R 32 futureY +R 32 _ptargx +R 32 _ptargy +R 32 lastX +R 32 lastY +R 32 oldX +R 32 oldY +R 32 offsetX +R 32 offsetY +R 32 velocityX +R 32 velocityY +R 32 pdir +R 32 unused +R 32 pfxnum +R 32 pData +R 32 ticksPerFrame +R 32 tickCounterOfCurrentFrame +R 32 numberOfFrames +R 32 currentFrame +R 32 _pAnimWidth +R 32 _pAnimWidth2 +R 32 _peflag +R 32 _plid +R 32 _pvid +R 32 _pSpell +R 8 _pSplType +R 8 _pSplFrom +R 16 alignment +R 32 _pTSpell +R 8 _pTSplType +R 24 alignment +R 32 _pRSpell +R 8 _pRSplType +R 24 alignment +R 32 _pSBkSpell +R 8 _pSBkSplType +M 64 8 spellLevel +R 56 alignment +R 64 _pMemSpells +R 64 _pAblSpells +R 64 _pScrlSpells +R 8 _pSpellFlags +R 24 alignment +M 4 32 _pSplHotKey +M 4 8 _pSplTHotKey +R 32 _pwtype +R 8 _pBlockFlag +R 8 _pInvincible +R 8 _pLightRad +R 8 _pLvlChanging +R 256 _pName +R 8 _pClass +R 24 alignment +R 32 _pStrength +R 32 _pBaseStr +R 32 _pMagic +R 32 _pBaseMag +R 32 _pDexterity +R 32 _pBaseDex +R 32 _pVitality +R 32 _pBaseVit +R 32 _pStatPts +R 32 _pDamageMod +R 32 _pBaseToBlk +R 32 _pHPBase +R 32 _pMaxHPBase +R 32 _pHitPoints +R 32 _pMaxHP +R 32 _pHPPer +R 32 _pManaBase +R 32 _pMaxManaBase +R 32 _pMana +R 32 _pMaxMana +R 32 _pManaPer +R 8 _pLevel +R 8 _pMaxLvl +R 16 alignment +R 32 _pExperience +R 32 _pMaxExp +R 32 _pNextExper +R 8 _pArmorClass +R 8 _pMagResist +R 8 _pFireResist +R 8 _pLghtResist +R 32 _pGold +R 32 _pInfraFlag +R 32 tempPositionX +R 32 tempPositionY +R 32 tempDirection +R 32 spellLevel +R 32 _pVar5 +R 32 offset2.x +R 32 offset2.y +R 32 actionFrame +M_DA 17 8 _pLvlVisited +M_HF 25 8 _pLvlVisited +M_DA 17 8 _pSLvlVisited +M_HF 25 8 _pSLvlVisited +R 16 alignment +R 32 _pGFXLoad +M 8 32 _pNAnim +R 32 _pNFrames +R 32 _pNWidth +M 8 32 _pWAnim +R 32 _pWWidth +M 8 32 _pAAnim +R 32 _pAFrames +R 32 _pAWidth +R 32 _pAFNum +M 8 32 _pLAnim +M 8 32 _pFAnim +M 8 32 _pTAnim +R 32 _pSFrames +R 32 _pSWidth +R 32 _pSFNum +R 32 _pHFrames +M 8 32 _pHAnim +R 32 _pHFrames +R 32 _pHWidth +M 8 32 _pDAnim +R 32 _pDFrames +R 32 _pDWidth +M 8 32 _pBAnim +R 32 _pBFrames +R 32 _pBWidth +C 7 item +C 40 item +R 32 _pNumInv +M 40 8 InvGrid +C 8 item +C 1 item +R 32 _pIMinDam +R 32 _pIMaxDam +R 32 _pIAC +R 32 _pIBonusDam +R 32 _pIBonusToHit +R 32 _pIBonusAC +R 32 _pIBonusDamMod +R 32 alignment +R 64 _pISpells +R 32 _pIFlags +R 32 _pIGetHit +R 8 _pISplLvlAdd +R 8 unused +R 16 alignment +R 32 _pISplDur +R 32 _pIEnAc +R 32 _pIFMinDam +R 32 _pIFMaxDam +R 32 _pILMinDam +R 32 _pILMaxDam +R 32 _pOilType +R 8 pTownWarps +R 8 pDungMsgs +R 8 pLvlLoad +R 8 pDungMsgs2 +R 8 pManaShield +R 8 pOriginalCathedral +R 16 unused +R 16 wReflections +R 112 unused +R 32 pDiabloKillLevel +R 32 pDifficulty +R 32 pDamAcFlags +R 160 unused diff --git a/test/fixtures/memory_map/portal.txt b/test/fixtures/memory_map/portal.txt new file mode 100644 index 000000000..76a13004f --- /dev/null +++ b/test/fixtures/memory_map/portal.txt @@ -0,0 +1,6 @@ +R 32 open +R 32 positionX +R 32 positionY +R 32 level +R 32 ltype +R 32 setlvl diff --git a/test/fixtures/memory_map/quest.txt b/test/fixtures/memory_map/quest.txt new file mode 100644 index 000000000..c59da838b --- /dev/null +++ b/test/fixtures/memory_map/quest.txt @@ -0,0 +1,21 @@ +R 8 _qlevel +R 8 _qtype +R 8 _qactive +R 8 _qlvltype +R 32 positionX +R 32 positionY +R 8 _qslvl +R 8 _qidx +R_DA 8 _qmsg +R_HF 16 alignment +R_HF 32 _qmsg +R 8 _qvar1 +R 8 _qvar2 +R 16 alignment +R_DA 8 alignment +R 32 _qlog +R 32 ReturnLvlPositionX +R 32 ReturnLvlPositionY +R 32 ReturnLevel +R 32 ReturnLevelType +R 32 DoomQuestState diff --git a/test/timedemo_test.cpp b/test/timedemo_test.cpp index 686cd2285..57a0d4f66 100644 --- a/test/timedemo_test.cpp +++ b/test/timedemo_test.cpp @@ -52,7 +52,7 @@ void RunTimedemo(std::string timedemoFolderName) StartGame(false, true); - HeroCompareResult result = pfile_compare_hero_demo(demoNumber); + HeroCompareResult result = pfile_compare_hero_demo(demoNumber, true); ASSERT_EQ(result.status, HeroCompareResult::Same) << result.message; ASSERT_FALSE(gbRunGame); gbRunGame = false;