1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

Refactor campaign regions

This commit is contained in:
nordsoft 2023-04-17 04:26:35 +04:00
parent e4c147db16
commit 70f4cc5e0f
5 changed files with 122 additions and 76 deletions

View File

@ -51,6 +51,7 @@
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
std::shared_ptr<CCampaignState> CBonusSelection::getCampaign() std::shared_ptr<CCampaignState> CBonusSelection::getCampaign()
{ {
return CSH->si->campState; return CSH->si->campState;
@ -61,8 +62,7 @@ CBonusSelection::CBonusSelection()
{ {
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
loadPositionsOfGraphics(); std::string bgName = getCampaign()->camp->header.campaignRegions.campPrefix + "_BG.BMP";
std::string bgName = campDescriptions[getCampaign()->camp->header.mapVersion].campPrefix + "_BG.BMP";
setBackground(bgName); setBackground(bgName);
panelBackground = std::make_shared<CPicture>("CAMPBRF.BMP", 456, 6); panelBackground = std::make_shared<CPicture>("CAMPBRF.BMP", 456, 6);
@ -106,35 +106,9 @@ CBonusSelection::CBonusSelection()
for(int g = 0; g < getCampaign()->camp->scenarios.size(); ++g) for(int g = 0; g < getCampaign()->camp->scenarios.size(); ++g)
{ {
if(getCampaign()->camp->conquerable(g)) if(getCampaign()->camp->conquerable(g))
regions.push_back(std::make_shared<CRegion>(g, true, true, campDescriptions[getCampaign()->camp->header.mapVersion])); regions.push_back(std::make_shared<CRegion>(g, true, true, getCampaign()->camp->header.campaignRegions));
else if(getCampaign()->camp->scenarios[g].conquered) //display as striped else if(getCampaign()->camp->scenarios[g].conquered) //display as striped
regions.push_back(std::make_shared<CRegion>(g, false, false, campDescriptions[getCampaign()->camp->header.mapVersion])); regions.push_back(std::make_shared<CRegion>(g, false, false, getCampaign()->camp->header.campaignRegions));
}
}
void CBonusSelection::loadPositionsOfGraphics()
{
const JsonNode config(ResourceID("config/campaign_regions.json"));
for(const JsonNode & campaign : config["campaign_regions"].Vector())
{
SCampPositions sc;
sc.campPrefix = campaign["prefix"].String();
sc.colorSuffixLength = static_cast<int>(campaign["color_suffix_length"].Float());
for(const JsonNode & desc : campaign["desc"].Vector())
{
SCampPositions::SRegionDesc rd;
rd.infix = desc["infix"].String();
rd.xpos = static_cast<int>(desc["x"].Float());
rd.ypos = static_cast<int>(desc["y"].Float());
sc.regions.push_back(rd);
}
campDescriptions.push_back(sc);
} }
} }
@ -470,7 +444,7 @@ void CBonusSelection::decreaseDifficulty()
CSH->setDifficulty(CSH->si->difficulty - 1); CSH->setDifficulty(CSH->si->difficulty - 1);
} }
CBonusSelection::CRegion::CRegion(int id, bool accessible, bool selectable, const SCampPositions & campDsc) CBonusSelection::CRegion::CRegion(int id, bool accessible, bool selectable, const CampaignRegions & campDsc)
: CIntObject(LCLICK | RCLICK), idOfMapAndRegion(id), accessible(accessible), selectable(selectable) : CIntObject(LCLICK | RCLICK), idOfMapAndRegion(id), accessible(accessible), selectable(selectable)
{ {
OBJ_CONSTRUCTION; OBJ_CONSTRUCTION;
@ -480,7 +454,7 @@ CBonusSelection::CRegion::CRegion(int id, bool accessible, bool selectable, cons
{"Re", "Bl", "Br", "Gr", "Or", "Vi", "Te", "Pi"} {"Re", "Bl", "Br", "Gr", "Or", "Vi", "Te", "Pi"}
}; };
const SCampPositions::SRegionDesc & desc = campDsc.regions[idOfMapAndRegion]; const CampaignRegions::RegionDescription & desc = campDsc.regions[idOfMapAndRegion];
pos.x += desc.xpos; pos.x += desc.xpos;
pos.y += desc.ypos; pos.y += desc.ypos;

View File

@ -8,6 +8,7 @@
* *
*/ */
#pragma once #pragma once
#include "../../lib/mapping/CCampaignHandler.h"
#include "../windows/CWindowObject.h" #include "../windows/CWindowObject.h"
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
@ -32,21 +33,6 @@ public:
std::shared_ptr<CCampaignState> getCampaign(); std::shared_ptr<CCampaignState> getCampaign();
CBonusSelection(); CBonusSelection();
struct SCampPositions
{
std::string campPrefix;
int colorSuffixLength;
struct SRegionDesc
{
std::string infix;
int xpos, ypos;
};
std::vector<SRegionDesc> regions;
};
class CRegion class CRegion
: public CIntObject : public CIntObject
{ {
@ -57,13 +43,12 @@ public:
bool accessible; // false if region should be striped bool accessible; // false if region should be striped
bool selectable; // true if region should be selectable bool selectable; // true if region should be selectable
public: public:
CRegion(int id, bool accessible, bool selectable, const SCampPositions & campDsc); CRegion(int id, bool accessible, bool selectable, const CampaignRegions & campDsc);
void updateState(); void updateState();
void clickLeft(tribool down, bool previousState) override; void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override;
}; };
void loadPositionsOfGraphics();
void createBonusesIcons(); void createBonusesIcons();
void updateAfterStateChange(); void updateAfterStateChange();
@ -84,7 +69,6 @@ public:
std::shared_ptr<CLabel> mapName; std::shared_ptr<CLabel> mapName;
std::shared_ptr<CLabel> labelMapDescription; std::shared_ptr<CLabel> labelMapDescription;
std::shared_ptr<CTextBox> mapDescription; std::shared_ptr<CTextBox> mapDescription;
std::vector<SCampPositions> campDescriptions;
std::vector<std::shared_ptr<CRegion>> regions; std::vector<std::shared_ptr<CRegion>> regions;
std::shared_ptr<CFlagBox> flagbox; std::shared_ptr<CFlagBox> flagbox;

View File

@ -100,8 +100,8 @@ bool mapSorter::operator()(const std::shared_ptr<CMapInfo> aaa, const std::share
switch(sortBy) switch(sortBy)
{ {
case _numOfMaps: //by number of maps in campaign case _numOfMaps: //by number of maps in campaign
return CGI->generaltexth->getCampaignLength(aaa->campaignHeader->mapVersion) < return aaa->campaignHeader->numberOfScenarios <
CGI->generaltexth->getCampaignLength(bbb->campaignHeader->mapVersion); bbb->campaignHeader->numberOfScenarios;
break; break;
case _name: //by name case _name: //by name
return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name); return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name);
@ -665,7 +665,7 @@ void SelectionTab::ListItem::updateItem(std::shared_ptr<CMapInfo> info, bool sel
iconLossCondition->disable(); iconLossCondition->disable();
labelNumberOfCampaignMaps->enable(); labelNumberOfCampaignMaps->enable();
std::ostringstream ostr(std::ostringstream::out); std::ostringstream ostr(std::ostringstream::out);
ostr << CGI->generaltexth->getCampaignLength(info->campaignHeader->mapVersion); ostr << info->campaignHeader->numberOfScenarios;
labelNumberOfCampaignMaps->setText(ostr.str()); labelNumberOfCampaignMaps->setText(ostr.str());
labelNumberOfCampaignMaps->setColor(color); labelNumberOfCampaignMaps->setColor(color);
} }

View File

@ -36,12 +36,53 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
CampaignRegions::RegionDescription CampaignRegions::RegionDescription::fromJson(const JsonNode & node)
{
CampaignRegions::RegionDescription rd;
rd.infix = node["infix"].String();
rd.xpos = static_cast<int>(node["x"].Float());
rd.ypos = static_cast<int>(node["y"].Float());
return rd;
}
CampaignRegions CampaignRegions::fromJson(const JsonNode & node)
{
CampaignRegions cr;
cr.campPrefix = node["prefix"].String();
cr.colorSuffixLength = static_cast<int>(node["color_suffix_length"].Float());
for(const JsonNode & desc : node["desc"].Vector())
cr.regions.push_back(CampaignRegions::RegionDescription::fromJson(desc));
return cr;
}
CampaignRegions CampaignRegions::getLegacy(int campId)
{
static std::vector<CampaignRegions> campDescriptions;
if(campDescriptions.empty()) //read once
{
const JsonNode config(ResourceID("config/campaign_regions.json"));
for(const JsonNode & campaign : config["campaign_regions"].Vector())
campDescriptions.push_back(CampaignRegions::fromJson(campaign));
}
return campDescriptions.at(campId);
}
bool CScenarioTravel::STravelBonus::isBonusForHero() const bool CScenarioTravel::STravelBonus::isBonusForHero() const
{ {
return type == SPELL || type == MONSTER || type == ARTIFACT || type == SPELL_SCROLL || type == PRIMARY_SKILL return type == SPELL || type == MONSTER || type == ARTIFACT || type == SPELL_SCROLL || type == PRIMARY_SKILL
|| type == SECONDARY_SKILL; || type == SECONDARY_SKILL;
} }
void CCampaignHeader::loadLegacyData(ui8 campId)
{
campaignRegions = CampaignRegions::getLegacy(campId);
numberOfScenarios = VLC->generaltexth->getCampaignLength(campId);
}
CCampaignHeader CCampaignHandler::getHeader( const std::string & name) CCampaignHeader CCampaignHandler::getHeader( const std::string & name)
{ {
ResourceID resourceID(name, EResType::CAMPAIGN); ResourceID resourceID(name, EResType::CAMPAIGN);
@ -86,10 +127,10 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
CBinaryReader reader(&stream); CBinaryReader reader(&stream);
ret->header = readHeaderFromMemory(reader, resourceID.getName(), modName, encoding); ret->header = readHeaderFromMemory(reader, resourceID.getName(), modName, encoding);
int howManyScenarios = static_cast<int>(VLC->generaltexth->getCampaignLength(ret->header.mapVersion)); int howManyScenarios = ret->header.numberOfScenarios;
for(int g=0; g<howManyScenarios; ++g) for(int g = 0; g < howManyScenarios; ++g)
{ {
CCampaignScenario sc = readScenarioFromMemory(reader, resourceID.getName(), modName, encoding, ret->header.version, ret->header.mapVersion); CCampaignScenario sc = readScenarioFromMemory(reader, ret->header);
ret->scenarios.push_back(sc); ret->scenarios.push_back(sc);
} }
@ -126,7 +167,7 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
for(auto & scenario : jsonCampaign["scenarios"].Vector()) for(auto & scenario : jsonCampaign["scenarios"].Vector())
{ {
CCampaignScenario sc = readScenarioFromJson(scenario, resourceID.getName(), modName, encoding, ret->header.version, ret->header.mapVersion); CCampaignScenario sc = readScenarioFromJson(scenario);
if(sc.isNotVoid()) if(sc.isNotVoid())
{ {
CMapService mapService; CMapService mapService;
@ -180,7 +221,7 @@ std::string CCampaignHandler::readLocalizedString(CBinaryReader & reader, std::s
return VLC->generaltexth->translate(stringID.get()); return VLC->generaltexth->translate(stringID.get());
} }
CCampaignHeader CCampaignHandler::readHeaderFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding ) CCampaignHeader CCampaignHandler::readHeaderFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding)
{ {
CCampaignHeader ret; CCampaignHeader ret;
@ -192,7 +233,8 @@ CCampaignHeader CCampaignHandler::readHeaderFromJson(JsonNode & reader, std::str
} }
ret.version = CampaignVersion::VCMI; ret.version = CampaignVersion::VCMI;
ret.mapVersion = reader["campaignId"].Integer(); ret.campaignRegions = CampaignRegions::fromJson(reader["regions"]);
ret.numberOfScenarios = reader["scenarios"].Vector().size();
ret.name = reader["name"].String(); ret.name = reader["name"].String();
ret.description = reader["description"].String(); ret.description = reader["description"].String();
ret.difficultyChoosenByPlayer = reader["allowDifficultySelection"].Bool(); ret.difficultyChoosenByPlayer = reader["allowDifficultySelection"].Bool();
@ -204,7 +246,7 @@ CCampaignHeader CCampaignHandler::readHeaderFromJson(JsonNode & reader, std::str
return ret; return ret;
} }
CCampaignScenario CCampaignHandler::readScenarioFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding, int version, int mapVersion) CCampaignScenario CCampaignHandler::readScenarioFromJson(JsonNode & reader)
{ {
auto prologEpilogReader = [](JsonNode & identifier) -> CCampaignScenario::SScenarioPrologEpilog auto prologEpilogReader = [](JsonNode & identifier) -> CCampaignScenario::SScenarioPrologEpilog
{ {
@ -231,12 +273,12 @@ CCampaignScenario CCampaignHandler::readScenarioFromJson(JsonNode & reader, std:
ret.prolog = prologEpilogReader(reader["prolog"]); ret.prolog = prologEpilogReader(reader["prolog"]);
ret.epilog = prologEpilogReader(reader["epilog"]); ret.epilog = prologEpilogReader(reader["epilog"]);
ret.travelOptions = readScenarioTravelFromJson(reader, version); ret.travelOptions = readScenarioTravelFromJson(reader);
return ret; return ret;
} }
CScenarioTravel CCampaignHandler::readScenarioTravelFromJson(JsonNode & reader, int version ) CScenarioTravel CCampaignHandler::readScenarioTravelFromJson(JsonNode & reader)
{ {
CScenarioTravel ret; CScenarioTravel ret;
@ -442,7 +484,8 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader,
CCampaignHeader ret; CCampaignHeader ret;
ret.version = reader.readUInt32(); ret.version = reader.readUInt32();
ret.mapVersion = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19] ui8 campId = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19]
ret.loadLegacyData(campId);
ret.name = readLocalizedString(reader, filename, modName, encoding, "name"); ret.name = readLocalizedString(reader, filename, modName, encoding, "name");
ret.description = readLocalizedString(reader, filename, modName, encoding, "description"); ret.description = readLocalizedString(reader, filename, modName, encoding, "description");
if (ret.version > CampaignVersion::RoE) if (ret.version > CampaignVersion::RoE)
@ -457,7 +500,7 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader,
return ret; return ret;
} }
CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, int version, int mapVersion ) CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & reader, const CCampaignHeader & header)
{ {
auto prologEpilogReader = [&](const std::string & identifier) -> CCampaignScenario::SScenarioPrologEpilog auto prologEpilogReader = [&](const std::string & identifier) -> CCampaignScenario::SScenarioPrologEpilog
{ {
@ -467,7 +510,7 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
{ {
ret.prologVideo = reader.readUInt8(); ret.prologVideo = reader.readUInt8();
ret.prologMusic = reader.readUInt8(); ret.prologMusic = reader.readUInt8();
ret.prologText = readLocalizedString(reader, filename, modName, encoding, identifier); ret.prologText = readLocalizedString(reader, header.filename, header.modName, header.encoding, identifier);
} }
return ret; return ret;
}; };
@ -476,7 +519,7 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
ret.conquered = false; ret.conquered = false;
ret.mapName = reader.readBaseString(); ret.mapName = reader.readBaseString();
ret.packedMapSize = reader.readUInt32(); ret.packedMapSize = reader.readUInt32();
if(mapVersion == 18)//unholy alliance if(header.numberOfScenarios > 0) //unholy alliance
{ {
ret.loadPreconditionRegions(reader.readUInt16()); ret.loadPreconditionRegions(reader.readUInt16());
} }
@ -486,11 +529,11 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
} }
ret.regionColor = reader.readUInt8(); ret.regionColor = reader.readUInt8();
ret.difficulty = reader.readUInt8(); ret.difficulty = reader.readUInt8();
ret.regionText = readLocalizedString(reader, filename, modName, encoding, ret.mapName + ".region"); ret.regionText = readLocalizedString(reader, header.filename, header.modName, header.encoding, ret.mapName + ".region");
ret.prolog = prologEpilogReader(ret.mapName + ".prolog"); ret.prolog = prologEpilogReader(ret.mapName + ".prolog");
ret.epilog = prologEpilogReader(ret.mapName + ".epilog"); ret.epilog = prologEpilogReader(ret.mapName + ".epilog");
ret.travelOptions = readScenarioTravelFromMemory(reader, version); ret.travelOptions = readScenarioTravelFromMemory(reader, header.version);
return ret; return ret;
} }

