From ecf8b9934b82165609f6e02ef40fb2df1f36d6d3 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Mon, 17 Apr 2023 23:19:56 +0400 Subject: [PATCH] Further refactoring --- lib/CGameState.cpp | 16 ++++---- lib/mapping/CCampaignHandler.cpp | 68 ++++++++++++++++---------------- lib/mapping/CCampaignHandler.h | 49 +++++++++++++---------- 3 files changed, 68 insertions(+), 65 deletions(-) diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 27cf29b6c..4284c334f 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1266,7 +1266,7 @@ void CGameState::prepareCrossoverHeroes(std::vectorartType->getId(); - assert( 8*18 > id );//number of arts that fits into h3m format - bool takeable = travelOptions.artifsKeptByHero[id / 8] & ( 1 << (id%8) ); + bool takeable = travelOptions.artifactsKeptByHero.count(art->artType->getId()); ArtifactLocation al(hero, artifactPosition); if(!takeable && !al.getSlot()->locked) //don't try removing locked artifacts -> it crashes #1719 @@ -1346,7 +1344,7 @@ void CGameState::prepareCrossoverHeroes(std::vector & j) -> bool { CreatureID::ECreatureID crid = j.second->getCreatureID().toEnum(); - return !(travelOptions.monstersKeptByHero[crid / 8] & (1 << (crid % 8))); + return !travelOptions.monstersKeptByHero.count(crid); }; auto stacksCopy = cgh->stacks; //copy of the map, so we can iterate iover it and remove stacks diff --git a/lib/mapping/CCampaignHandler.cpp b/lib/mapping/CCampaignHandler.cpp index f7760d37c..a91712494 100644 --- a/lib/mapping/CCampaignHandler.cpp +++ b/lib/mapping/CCampaignHandler.cpp @@ -282,13 +282,6 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromJson(JsonNode & reader) { CScenarioTravel ret; - std::map heroKeepsMap = { - {"experience", 1}, - {"primarySkill", 2}, - {"secondarySkill", 4}, - {"spells", 8}, - {"artifacts", 16} - }; std::map startOptionsMap = { {"none", 0}, {"bonus", 1}, @@ -337,31 +330,25 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromJson(JsonNode & reader) }; for(auto & k : reader["heroKeeps"].Vector()) - ret.whatHeroKeeps |= heroKeepsMap[k.String()]; + { + if(k.String() == "experience") ret.whatHeroKeeps.experience = true; + if(k.String() == "primarySkills") ret.whatHeroKeeps.primarySkills = true; + if(k.String() == "secondarySkills") ret.whatHeroKeeps.secondarySkills = true; + if(k.String() == "spells") ret.whatHeroKeeps.spells = true; + if(k.String() == "artifacts") ret.whatHeroKeeps.artifacts = true; + } for(auto & k : reader["keepCreatures"].Vector()) { if(auto identifier = VLC->modh->identifiers.getIdentifier(CModHandler::scopeMap(), "creature", k.String())) - { - int creId = identifier.get(); - if(creId >= ret.monstersKeptByHero.size()) - logGlobal->warn("VCMP Loading: creature %s with id %d isn't supported yet", k.String(), creId); - else - ret.monstersKeptByHero[creId / 8] |= (1 << creId % 8); - } + ret.monstersKeptByHero.insert(CreatureID(identifier.get())); else logGlobal->warn("VCMP Loading: keepCreatures contains unresolved identifier %s", k.String()); } for(auto & k : reader["keepArtifacts"].Vector()) { if(auto identifier = VLC->modh->identifiers.getIdentifier(CModHandler::scopeMap(), "artifact", k.String())) - { - int artId = identifier.get(); - if(artId >= ret.artifsKeptByHero.size()) - logGlobal->warn("VCMP Loading: artifact %s with id %d isn't supported yet", k.String(), artId); - else - ret.artifsKeptByHero[artId / 8] |= (1 << artId % 8); - } + ret.artifactsKeptByHero.insert(ArtifactID(identifier.get())); else logGlobal->warn("VCMP Loading: keepArtifacts contains unresolved identifier %s", k.String()); } @@ -491,8 +478,8 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader, if (ret.version > CampaignVersion::RoE) ret.difficultyChoosenByPlayer = reader.readInt8(); else - ret.difficultyChoosenByPlayer = 0; - ret.music = reader.readInt8(); + ret.difficultyChoosenByPlayer = false; + reader.readInt8(); //music - skip as unused ret.filename = filename; ret.modName = modName; ret.encoding = encoding; @@ -518,7 +505,7 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read CCampaignScenario ret; ret.conquered = false; ret.mapName = reader.readBaseString(); - ret.packedMapSize = reader.readUInt32(); + reader.readUInt32(); //packedMapSize - not used if(header.numberOfScenarios > 8) //unholy alliance { ret.loadPreconditionRegions(reader.readUInt16()); @@ -551,18 +538,29 @@ CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory(CBinaryReader & r { CScenarioTravel ret; - ret.whatHeroKeeps = reader.readUInt8(); - reader.getStream()->read(ret.monstersKeptByHero.data(), ret.monstersKeptByHero.size()); - - if (version < CampaignVersion::SoD) + ui8 whatHeroKeeps = reader.readUInt8(); + ret.whatHeroKeeps.experience = whatHeroKeeps & 1; + ret.whatHeroKeeps.primarySkills = whatHeroKeeps & 2; + ret.whatHeroKeeps.secondarySkills = whatHeroKeeps & 4; + ret.whatHeroKeeps.spells = whatHeroKeeps & 8; + ret.whatHeroKeeps.artifacts = whatHeroKeeps & 16; + + auto bitMaskToId = [&reader](std::set & container, int size) { - ret.artifsKeptByHero.fill(0); - reader.getStream()->read(ret.artifsKeptByHero.data(), ret.artifsKeptByHero.size() - 1); - } + for(int iId = 0, byte = 0; iId < size * 8; ++iId) + { + if(iId % 8 == 0) + byte = reader.readUInt8(); + if(byte & (1 << iId % 8)) + container.insert(T(iId)); + } + }; + + bitMaskToId(ret.monstersKeptByHero, 19); + if(version < CampaignVersion::SoD) + bitMaskToId(ret.artifactsKeptByHero, 17); else - { - reader.getStream()->read(ret.artifsKeptByHero.data(), ret.artifsKeptByHero.size()); - } + bitMaskToId(ret.artifactsKeptByHero, 18); ret.startOptions = reader.readUInt8(); diff --git a/lib/mapping/CCampaignHandler.h b/lib/mapping/CCampaignHandler.h index bb9e9e765..9dde5cae1 100644 --- a/lib/mapping/CCampaignHandler.h +++ b/lib/mapping/CCampaignHandler.h @@ -77,8 +77,7 @@ public: CampaignRegions campaignRegions; int numberOfScenarios = 0; std::string name, description; - ui8 difficultyChoosenByPlayer = 0; - ui8 music = 0; //CmpMusic.txt, start from 0, field is unused in vcmi + bool difficultyChoosenByPlayer = false; bool valid = false; std::string filename; @@ -90,34 +89,44 @@ public: template void serialize(Handler &h, const int formatVersion) { h & version; - if(!h.saving && formatVersion < 821) - { - ui8 campId = 0; //legacy field - h & campId; - loadLegacyData(campId); - } - else - { - h & campaignRegions; - h & numberOfScenarios; - } + h & campaignRegions; + h & numberOfScenarios; h & name; h & description; h & difficultyChoosenByPlayer; - if(formatVersion < 821) - h & music; //deprecated h & filename; h & modName; h & encoding; + h & valid; } }; class DLL_LINKAGE CScenarioTravel { public: - ui8 whatHeroKeeps = 0; //bitfield [0] - experience, [1] - prim skills, [2] - sec skills, [3] - spells, [4] - artifacts - std::array monstersKeptByHero; - std::array artifsKeptByHero; + + struct DLL_LINKAGE WhatHeroKeeps + { + bool experience = false; + bool primarySkills = false; + bool secondarySkills = false; + bool spells = false; + bool artifacts = false; + + template void serialize(Handler &h, const int formatVersion) + { + h & experience; + h & primarySkills; + h & secondarySkills; + h & spells; + h & artifacts; + } + }; + + WhatHeroKeeps whatHeroKeeps; + + std::set monstersKeptByHero; + std::set artifactsKeptByHero; ui8 startOptions = 0; //1 - start bonus, 2 - traveling hero, 3 - hero options @@ -147,7 +156,7 @@ public: { h & whatHeroKeeps; h & monstersKeptByHero; - h & artifsKeptByHero; + h & artifactsKeptByHero; h & startOptions; h & playerColor; h & bonusesToChoose; @@ -176,7 +185,6 @@ public: std::string mapName; //*.h3m std::string scenarioName; //from header. human-readble - ui32 packedMapSize = 0; //generally not used std::set preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c) ui8 regionColor = 0; ui8 difficulty = 0; @@ -200,7 +208,6 @@ public: { h & mapName; h & scenarioName; - h & packedMapSize; h & preconditionRegions; h & regionColor; h & difficulty;