From bd70b6fabd9b86c1b9b4d67e05d7c28b248fd58f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 24 Feb 2023 16:15:45 +0200 Subject: [PATCH] Unicode conversion functions now require source encoding --- client/renderSDL/CBitmapFont.cpp | 4 +- client/renderSDL/CBitmapHanFont.cpp | 4 +- lib/CGeneralTextHandler.cpp | 2 +- lib/CGeneralTextHandler.h | 5 +- lib/CModHandler.cpp | 4 +- lib/TextOperations.cpp | 10 - lib/TextOperations.h | 2 - lib/filesystem/CBinaryReader.cpp | 7 +- lib/filesystem/CBinaryReader.h | 3 +- lib/mapObjects/ObjectTemplate.cpp | 2 +- lib/mapping/CCampaignHandler.cpp | 15 +- lib/mapping/CCampaignHandler.h | 2 + lib/mapping/MapFormatH3M.cpp | 555 ++++++++++++++-------------- lib/mapping/MapFormatH3M.h | 17 +- 14 files changed, 319 insertions(+), 313 deletions(-) diff --git a/client/renderSDL/CBitmapFont.cpp b/client/renderSDL/CBitmapFont.cpp index b26fd71b6..6d85813c0 100644 --- a/client/renderSDL/CBitmapFont.cpp +++ b/client/renderSDL/CBitmapFont.cpp @@ -55,7 +55,7 @@ size_t CBitmapFont::getLineHeight() const size_t CBitmapFont::getGlyphWidth(const char * data) const { - std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0]))); + std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0])), "ASCII"); if (localChar.size() == 1) { @@ -133,7 +133,7 @@ void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, co for(size_t i=0; irenderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY); @@ -115,7 +115,7 @@ size_t CBitmapHanFont::getLineHeight() const size_t CBitmapHanFont::getGlyphWidth(const char * data) const { - std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0]))); + std::string localChar = TextOperations::fromUnicode(std::string(data, TextOperations::getUnicodeCharacterSize(data[0])), "GBK"); if (localChar.size() == 1) return fallback->getGlyphWidth(data); diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index 64284c37a..47cda45d8 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/lib/CGeneralTextHandler.cpp @@ -190,7 +190,7 @@ std::string CLegacyConfigParser::readString() std::string str = readRawString(); if (TextOperations::isValidASCII(str)) return str; - return TextOperations::toUnicode(str); + return TextOperations::toUnicode(str, fileEncoding); } float CLegacyConfigParser::readNumber() diff --git a/lib/CGeneralTextHandler.h b/lib/CGeneralTextHandler.h index b32511c75..447a808b4 100644 --- a/lib/CGeneralTextHandler.h +++ b/lib/CGeneralTextHandler.h @@ -17,12 +17,12 @@ class JsonNode; /// Parser for any text files from H3 class DLL_LINKAGE CLegacyConfigParser { + std::string fileEncoding; + std::unique_ptr data; char * curr; char * end; - void init(const std::unique_ptr & input); - /// extracts part of quoted string. std::string extractQuotedPart(); @@ -56,6 +56,7 @@ public: bool endLine(); explicit CLegacyConfigParser(std::string URI); +private: explicit CLegacyConfigParser(const std::unique_ptr & input); }; diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 6da2329bf..98e677af6 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -943,8 +943,8 @@ std::vector CModHandler::getModList(std::string path) bool CModHandler::isScopeReserved(const TModID & scope) { - static const std::array reservedScopes = { - "core", "map", "game" + static const std::array reservedScopes = { + "core", "map", "game", "root", "saves", "config" }; return std::find(reservedScopes.begin(), reservedScopes.end(), scope) != reservedScopes.end(); diff --git a/lib/TextOperations.cpp b/lib/TextOperations.cpp index 38f0c4bd5..6733e9598 100644 --- a/lib/TextOperations.cpp +++ b/lib/TextOperations.cpp @@ -112,21 +112,11 @@ bool TextOperations::isValidUnicodeString(const char * data, size_t size) return true; } -std::string TextOperations::toUnicode(const std::string &text) -{ - return toUnicode(text, CGeneralTextHandler::getInstalledEncoding()); -} - std::string TextOperations::toUnicode(const std::string &text, const std::string &encoding) { return boost::locale::conv::to_utf(text, encoding); } -std::string TextOperations::fromUnicode(const std::string & text) -{ - return fromUnicode(text, CGeneralTextHandler::getInstalledEncoding()); -} - std::string TextOperations::fromUnicode(const std::string &text, const std::string &encoding) { return boost::locale::conv::from_utf(text, encoding); diff --git a/lib/TextOperations.h b/lib/TextOperations.h index df33738b9..ba72c6da2 100644 --- a/lib/TextOperations.h +++ b/lib/TextOperations.h @@ -31,12 +31,10 @@ namespace TextOperations bool DLL_LINKAGE isValidUnicodeString(const char * data, size_t size); /// converts text to UTF-8 from specified encoding or from one specified in settings - std::string DLL_LINKAGE toUnicode(const std::string & text); std::string DLL_LINKAGE toUnicode(const std::string & text, const std::string & encoding); /// converts text from unicode to specified encoding or to one specified in settings /// NOTE: usage of these functions should be avoided if possible - std::string DLL_LINKAGE fromUnicode(const std::string & text); std::string DLL_LINKAGE fromUnicode(const std::string & text, const std::string & encoding); ///delete specified amount of UTF-8 characters from right diff --git a/lib/filesystem/CBinaryReader.cpp b/lib/filesystem/CBinaryReader.cpp index 4e4594450..d697c2342 100644 --- a/lib/filesystem/CBinaryReader.cpp +++ b/lib/filesystem/CBinaryReader.cpp @@ -86,7 +86,7 @@ INSTANTIATE(si64, readInt64) #undef INSTANTIATE -std::string CBinaryReader::readString() +std::string CBinaryReader::readBaseString() { unsigned int len = readUInt32(); assert(len <= 500000); //not too long @@ -95,10 +95,7 @@ std::string CBinaryReader::readString() std::string ret; ret.resize(len); read(reinterpret_cast(&ret[0]), len); - //FIXME: any need to move this into separate "read localized string" method? - if (TextOperations::isValidASCII(ret)) - return ret; - return TextOperations::toUnicode(ret); + return ret; } return ""; diff --git a/lib/filesystem/CBinaryReader.h b/lib/filesystem/CBinaryReader.h index c5a5f2829..972401369 100644 --- a/lib/filesystem/CBinaryReader.h +++ b/lib/filesystem/CBinaryReader.h @@ -73,7 +73,8 @@ public: ui64 readUInt64(); si64 readInt64(); - std::string readString(); + /// Reads string without any encoding conversions + std::string readBaseString(); inline bool readBool() { diff --git a/lib/mapObjects/ObjectTemplate.cpp b/lib/mapObjects/ObjectTemplate.cpp index bbca6dbb5..ad022cdb0 100644 --- a/lib/mapObjects/ObjectTemplate.cpp +++ b/lib/mapObjects/ObjectTemplate.cpp @@ -198,7 +198,7 @@ void ObjectTemplate::readMsk() void ObjectTemplate::readMap(CBinaryReader & reader) { - animationFile = reader.readString(); + animationFile = reader.readBaseString(); setSize(8, 6); ui8 blockMask[6]; diff --git a/lib/mapping/CCampaignHandler.cpp b/lib/mapping/CCampaignHandler.cpp index ce441b4e4..9c05c9999 100644 --- a/lib/mapping/CCampaignHandler.cpp +++ b/lib/mapping/CCampaignHandler.cpp @@ -110,14 +110,19 @@ std::unique_ptr CCampaignHandler::getCampaign( const std::string & na return ret; } +std::string CCampaignHandler::readLocalizedString(CBinaryReader & reader) +{ + return reader.readBaseString(); +} + CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader ) { CCampaignHeader ret; ret.version = reader.readUInt32(); ret.mapVersion = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19] - ret.name = reader.readString(); - ret.description = reader.readString(); + ret.name = readLocalizedString(reader); + ret.description = readLocalizedString(reader); if (ret.version > CampaignVersion::RoE) ret.difficultyChoosenByPlayer = reader.readInt8(); else @@ -136,14 +141,14 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read { ret.prologVideo = reader.readUInt8(); ret.prologMusic = reader.readUInt8(); - ret.prologText = reader.readString(); + ret.prologText = readLocalizedString(reader); } return ret; }; CCampaignScenario ret; ret.conquered = false; - ret.mapName = reader.readString(); + ret.mapName = readLocalizedString(reader); ret.packedMapSize = reader.readUInt32(); if(mapVersion == 18)//unholy alliance { @@ -155,7 +160,7 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read } ret.regionColor = reader.readUInt8(); ret.difficulty = reader.readUInt8(); - ret.regionText = reader.readString(); + ret.regionText = readLocalizedString(reader); ret.prolog = prologEpilogReader(); ret.epilog = prologEpilogReader(); diff --git a/lib/mapping/CCampaignHandler.h b/lib/mapping/CCampaignHandler.h index 98cce5f76..7a1435faf 100644 --- a/lib/mapping/CCampaignHandler.h +++ b/lib/mapping/CCampaignHandler.h @@ -218,6 +218,8 @@ class DLL_LINKAGE CCampaignHandler { std::vector scenariosCountPerCampaign; + static std::string readLocalizedString(CBinaryReader & reader); + static CCampaignHeader readHeaderFromMemory(CBinaryReader & reader); static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, int version, int mapVersion ); static CScenarioTravel readScenarioTravelFromMemory(CBinaryReader & reader, int version); diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 2a2934646..9cc36c2f2 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -16,6 +16,7 @@ #include "../CStopWatch.h" #include "../filesystem/Filesystem.h" +#include "../filesystem/CBinaryReader.h" #include "../spells/CSpellHandler.h" #include "../CSkillHandler.h" #include "../CCreatureHandler.h" @@ -31,10 +32,12 @@ VCMI_LIB_NAMESPACE_BEGIN - const bool CMapLoaderH3M::IS_PROFILING_ENABLED = false; -CMapLoaderH3M::CMapLoaderH3M(CInputStream * stream) : map(nullptr), reader(stream),inputStream(stream) +CMapLoaderH3M::CMapLoaderH3M(CInputStream * stream) + : map(nullptr) + , reader(new CBinaryReader(stream)) + , inputStream(stream) { } @@ -144,7 +147,7 @@ void CMapLoaderH3M::readHeader() //} // Map version - mapHeader->version = static_cast(reader.readUInt32()); + mapHeader->version = static_cast(reader->readUInt32()); if(mapHeader->version != EMapFormat::ROE && mapHeader->version != EMapFormat::AB && mapHeader->version != EMapFormat::SOD && mapHeader->version != EMapFormat::WOG) { @@ -152,15 +155,15 @@ void CMapLoaderH3M::readHeader() } // Read map name, description, dimensions,... - mapHeader->areAnyPlayers = reader.readBool(); - mapHeader->height = mapHeader->width = reader.readUInt32(); - mapHeader->twoLevel = reader.readBool(); - mapHeader->name = reader.readString(); - mapHeader->description = reader.readString(); - mapHeader->difficulty = reader.readInt8(); + mapHeader->areAnyPlayers = reader->readBool(); + mapHeader->height = mapHeader->width = reader->readUInt32(); + mapHeader->twoLevel = reader->readBool(); + mapHeader->name = readLocalizedString(); + mapHeader->description = readLocalizedString(); + mapHeader->difficulty = reader->readInt8(); if(mapHeader->version != EMapFormat::ROE) { - mapHeader->levelLimit = reader.readUInt8(); + mapHeader->levelLimit = reader->readUInt8(); } else { @@ -177,8 +180,8 @@ void CMapLoaderH3M::readPlayerInfo() { for(int i = 0; i < mapHeader->players.size(); ++i) { - mapHeader->players[i].canHumanPlay = reader.readBool(); - mapHeader->players[i].canComputerPlay = reader.readBool(); + mapHeader->players[i].canHumanPlay = reader->readBool(); + mapHeader->players[i].canComputerPlay = reader->readBool(); // If nobody can play with this player if((!(mapHeader->players[i].canHumanPlay || mapHeader->players[i].canComputerPlay))) @@ -187,23 +190,23 @@ void CMapLoaderH3M::readPlayerInfo() { case EMapFormat::SOD: case EMapFormat::WOG: - reader.skip(13); + reader->skip(13); break; case EMapFormat::AB: - reader.skip(12); + reader->skip(12); break; case EMapFormat::ROE: - reader.skip(6); + reader->skip(6); break; } continue; } - mapHeader->players[i].aiTactic = static_cast(reader.readUInt8()); + mapHeader->players[i].aiTactic = static_cast(reader->readUInt8()); if(mapHeader->version == EMapFormat::SOD || mapHeader->version == EMapFormat::WOG) { - mapHeader->players[i].p7 = reader.readUInt8(); + mapHeader->players[i].p7 = reader->readUInt8(); } else { @@ -211,16 +214,16 @@ void CMapLoaderH3M::readPlayerInfo() } // Factions this player can choose - ui16 allowedFactions = reader.readUInt8(); + ui16 allowedFactions = reader->readUInt8(); // How many factions will be read from map ui16 totalFactions = GameConstants::F_NUMBER; if(mapHeader->version != EMapFormat::ROE) - allowedFactions += reader.readUInt8() * 256; // 256 = 2^8 = 0b100000000 + allowedFactions += reader->readUInt8() * 256; // 256 = 2^8 = 0b100000000 else totalFactions--; //exclude conflux for ROE - const bool isFactionRandom = mapHeader->players[i].isFactionRandom = reader.readBool(); + const bool isFactionRandom = mapHeader->players[i].isFactionRandom = reader->readBool(); const ui16 allFactionsMask = (mapHeader->version == EMapFormat::ROE) ? 0b11111111 // 8 towns for ROE : 0b111111111; // 8 towns + Conflux @@ -238,13 +241,13 @@ void CMapLoaderH3M::readPlayerInfo() } } - mapHeader->players[i].hasMainTown = reader.readBool(); + mapHeader->players[i].hasMainTown = reader->readBool(); if(mapHeader->players[i].hasMainTown) { if(mapHeader->version != EMapFormat::ROE) { - mapHeader->players[i].generateHeroAtMainTown = reader.readBool(); - mapHeader->players[i].generateHero = reader.readBool(); + mapHeader->players[i].generateHeroAtMainTown = reader->readBool(); + mapHeader->players[i].generateHero = reader->readBool(); } else { @@ -255,30 +258,30 @@ void CMapLoaderH3M::readPlayerInfo() mapHeader->players[i].posOfMainTown = readInt3(); } - mapHeader->players[i].hasRandomHero = reader.readBool(); - mapHeader->players[i].mainCustomHeroId = reader.readUInt8(); + mapHeader->players[i].hasRandomHero = reader->readBool(); + mapHeader->players[i].mainCustomHeroId = reader->readUInt8(); if(mapHeader->players[i].mainCustomHeroId != 0xff) { - mapHeader->players[i].mainCustomHeroPortrait = reader.readUInt8(); + mapHeader->players[i].mainCustomHeroPortrait = reader->readUInt8(); if (mapHeader->players[i].mainCustomHeroPortrait == 0xff) mapHeader->players[i].mainCustomHeroPortrait = -1; //correct 1-byte -1 (0xff) into 4-byte -1 - mapHeader->players[i].mainCustomHeroName = reader.readString(); + mapHeader->players[i].mainCustomHeroName = readLocalizedString(); } else mapHeader->players[i].mainCustomHeroId = -1; //correct 1-byte -1 (0xff) into 4-byte -1 if(mapHeader->version != EMapFormat::ROE) { - mapHeader->players[i].powerPlaceholders = reader.readUInt8(); //unknown byte - int heroCount = reader.readUInt8(); - reader.skip(3); + mapHeader->players[i].powerPlaceholders = reader->readUInt8(); //unknown byte + int heroCount = reader->readUInt8(); + reader->skip(3); for(int pp = 0; pp < heroCount; ++pp) { SHeroName vv; - vv.heroId = reader.readUInt8(); - vv.heroName = reader.readString(); + vv.heroId = reader->readUInt8(); + vv.heroName = readLocalizedString(); mapHeader->players[i].heroesNames.push_back(vv); } @@ -301,7 +304,7 @@ void CMapLoaderH3M::readVictoryLossConditions() { mapHeader->triggeredEvents.clear(); - auto vicCondition = static_cast(reader.readUInt8()); + auto vicCondition = static_cast(reader->readUInt8()); EventCondition victoryCondition(EventCondition::STANDARD_WIN); EventCondition defeatCondition(EventCondition::DAYS_WITHOUT_TOWN); @@ -341,8 +344,8 @@ void CMapLoaderH3M::readVictoryLossConditions() mapHeader->victoryIconIndex = static_cast(vicCondition); mapHeader->victoryMessage = VLC->generaltexth->victoryConditions[static_cast(vicCondition) + 1]; - bool allowNormalVictory = reader.readBool(); - bool appliesToAI = reader.readBool(); + bool allowNormalVictory = reader->readBool(); + bool appliesToAI = reader->readBool(); if (allowNormalVictory) { @@ -360,9 +363,9 @@ void CMapLoaderH3M::readVictoryLossConditions() case EVictoryConditionType::ARTIFACT: { EventCondition cond(EventCondition::HAVE_ARTIFACT); - cond.objectType = reader.readUInt8(); + cond.objectType = reader->readUInt8(); if (mapHeader->version != EMapFormat::ROE) - reader.skip(1); + reader->skip(1); specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[281]; specialVictory.onFulfill = VLC->generaltexth->allTexts[280]; @@ -372,10 +375,10 @@ void CMapLoaderH3M::readVictoryLossConditions() case EVictoryConditionType::GATHERTROOP: { EventCondition cond(EventCondition::HAVE_CREATURES); - cond.objectType = reader.readUInt8(); + cond.objectType = reader->readUInt8(); if (mapHeader->version != EMapFormat::ROE) - reader.skip(1); - cond.value = reader.readUInt32(); + reader->skip(1); + cond.value = reader->readUInt32(); specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[277]; specialVictory.onFulfill = VLC->generaltexth->allTexts[276]; @@ -385,8 +388,8 @@ void CMapLoaderH3M::readVictoryLossConditions() case EVictoryConditionType::GATHERRESOURCE: { EventCondition cond(EventCondition::HAVE_RESOURCES); - cond.objectType = reader.readUInt8(); - cond.value = reader.readUInt32(); + cond.objectType = reader->readUInt8(); + cond.value = reader->readUInt32(); specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[279]; specialVictory.onFulfill = VLC->generaltexth->allTexts[278]; @@ -398,9 +401,9 @@ void CMapLoaderH3M::readVictoryLossConditions() EventExpression::OperatorAll oper; EventCondition cond(EventCondition::HAVE_BUILDING); cond.position = readInt3(); - cond.objectType = BuildingID::TOWN_HALL + reader.readUInt8(); + cond.objectType = BuildingID::TOWN_HALL + reader->readUInt8(); oper.expressions.emplace_back(cond); - cond.objectType = BuildingID::FORT + reader.readUInt8(); + cond.objectType = BuildingID::FORT + reader->readUInt8(); oper.expressions.emplace_back(cond); specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[283]; @@ -478,7 +481,7 @@ void CMapLoaderH3M::readVictoryLossConditions() case EVictoryConditionType::TRANSPORTITEM: { EventCondition cond(EventCondition::TRANSPORT); - cond.objectType = reader.readUInt8(); + cond.objectType = reader->readUInt8(); cond.position = readInt3(); specialVictory.effect.toOtherMessage = VLC->generaltexth->allTexts[293]; @@ -512,7 +515,7 @@ void CMapLoaderH3M::readVictoryLossConditions() } // Read loss conditions - auto lossCond = static_cast(reader.readUInt8()); + auto lossCond = static_cast(reader->readUInt8()); if (lossCond == ELossConditionType::LOSSSTANDARD) { mapHeader->defeatIconIndex = 3; @@ -558,7 +561,7 @@ void CMapLoaderH3M::readVictoryLossConditions() case ELossConditionType::TIMEEXPIRES: { EventCondition cond(EventCondition::DAYS_PASSED); - cond.value = reader.readUInt16(); + cond.value = reader->readUInt16(); specialDefeat.onFulfill = VLC->generaltexth->allTexts[254]; specialDefeat.trigger = EventExpression(cond); @@ -587,13 +590,13 @@ void CMapLoaderH3M::readVictoryLossConditions() void CMapLoaderH3M::readTeamInfo() { - mapHeader->howManyTeams = reader.readUInt8(); + mapHeader->howManyTeams = reader->readUInt8(); if(mapHeader->howManyTeams > 0) { // Teams for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i) { - mapHeader->players[i].team = TeamID(reader.readUInt8()); + mapHeader->players[i].team = TeamID(reader->readUInt8()); } } else @@ -620,15 +623,15 @@ void CMapLoaderH3M::readAllowedHeroes() // Probably reserved for further heroes if(mapHeader->version > EMapFormat::ROE) { - int placeholdersQty = reader.readUInt32(); + int placeholdersQty = reader->readUInt32(); - reader.skip(placeholdersQty * 1); + reader->skip(placeholdersQty * 1); // std::vector placeholdedHeroes; // // for(int p = 0; p < placeholdersQty; ++p) // { -// placeholdedHeroes.push_back(reader.readUInt8()); +// placeholdedHeroes.push_back(reader->readUInt8()); // } } } @@ -638,19 +641,19 @@ void CMapLoaderH3M::readDisposedHeroes() // Reading disposed heroes (20 bytes) if(map->version >= EMapFormat::SOD) { - ui8 disp = reader.readUInt8(); + ui8 disp = reader->readUInt8(); map->disposedHeroes.resize(disp); for(int g = 0; g < disp; ++g) { - map->disposedHeroes[g].heroId = reader.readUInt8(); - map->disposedHeroes[g].portrait = reader.readUInt8(); - map->disposedHeroes[g].name = reader.readString(); - map->disposedHeroes[g].players = reader.readUInt8(); + map->disposedHeroes[g].heroId = reader->readUInt8(); + map->disposedHeroes[g].portrait = reader->readUInt8(); + map->disposedHeroes[g].name = readLocalizedString(); + map->disposedHeroes[g].players = reader->readUInt8(); } } //omitting NULLS - reader.skip(31); + reader->skip(31); } void CMapLoaderH3M::readAllowedArtifacts() @@ -727,13 +730,13 @@ void CMapLoaderH3M::readAllowedSpellsAbilities() void CMapLoaderH3M::readRumors() { - int rumNr = reader.readUInt32(); + int rumNr = reader->readUInt32(); for(int it = 0; it < rumNr; it++) { Rumor ourRumor; - ourRumor.name = reader.readString(); - ourRumor.text = reader.readString(); + ourRumor.name = readLocalizedString(); + ourRumor.text = readLocalizedString(); map->rumors.push_back(ourRumor); } } @@ -748,58 +751,58 @@ void CMapLoaderH3M::readPredefinedHeroes() // Disposed heroes for(int z = 0; z < GameConstants::HEROES_QUANTITY; z++) { - int custom = reader.readUInt8(); + int custom = reader->readUInt8(); if(!custom) continue; auto * hero = new CGHeroInstance(); hero->ID = Obj::HERO; hero->subID = z; - bool hasExp = reader.readBool(); + bool hasExp = reader->readBool(); if(hasExp) { - hero->exp = reader.readUInt32(); + hero->exp = reader->readUInt32(); } else { hero->exp = 0; } - bool hasSecSkills = reader.readBool(); + bool hasSecSkills = reader->readBool(); if(hasSecSkills) { - int howMany = reader.readUInt32(); + int howMany = reader->readUInt32(); hero->secSkills.resize(howMany); for(int yy = 0; yy < howMany; ++yy) { - hero->secSkills[yy].first = SecondarySkill(reader.readUInt8()); - hero->secSkills[yy].second = reader.readUInt8(); + hero->secSkills[yy].first = SecondarySkill(reader->readUInt8()); + hero->secSkills[yy].second = reader->readUInt8(); } } loadArtifactsOfHero(hero); - bool hasCustomBio = reader.readBool(); + bool hasCustomBio = reader->readBool(); if(hasCustomBio) { - hero->biographyCustom = reader.readString(); + hero->biographyCustom = readLocalizedString(); } // 0xFF is default, 00 male, 01 female - hero->sex = reader.readUInt8(); + hero->sex = reader->readUInt8(); - bool hasCustomSpells = reader.readBool(); + bool hasCustomSpells = reader->readBool(); if(hasCustomSpells) { readSpells(hero->spells); } - bool hasCustomPrimSkills = reader.readBool(); + bool hasCustomPrimSkills = reader->readBool(); if(hasCustomPrimSkills) { for(int xx = 0; xx < GameConstants::PRIMARY_SKILLS; xx++) { - hero->pushPrimSkill(static_cast(xx), reader.readUInt8()); + hero->pushPrimSkill(static_cast(xx), reader->readUInt8()); } } map->predefinedHeroes.emplace_back(hero); @@ -813,7 +816,7 @@ void CMapLoaderH3M::readPredefinedHeroes() void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero) { - bool artSet = reader.readBool(); + bool artSet = reader->readBool(); // True if artifact set is not default (hero has some artifacts) if(artSet) @@ -854,12 +857,12 @@ void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero) } else { - reader.skip(1); + reader->skip(1); } // bag artifacts //20 // number of artifacts in hero's bag - int amount = reader.readUInt16(); + int amount = reader->readUInt16(); for(int ss = 0; ss < amount; ++ss) { loadArtifactToSlot(hero, GameConstants::BACKPACK_START + static_cast(hero->artifactsInBackpack.size())); @@ -874,11 +877,11 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot) if(map->version == EMapFormat::ROE) { - aid = ArtifactID(reader.readUInt8()); + aid = ArtifactID(reader->readUInt8()); } else { - aid = ArtifactID(reader.readUInt16()); + aid = ArtifactID(reader->readUInt16()); } bool isArt = aid != artmask; @@ -934,13 +937,13 @@ void CMapLoaderH3M::readTerrain() for(pos.x = 0; pos.x < map->width; pos.x++) { auto & tile = map->getTile(pos); - tile.terType = const_cast(VLC->terrainTypeHandler->getByIndex(reader.readUInt8())); - tile.terView = reader.readUInt8(); - tile.riverType = const_cast(VLC->riverTypeHandler->getByIndex(reader.readUInt8())); - tile.riverDir = reader.readUInt8(); - tile.roadType = const_cast(VLC->roadTypeHandler->getByIndex(reader.readUInt8())); - tile.roadDir = reader.readUInt8(); - tile.extTileFlags = reader.readUInt8(); + tile.terType = const_cast(VLC->terrainTypeHandler->getByIndex(reader->readUInt8())); + tile.terView = reader->readUInt8(); + tile.riverType = const_cast(VLC->riverTypeHandler->getByIndex(reader->readUInt8())); + tile.riverDir = reader->readUInt8(); + tile.roadType = const_cast(VLC->roadTypeHandler->getByIndex(reader->readUInt8())); + tile.roadDir = reader->readUInt8(); + tile.extTileFlags = reader->readUInt8(); tile.blocked = !tile.terType->isPassable(); tile.visitable = false; @@ -952,7 +955,7 @@ void CMapLoaderH3M::readTerrain() void CMapLoaderH3M::readDefInfo() { - int defAmount = reader.readUInt32(); + int defAmount = reader->readUInt32(); templates.reserve(defAmount); @@ -960,14 +963,14 @@ void CMapLoaderH3M::readDefInfo() for(int idd = 0; idd < defAmount; ++idd) { auto * tmpl = new ObjectTemplate; - tmpl->readMap(reader); + tmpl->readMap(*reader); templates.push_back(std::shared_ptr(tmpl)); } } void CMapLoaderH3M::readObjects() { - int howManyObjs = reader.readUInt32(); + int howManyObjs = reader->readUInt32(); for(int ww = 0; ww < howManyObjs; ++ww) { @@ -975,11 +978,11 @@ void CMapLoaderH3M::readObjects() int3 objPos = readInt3(); - int defnum = reader.readUInt32(); + int defnum = reader->readUInt32(); ObjectInstanceID idToBeGiven = ObjectInstanceID(static_cast(map->objects.size())); std::shared_ptr objTempl = templates.at(defnum); - reader.skip(5); + reader->skip(5); switch(objTempl->id) { @@ -990,55 +993,55 @@ void CMapLoaderH3M::readObjects() readMessageAndGuards(evnt->message, evnt); - evnt->gainedExp = reader.readUInt32(); - evnt->manaDiff = reader.readUInt32(); - evnt->moraleDiff = reader.readInt8(); - evnt->luckDiff = reader.readInt8(); + evnt->gainedExp = reader->readUInt32(); + evnt->manaDiff = reader->readUInt32(); + evnt->moraleDiff = reader->readInt8(); + evnt->luckDiff = reader->readInt8(); readResourses(evnt->resources); evnt->primskills.resize(GameConstants::PRIMARY_SKILLS); for(int x = 0; x < 4; ++x) { - evnt->primskills[x] = static_cast(reader.readUInt8()); + evnt->primskills[x] = static_cast(reader->readUInt8()); } - int gabn = reader.readUInt8(); // Number of gained abilities + int gabn = reader->readUInt8(); // Number of gained abilities for(int oo = 0; oo < gabn; ++oo) { - evnt->abilities.emplace_back(reader.readUInt8()); - evnt->abilityLevels.push_back(reader.readUInt8()); + evnt->abilities.emplace_back(reader->readUInt8()); + evnt->abilityLevels.push_back(reader->readUInt8()); } - int gart = reader.readUInt8(); // Number of gained artifacts + int gart = reader->readUInt8(); // Number of gained artifacts for(int oo = 0; oo < gart; ++oo) { if(map->version == EMapFormat::ROE) { - evnt->artifacts.emplace_back(reader.readUInt8()); + evnt->artifacts.emplace_back(reader->readUInt8()); } else { - evnt->artifacts.emplace_back(reader.readUInt16()); + evnt->artifacts.emplace_back(reader->readUInt16()); } } - int gspel = reader.readUInt8(); // Number of gained spells + int gspel = reader->readUInt8(); // Number of gained spells for(int oo = 0; oo < gspel; ++oo) { - evnt->spells.emplace_back(reader.readUInt8()); + evnt->spells.emplace_back(reader->readUInt8()); } - int gcre = reader.readUInt8(); //number of gained creatures + int gcre = reader->readUInt8(); //number of gained creatures readCreatureSet(&evnt->creatures, gcre); - reader.skip(8); - evnt->availableFor = reader.readUInt8(); - evnt->computerActivate = reader.readUInt8(); - evnt->removeAfterVisit = reader.readUInt8(); + reader->skip(8); + evnt->availableFor = reader->readUInt8(); + evnt->computerActivate = reader->readUInt8(); + evnt->removeAfterVisit = reader->readUInt8(); evnt->humanActivate = true; - reader.skip(4); + reader->skip(4); break; } case Obj::HERO: @@ -1063,32 +1066,32 @@ void CMapLoaderH3M::readObjects() if(map->version > EMapFormat::ROE) { - cre->identifier = reader.readUInt32(); + cre->identifier = reader->readUInt32(); map->questIdentifierToId[cre->identifier] = idToBeGiven; } auto * hlp = new CStackInstance(); - hlp->count = reader.readUInt16(); + hlp->count = reader->readUInt16(); //type will be set during initialization cre->putStack(SlotID(0), hlp); - cre->character = reader.readUInt8(); + cre->character = reader->readUInt8(); - bool hasMessage = reader.readBool(); + bool hasMessage = reader->readBool(); if(hasMessage) { - cre->message = reader.readString(); + cre->message = readLocalizedString(); readResourses(cre->resources); int artID = 0; if (map->version == EMapFormat::ROE) { - artID = reader.readUInt8(); + artID = reader->readUInt8(); } else { - artID = reader.readUInt16(); + artID = reader->readUInt16(); } if(map->version == EMapFormat::ROE) @@ -1114,9 +1117,9 @@ void CMapLoaderH3M::readObjects() } } } - cre->neverFlees = reader.readUInt8(); - cre->notGrowingTeam =reader.readUInt8(); - reader.skip(2); + cre->neverFlees = reader->readUInt8(); + cre->notGrowingTeam =reader->readUInt8(); + reader->skip(2); break; } case Obj::OCEAN_BOTTLE: @@ -1124,8 +1127,8 @@ void CMapLoaderH3M::readObjects() { auto * sb = new CGSignBottle(); nobj = sb; - sb->message = reader.readString(); - reader.skip(4); + sb->message = readLocalizedString(); + reader->skip(4); break; } case Obj::SEER_HUT: @@ -1143,7 +1146,7 @@ void CMapLoaderH3M::readObjects() { for(int i = 0 ; i < 4; ++i) { - ui8 c = reader.readUInt8(); + ui8 c = reader->readUInt8(); for(int yy = 0; yy < 8; ++yy) { if(i * 8 + yy < GameConstants::SKILL_QUANTITY) @@ -1174,9 +1177,9 @@ void CMapLoaderH3M::readObjects() { auto * sch = new CGScholar(); nobj = sch; - sch->bonusType = static_cast(reader.readUInt8()); - sch->bonusID = reader.readUInt8(); - reader.skip(6); + sch->bonusType = static_cast(reader->readUInt8()); + sch->bonusID = reader->readUInt8(); + reader->skip(6); break; } case Obj::GARRISON: @@ -1184,18 +1187,18 @@ void CMapLoaderH3M::readObjects() { auto * gar = new CGGarrison(); nobj = gar; - nobj->setOwner(PlayerColor(reader.readUInt8())); - reader.skip(3); + nobj->setOwner(PlayerColor(reader->readUInt8())); + reader->skip(3); readCreatureSet(gar, 7); if(map->version > EMapFormat::ROE) { - gar->removableUnits = reader.readBool(); + gar->removableUnits = reader->readBool(); } else { gar->removableUnits = true; } - reader.skip(8); + reader->skip(8); break; } case Obj::ARTIFACT: @@ -1215,7 +1218,7 @@ void CMapLoaderH3M::readObjects() if(objTempl->id == Obj::SPELL_SCROLL) { - spellID = reader.readUInt32(); + spellID = reader->readUInt32(); artID = ArtifactID::SPELL_SCROLL; } else if(objTempl->id == Obj::ARTIFACT) @@ -1235,13 +1238,13 @@ void CMapLoaderH3M::readObjects() readMessageAndGuards(res->message, res); - res->amount = reader.readUInt32(); + res->amount = reader->readUInt32(); if(objTempl->subid == Res::GOLD) { // Gold is multiplied by 100. res->amount *= 100; } - reader.skip(4); + reader->skip(4); break; } case Obj::RANDOM_TOWN: @@ -1254,8 +1257,8 @@ void CMapLoaderH3M::readObjects() case Obj::ABANDONED_MINE: { nobj = new CGMine(); - nobj->setOwner(PlayerColor(reader.readUInt8())); - reader.skip(3); + nobj->setOwner(PlayerColor(reader->readUInt8())); + reader->skip(3); break; } case Obj::CREATURE_GENERATOR1: @@ -1264,8 +1267,8 @@ void CMapLoaderH3M::readObjects() case Obj::CREATURE_GENERATOR4: { nobj = new CGDwelling(); - nobj->setOwner(PlayerColor(reader.readUInt8())); - reader.skip(3); + nobj->setOwner(PlayerColor(reader->readUInt8())); + reader->skip(3); break; } case Obj::SHRINE_OF_MAGIC_INCANTATION: @@ -1274,7 +1277,7 @@ void CMapLoaderH3M::readObjects() { auto * shr = new CGShrine(); nobj = shr; - ui8 raw_id = reader.readUInt8(); + ui8 raw_id = reader->readUInt8(); if (255 == raw_id) { @@ -1285,7 +1288,7 @@ void CMapLoaderH3M::readObjects() shr->spell = SpellID(raw_id); } - reader.skip(3); + reader->skip(3); break; } case Obj::PANDORAS_BOX: @@ -1294,51 +1297,51 @@ void CMapLoaderH3M::readObjects() nobj = box; readMessageAndGuards(box->message, box); - box->gainedExp = reader.readUInt32(); - box->manaDiff = reader.readUInt32(); - box->moraleDiff = reader.readInt8(); - box->luckDiff = reader.readInt8(); + box->gainedExp = reader->readUInt32(); + box->manaDiff = reader->readUInt32(); + box->moraleDiff = reader->readInt8(); + box->luckDiff = reader->readInt8(); readResourses(box->resources); box->primskills.resize(GameConstants::PRIMARY_SKILLS); for(int x = 0; x < 4; ++x) { - box->primskills[x] = static_cast(reader.readUInt8()); + box->primskills[x] = static_cast(reader->readUInt8()); } - int gabn = reader.readUInt8();//number of gained abilities + int gabn = reader->readUInt8();//number of gained abilities for(int oo = 0; oo < gabn; ++oo) { - box->abilities.emplace_back(reader.readUInt8()); - box->abilityLevels.push_back(reader.readUInt8()); + box->abilities.emplace_back(reader->readUInt8()); + box->abilityLevels.push_back(reader->readUInt8()); } - int gart = reader.readUInt8(); //number of gained artifacts + int gart = reader->readUInt8(); //number of gained artifacts for(int oo = 0; oo < gart; ++oo) { if(map->version > EMapFormat::ROE) { - box->artifacts.emplace_back(reader.readUInt16()); + box->artifacts.emplace_back(reader->readUInt16()); } else { - box->artifacts.emplace_back(reader.readUInt8()); + box->artifacts.emplace_back(reader->readUInt8()); } } - int gspel = reader.readUInt8(); //number of gained spells + int gspel = reader->readUInt8(); //number of gained spells for(int oo = 0; oo < gspel; ++oo) { - box->spells.emplace_back(reader.readUInt8()); + box->spells.emplace_back(reader->readUInt8()); } - int gcre = reader.readUInt8(); //number of gained creatures + int gcre = reader->readUInt8(); //number of gained creatures readCreatureSet(&box->creatures, gcre); - reader.skip(8); + reader->skip(8); break; } case Obj::GRAIL: { map->grailPos = objPos; - map->grailRadius = reader.readUInt32(); + map->grailRadius = reader->readUInt32(); continue; } case Obj::RANDOM_DWELLING: //same as castle + level range @@ -1364,20 +1367,20 @@ void CMapLoaderH3M::readObjects() } spec->owner = dwelling; - nobj->setOwner(PlayerColor(reader.readUInt32())); + nobj->setOwner(PlayerColor(reader->readUInt32())); //216 and 217 if(auto * castleSpec = dynamic_cast(spec)) { castleSpec->instanceId = ""; - castleSpec->identifier = reader.readUInt32(); + castleSpec->identifier = reader->readUInt32(); if(!castleSpec->identifier) { castleSpec->asCastle = false; const int MASK_SIZE = 8; ui8 mask[2]; - mask[0] = reader.readUInt8(); - mask[1] = reader.readUInt8(); + mask[0] = reader->readUInt8(); + mask[1] = reader->readUInt8(); castleSpec->allowedFactions.clear(); castleSpec->allowedFactions.resize(VLC->townh->size(), false); @@ -1397,8 +1400,8 @@ void CMapLoaderH3M::readObjects() //216 and 218 if(auto * lvlSpec = dynamic_cast(spec)) { - lvlSpec->minLevel = std::max(reader.readUInt8(), static_cast(1)); - lvlSpec->maxLevel = std::min(reader.readUInt8(), static_cast(7)); + lvlSpec->minLevel = std::max(reader->readUInt8(), static_cast(1)); + lvlSpec->maxLevel = std::min(reader->readUInt8(), static_cast(7)); } dwelling->info = spec; break; @@ -1413,7 +1416,7 @@ void CMapLoaderH3M::readObjects() case Obj::SHIPYARD: { nobj = new CGShipyard(); - nobj->setOwner(PlayerColor(reader.readUInt32())); + nobj->setOwner(PlayerColor(reader->readUInt32())); break; } case Obj::HERO_PLACEHOLDER: //hero placeholder @@ -1421,14 +1424,14 @@ void CMapLoaderH3M::readObjects() auto * hp = new CGHeroPlaceholder(); nobj = hp; - hp->setOwner(PlayerColor(reader.readUInt8())); + hp->setOwner(PlayerColor(reader->readUInt8())); - int htid = reader.readUInt8(); //hero type id + int htid = reader->readUInt8(); //hero type id nobj->subID = htid; if(htid == 0xff) { - hp->power = reader.readUInt8(); + hp->power = reader->readUInt8(); logGlobal->info("Hero placeholder: by power at %s", objPos.toString()); } else @@ -1466,7 +1469,7 @@ void CMapLoaderH3M::readObjects() case Obj::LIGHTHOUSE: //Lighthouse { nobj = new CGLighthouse(); - nobj->tempOwner = PlayerColor(reader.readUInt32()); + nobj->tempOwner = PlayerColor(reader->readUInt32()); break; } default: //any other object @@ -1523,13 +1526,13 @@ void CMapLoaderH3M::readCreatureSet(CCreatureSet * out, int number) if (version) { - creID = CreatureID(reader.readUInt16()); + creID = CreatureID(reader->readUInt16()); } else { - creID = CreatureID(reader.readUInt8()); + creID = CreatureID(reader->readUInt8()); } - count = reader.readUInt16(); + count = reader->readUInt16(); // Empty slot if(creID == maxID) @@ -1560,12 +1563,12 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, if(map->version > EMapFormat::ROE) { - unsigned int identifier = reader.readUInt32(); + unsigned int identifier = reader->readUInt32(); map->questIdentifierToId[identifier] = idToBeGiven; } - PlayerColor owner = PlayerColor(reader.readUInt8()); - nhi->subID = reader.readUInt8(); + PlayerColor owner = PlayerColor(reader->readUInt8()); + nhi->subID = reader->readUInt8(); assert(!nhi->getArt(ArtifactPosition::MACH4)); @@ -1595,17 +1598,17 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, } } - bool hasName = reader.readBool(); + bool hasName = reader->readBool(); if(hasName) { - nhi->nameCustom = reader.readString(); + nhi->nameCustom = readLocalizedString(); } if(map->version > EMapFormat::AB) { - bool hasExp = reader.readBool(); + bool hasExp = reader->readBool(); if(hasExp) { - nhi->exp = reader.readUInt32(); + nhi->exp = reader->readUInt32(); } else { @@ -1614,7 +1617,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, } else { - nhi->exp = reader.readUInt32(); + nhi->exp = reader->readUInt32(); //0 means "not set" in <=AB maps if(!nhi->exp) @@ -1623,13 +1626,13 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, } } - bool hasPortrait = reader.readBool(); + bool hasPortrait = reader->readBool(); if(hasPortrait) { - nhi->portrait = reader.readUInt8(); + nhi->portrait = reader->readUInt8(); } - bool hasSecSkills = reader.readBool(); + bool hasSecSkills = reader->readBool(); if(hasSecSkills) { if(!nhi->secSkills.empty()) @@ -1638,34 +1641,34 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, //logGlobal->warn("Hero %s subID=%d has set secondary skills twice (in map properties and on adventure map instance). Using the latter set...", nhi->name, nhi->subID); } - int howMany = reader.readUInt32(); + int howMany = reader->readUInt32(); nhi->secSkills.resize(howMany); for(int yy = 0; yy < howMany; ++yy) { - nhi->secSkills[yy].first = SecondarySkill(reader.readUInt8()); - nhi->secSkills[yy].second = reader.readUInt8(); + nhi->secSkills[yy].first = SecondarySkill(reader->readUInt8()); + nhi->secSkills[yy].second = reader->readUInt8(); } } - bool hasGarison = reader.readBool(); + bool hasGarison = reader->readBool(); if(hasGarison) { readCreatureSet(nhi, 7); } - nhi->formation = reader.readUInt8(); + nhi->formation = reader->readUInt8(); loadArtifactsOfHero(nhi); - nhi->patrol.patrolRadius = reader.readUInt8(); + nhi->patrol.patrolRadius = reader->readUInt8(); nhi->patrol.patrolling = (nhi->patrol.patrolRadius != 0xff); if(map->version > EMapFormat::ROE) { - bool hasCustomBiography = reader.readBool(); + bool hasCustomBiography = reader->readBool(); if(hasCustomBiography) { - nhi->biographyCustom = reader.readString(); + nhi->biographyCustom = readLocalizedString(); } - nhi->sex = reader.readUInt8(); + nhi->sex = reader->readUInt8(); // Remove trash if (nhi->sex != 0xFF) @@ -1681,7 +1684,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, // Spells if(map->version > EMapFormat::AB) { - bool hasCustomSpells = reader.readBool(); + bool hasCustomSpells = reader->readBool(); if(!nhi->spells.empty()) { nhi->clear(); @@ -1698,7 +1701,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, else if(map->version == EMapFormat::AB) { //we can read one spell - ui8 buff = reader.readUInt8(); + ui8 buff = reader->readUInt8(); if(buff != 254) { nhi->spells.insert(SpellID::PRESET); //placeholder "preset spells" @@ -1711,7 +1714,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, if(map->version > EMapFormat::AB) { - bool hasCustomPrimSkills = reader.readBool(); + bool hasCustomPrimSkills = reader->readBool(); if(hasCustomPrimSkills) { auto ps = nhi->getAllBonuses(Selector::type()(Bonus::PRIMARY_SKILL) @@ -1726,11 +1729,11 @@ CGObjectInstance * CMapLoaderH3M::readHero(const ObjectInstanceID & idToBeGiven, for(int xx = 0; xx < GameConstants::PRIMARY_SKILLS; ++xx) { - nhi->pushPrimSkill(static_cast(xx), reader.readUInt8()); + nhi->pushPrimSkill(static_cast(xx), reader->readUInt8()); } } } - reader.skip(16); + reader->skip(16); return nhi; } @@ -1745,7 +1748,7 @@ CGSeerHut * CMapLoaderH3M::readSeerHut() else { //RoE - auto artID = ArtifactID(reader.readUInt8()); + auto artID = ArtifactID(reader->readUInt8()); if (artID != 255) { //not none quest @@ -1762,87 +1765,87 @@ CGSeerHut * CMapLoaderH3M::readSeerHut() if (hut->quest->missionType) { - auto rewardType = static_cast(reader.readUInt8()); + auto rewardType = static_cast(reader->readUInt8()); hut->rewardType = rewardType; switch(rewardType) { case CGSeerHut::EXPERIENCE: { - hut->rVal = reader.readUInt32(); + hut->rVal = reader->readUInt32(); break; } case CGSeerHut::MANA_POINTS: { - hut->rVal = reader.readUInt32(); + hut->rVal = reader->readUInt32(); break; } case CGSeerHut::MORALE_BONUS: { - hut->rVal = reader.readUInt8(); + hut->rVal = reader->readUInt8(); break; } case CGSeerHut::LUCK_BONUS: { - hut->rVal = reader.readUInt8(); + hut->rVal = reader->readUInt8(); break; } case CGSeerHut::RESOURCES: { - hut->rID = reader.readUInt8(); + hut->rID = reader->readUInt8(); // Only the first 3 bytes are used. Skip the 4th. - hut->rVal = reader.readUInt32() & 0x00ffffff; + hut->rVal = reader->readUInt32() & 0x00ffffff; break; } case CGSeerHut::PRIMARY_SKILL: { - hut->rID = reader.readUInt8(); - hut->rVal = reader.readUInt8(); + hut->rID = reader->readUInt8(); + hut->rVal = reader->readUInt8(); break; } case CGSeerHut::SECONDARY_SKILL: { - hut->rID = reader.readUInt8(); - hut->rVal = reader.readUInt8(); + hut->rID = reader->readUInt8(); + hut->rVal = reader->readUInt8(); break; } case CGSeerHut::ARTIFACT: { if (map->version == EMapFormat::ROE) { - hut->rID = reader.readUInt8(); + hut->rID = reader->readUInt8(); } else { - hut->rID = reader.readUInt16(); + hut->rID = reader->readUInt16(); } break; } case CGSeerHut::SPELL: { - hut->rID = reader.readUInt8(); + hut->rID = reader->readUInt8(); break; } case CGSeerHut::CREATURE: { if(map->version > EMapFormat::ROE) { - hut->rID = reader.readUInt16(); - hut->rVal = reader.readUInt16(); + hut->rID = reader->readUInt16(); + hut->rVal = reader->readUInt16(); } else { - hut->rID = reader.readUInt8(); - hut->rVal = reader.readUInt16(); + hut->rID = reader->readUInt8(); + hut->rVal = reader->readUInt16(); } break; } } - reader.skip(2); + reader->skip(2); } else { // missionType==255 - reader.skip(3); + reader->skip(3); } return hut; @@ -1850,7 +1853,7 @@ CGSeerHut * CMapLoaderH3M::readSeerHut() void CMapLoaderH3M::readQuest(IQuestObject * guard) { - guard->quest->missionType = static_cast(reader.readUInt8()); + guard->quest->missionType = static_cast(reader->readUInt8()); switch(guard->quest->missionType) { @@ -1861,7 +1864,7 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard) guard->quest->m2stats.resize(4); for(int x = 0; x < 4; ++x) { - guard->quest->m2stats[x] = reader.readUInt8(); + guard->quest->m2stats[x] = reader->readUInt8(); } } break; @@ -1869,15 +1872,15 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard) case CQuest::MISSION_KILL_HERO: case CQuest::MISSION_KILL_CREATURE: { - guard->quest->m13489val = reader.readUInt32(); + guard->quest->m13489val = reader->readUInt32(); break; } case CQuest::MISSION_ART: { - int artNumber = reader.readUInt8(); + int artNumber = reader->readUInt8(); for(int yy = 0; yy < artNumber; ++yy) { - auto artid = ArtifactID(reader.readUInt16()); + auto artid = ArtifactID(reader->readUInt16()); guard->quest->addArtifactID(artid); map->allowedArtifact[artid] = false; //these are unavailable for random generation } @@ -1885,12 +1888,12 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard) } case CQuest::MISSION_ARMY: { - int typeNumber = reader.readUInt8(); + int typeNumber = reader->readUInt8(); guard->quest->m6creatures.resize(typeNumber); for(int hh = 0; hh < typeNumber; ++hh) { - guard->quest->m6creatures[hh].type = VLC->creh->objects[reader.readUInt16()]; - guard->quest->m6creatures[hh].count = reader.readUInt16(); + guard->quest->m6creatures[hh].type = VLC->creh->objects[reader->readUInt16()]; + guard->quest->m6creatures[hh].count = reader->readUInt16(); } break; } @@ -1899,19 +1902,19 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard) guard->quest->m7resources.resize(7); for(int x = 0; x < 7; ++x) { - guard->quest->m7resources[x] = reader.readUInt32(); + guard->quest->m7resources[x] = reader->readUInt32(); } break; } case CQuest::MISSION_HERO: case CQuest::MISSION_PLAYER: { - guard->quest->m13489val = reader.readUInt8(); + guard->quest->m13489val = reader->readUInt8(); break; } } - int limit = reader.readUInt32(); + int limit = reader->readUInt32(); if(limit == (static_cast(0xffffffff))) { guard->quest->lastDay = -1; @@ -1920,9 +1923,9 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard) { guard->quest->lastDay = limit; } - guard->quest->firstVisitText = reader.readString(); - guard->quest->nextVisitText = reader.readString(); - guard->quest->completedText = reader.readString(); + guard->quest->firstVisitText = readLocalizedString(); + guard->quest->nextVisitText = readLocalizedString(); + guard->quest->completedText = readLocalizedString(); guard->quest->isCustomFirst = !guard->quest->firstVisitText.empty(); guard->quest->isCustomNext = !guard->quest->nextVisitText.empty(); guard->quest->isCustomComplete = !guard->quest->completedText.empty(); @@ -1933,23 +1936,23 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) auto * nt = new CGTownInstance(); if(map->version > EMapFormat::ROE) { - nt->identifier = reader.readUInt32(); + nt->identifier = reader->readUInt32(); } - nt->tempOwner = PlayerColor(reader.readUInt8()); - bool hasName = reader.readBool(); + nt->tempOwner = PlayerColor(reader->readUInt8()); + bool hasName = reader->readBool(); if(hasName) { - nt->setNameTranslated( reader.readString()); + nt->setNameTranslated( readLocalizedString()); } - bool hasGarrison = reader.readBool(); + bool hasGarrison = reader->readBool(); if(hasGarrison) { readCreatureSet(nt, 7); } - nt->formation = reader.readUInt8(); + nt->formation = reader->readUInt8(); - bool hasCustomBuildings = reader.readBool(); + bool hasCustomBuildings = reader->readBool(); if(hasCustomBuildings) { readBitmask(nt->builtBuildings,6,48,false); @@ -1962,7 +1965,7 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) // Standard buildings else { - bool hasFort = reader.readBool(); + bool hasFort = reader->readBool(); if(hasFort) { nt->builtBuildings.insert(BuildingID::FORT); @@ -1976,7 +1979,7 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) { for(int i = 0; i < 9; ++i) { - ui8 c = reader.readUInt8(); + ui8 c = reader->readUInt8(); for(int yy = 0; yy < 8; ++yy) { if(i * 8 + yy < GameConstants::SPELLS_QUANTITY) @@ -1992,7 +1995,7 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) for(int i = 0; i < 9; ++i) { - ui8 c = reader.readUInt8(); + ui8 c = reader->readUInt8(); for(int yy = 0; yy < 8; ++yy) { int spellid = i * 8 + yy; @@ -2013,32 +2016,32 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) } // Read castle events - int numberOfEvent = reader.readUInt32(); + int numberOfEvent = reader->readUInt32(); for(int gh = 0; gh < numberOfEvent; ++gh) { CCastleEvent nce; nce.town = nt; - nce.name = reader.readString(); - nce.message = reader.readString(); + nce.name = readLocalizedString(); + nce.message = readLocalizedString(); readResourses(nce.resources); - nce.players = reader.readUInt8(); + nce.players = reader->readUInt8(); if(map->version > EMapFormat::AB) { - nce.humanAffected = reader.readUInt8(); + nce.humanAffected = reader->readUInt8(); } else { nce.humanAffected = true; } - nce.computerAffected = reader.readUInt8(); - nce.firstOccurence = reader.readUInt16(); - nce.nextOccurence = reader.readUInt8(); + nce.computerAffected = reader->readUInt8(); + nce.firstOccurence = reader->readUInt16(); + nce.nextOccurence = reader->readUInt8(); - reader.skip(17); + reader->skip(17); // New buildings @@ -2049,17 +2052,17 @@ CGTownInstance * CMapLoaderH3M::readTown(int castleID) nce.creatures.resize(7); for(int vv = 0; vv < 7; ++vv) { - nce.creatures[vv] = reader.readUInt16(); + nce.creatures[vv] = reader->readUInt16(); } - reader.skip(4); + reader->skip(4); nt->events.push_back(nce); } if(map->version > EMapFormat::AB) { - nt->alignment = reader.readUInt8(); + nt->alignment = reader->readUInt8(); } - reader.skip(3); + reader->skip(3); return nt; } @@ -2126,28 +2129,28 @@ std::set CMapLoaderH3M::convertBuildings(const std::set void CMapLoaderH3M::readEvents() { - int numberOfEvents = reader.readUInt32(); + int numberOfEvents = reader->readUInt32(); for(int yyoo = 0; yyoo < numberOfEvents; ++yyoo) { CMapEvent ne; - ne.name = reader.readString(); - ne.message = reader.readString(); + ne.name = readLocalizedString(); + ne.message = readLocalizedString(); readResourses(ne.resources); - ne.players = reader.readUInt8(); + ne.players = reader->readUInt8(); if(map->version > EMapFormat::AB) { - ne.humanAffected = reader.readUInt8(); + ne.humanAffected = reader->readUInt8(); } else { ne.humanAffected = true; } - ne.computerAffected = reader.readUInt8(); - ne.firstOccurence = reader.readUInt16(); - ne.nextOccurence = reader.readUInt8(); + ne.computerAffected = reader->readUInt8(); + ne.firstOccurence = reader->readUInt16(); + ne.nextOccurence = reader->readUInt8(); - reader.skip(17); + reader->skip(17); map->events.push_back(ne); } @@ -2155,16 +2158,16 @@ void CMapLoaderH3M::readEvents() void CMapLoaderH3M::readMessageAndGuards(std::string& message, CCreatureSet* guards) { - bool hasMessage = reader.readBool(); + bool hasMessage = reader->readBool(); if(hasMessage) { - message = reader.readString(); - bool hasGuards = reader.readBool(); + message = readLocalizedString(); + bool hasGuards = reader->readBool(); if(hasGuards) { readCreatureSet(guards, 7); } - reader.skip(4); + reader->skip(4); } } @@ -2178,7 +2181,7 @@ void CMapLoaderH3M::readResourses(TResources& resources) resources.resize(GameConstants::RESOURCE_QUANTITY); //needed? for(int x = 0; x < 7; ++x) { - resources[x] = reader.readUInt32(); + resources[x] = reader->readUInt32(); } } @@ -2202,7 +2205,7 @@ void CMapLoaderH3M::readBitmask(std::vector& dest, const int byteCount, co { for(int byte = 0; byte < byteCount; ++byte) { - const ui8 mask = reader.readUInt8(); + const ui8 mask = reader->readUInt8(); for(int bit = 0; bit < 8; ++bit) { if(byte * 8 + bit < limit) @@ -2228,11 +2231,25 @@ ui8 CMapLoaderH3M::reverse(ui8 arg) const return ret; } +int3 CMapLoaderH3M::readInt3() +{ + int3 p; + p.x = reader->readUInt8(); + p.y = reader->readUInt8(); + p.z = reader->readUInt8(); + return p; +} + +std::string CMapLoaderH3M::readLocalizedString() +{ + return reader->readBaseString(); +} + void CMapLoaderH3M::afterRead() { - //convert main town positions for all players to actual object position, in H3M it is position of active tile + //convert main town positions for all players to actual object position, in H3M it is position of active tile - for(auto & p : map->players) + for(auto & p : map->players) { int3 posOfMainTown = p.posOfMainTown; if(posOfMainTown.valid() && map->isInTheMap(posOfMainTown)) diff --git a/lib/mapping/MapFormatH3M.h b/lib/mapping/MapFormatH3M.h index 134c40f3f..ffceaabe4 100644 --- a/lib/mapping/MapFormatH3M.h +++ b/lib/mapping/MapFormatH3M.h @@ -17,11 +17,11 @@ #include "../int3.h" -#include "../filesystem/CBinaryReader.h" VCMI_LIB_NAMESPACE_BEGIN class CGHeroInstance; +class CBinaryReader; class CArtifactInstance; class CGObjectInstance; class CGSeerHut; @@ -234,14 +234,10 @@ private: /** * Helper to read map position */ - inline int3 readInt3() - { - int3 p; - p.x = reader.readUInt8(); - p.y = reader.readUInt8(); - p.z = reader.readUInt8(); - return p; - } + int3 readInt3(); + + /// reads string from input stream and converts it to unicode + std::string readLocalizedString(); void afterRead(); @@ -257,8 +253,7 @@ private: * (when loading a map then the mapHeader ptr points to the same object) */ std::unique_ptr mapHeader; - - CBinaryReader reader; + std::unique_ptr reader; CInputStream * inputStream; };