View File

@ -37,11 +37,45 @@ namespace CampaignVersion
const int VCMI_MAX = 1; const int VCMI_MAX = 1;
} }
struct DLL_LINKAGE CampaignRegions
{
std::string campPrefix;
int colorSuffixLength;
struct DLL_LINKAGE RegionDescription
{
std::string infix;
int xpos, ypos;
template <typename Handler> void serialize(Handler &h, const int formatVersion)
{
h & infix;
h & xpos;
h & ypos;
}
static CampaignRegions::RegionDescription fromJson(const JsonNode & node);
};
std::vector<RegionDescription> regions;
template <typename Handler> void serialize(Handler &h, const int formatVersion)
{
h & campPrefix;
h & colorSuffixLength;
h & regions;
}
static CampaignRegions fromJson(const JsonNode & node);
static CampaignRegions getLegacy(int campId);
};
class DLL_LINKAGE CCampaignHeader class DLL_LINKAGE CCampaignHeader
{ {
public: public:
si32 version = 0; //4 - RoE, 5 - AB, 6 - SoD and WoG si32 version = 0; //4 - RoE, 5 - AB, 6 - SoD and WoG
ui8 mapVersion = 0; //CampText.txt's format CampaignRegions campaignRegions;
int numberOfScenarios = 0;
std::string name, description; std::string name, description;
ui8 difficultyChoosenByPlayer = 0; ui8 difficultyChoosenByPlayer = 0;
ui8 music = 0; //CmpMusic.txt, start from 0, field is unused in vcmi ui8 music = 0; //CmpMusic.txt, start from 0, field is unused in vcmi
@ -51,14 +85,27 @@ public:
std::string modName; std::string modName;
std::string encoding; std::string encoding;
void loadLegacyData(ui8 campId);
template <typename Handler> void serialize(Handler &h, const int formatVersion) template <typename Handler> void serialize(Handler &h, const int formatVersion)
{ {
h & version; h & version;
h & mapVersion; if(!h.saving && formatVersion < 821)
{
ui8 campId = 0; //legacy field
h & campId;
loadLegacyData(campId);
}
else
{
h & campaignRegions;
h & numberOfScenarios;
}
h & name; h & name;
h & description; h & description;
h & difficultyChoosenByPlayer; h & difficultyChoosenByPlayer;
h & music; if(formatVersion < 821)
h & music; //deprecated
h & filename; h & filename;
h & modName; h & modName;
h & encoding; h & encoding;
@ -223,18 +270,16 @@ public:
class DLL_LINKAGE CCampaignHandler class DLL_LINKAGE CCampaignHandler
{ {
std::vector<size_t> scenariosCountPerCampaign;
static std::string readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier); static std::string readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier);
//parsers for VCMI campaigns (*.vcmp) //parsers for VCMI campaigns (*.vcmp)
static CCampaignHeader readHeaderFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding); static CCampaignHeader readHeaderFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding);
static CCampaignScenario readScenarioFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding, int version, int mapVersion ); static CCampaignScenario readScenarioFromJson(JsonNode & reader);
static CScenarioTravel readScenarioTravelFromJson(JsonNode & reader, int version); static CScenarioTravel readScenarioTravelFromJson(JsonNode & reader);
//parsers for original H3C campaigns //parsers for original H3C campaigns
static CCampaignHeader readHeaderFromMemory(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding); static CCampaignHeader readHeaderFromMemory(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding);
static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, int version, int mapVersion ); static CCampaignScenario readScenarioFromMemory(CBinaryReader & reader, const CCampaignHeader & header);
static CScenarioTravel readScenarioTravelFromMemory(CBinaryReader & reader, int version); static CScenarioTravel readScenarioTravelFromMemory(CBinaryReader & reader, int version);
/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m) /// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
/// headerOnly - only header will be decompressed, returned vector wont have any maps /// headerOnly - only header will be decompressed, returned vector wont have any maps