1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +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"
std::shared_ptr<CCampaignState> CBonusSelection::getCampaign()
{
return CSH->si->campState;
@ -61,8 +62,7 @@ CBonusSelection::CBonusSelection()
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
loadPositionsOfGraphics();
std::string bgName = campDescriptions[getCampaign()->camp->header.mapVersion].campPrefix + "_BG.BMP";
std::string bgName = getCampaign()->camp->header.campaignRegions.campPrefix + "_BG.BMP";
setBackground(bgName);
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)
{
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
regions.push_back(std::make_shared<CRegion>(g, false, false, campDescriptions[getCampaign()->camp->header.mapVersion]));
}
}
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);
regions.push_back(std::make_shared<CRegion>(g, false, false, getCampaign()->camp->header.campaignRegions));
}
}
@ -470,7 +444,7 @@ void CBonusSelection::decreaseDifficulty()
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)
{
OBJ_CONSTRUCTION;
@ -480,7 +454,7 @@ CBonusSelection::CRegion::CRegion(int id, bool accessible, bool selectable, cons
{"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.y += desc.ypos;

View File

@ -8,6 +8,7 @@
*
*/
#pragma once
#include "../../lib/mapping/CCampaignHandler.h"
#include "../windows/CWindowObject.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -32,21 +33,6 @@ public:
std::shared_ptr<CCampaignState> getCampaign();
CBonusSelection();
struct SCampPositions
{
std::string campPrefix;
int colorSuffixLength;
struct SRegionDesc
{
std::string infix;
int xpos, ypos;
};
std::vector<SRegionDesc> regions;
};
class CRegion
: public CIntObject
{
@ -57,13 +43,12 @@ public:
bool accessible; // false if region should be striped
bool selectable; // true if region should be selectable
public:
CRegion(int id, bool accessible, bool selectable, const SCampPositions & campDsc);
CRegion(int id, bool accessible, bool selectable, const CampaignRegions & campDsc);
void updateState();
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
};
void loadPositionsOfGraphics();
void createBonusesIcons();
void updateAfterStateChange();
@ -84,7 +69,6 @@ public:
std::shared_ptr<CLabel> mapName;
std::shared_ptr<CLabel> labelMapDescription;
std::shared_ptr<CTextBox> mapDescription;
std::vector<SCampPositions> campDescriptions;
std::vector<std::shared_ptr<CRegion>> regions;
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)
{
case _numOfMaps: //by number of maps in campaign
return CGI->generaltexth->getCampaignLength(aaa->campaignHeader->mapVersion) <
CGI->generaltexth->getCampaignLength(bbb->campaignHeader->mapVersion);
return aaa->campaignHeader->numberOfScenarios <
bbb->campaignHeader->numberOfScenarios;
break;
case _name: //by 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();
labelNumberOfCampaignMaps->enable();
std::ostringstream ostr(std::ostringstream::out);
ostr << CGI->generaltexth->getCampaignLength(info->campaignHeader->mapVersion);
ostr << info->campaignHeader->numberOfScenarios;
labelNumberOfCampaignMaps->setText(ostr.str());
labelNumberOfCampaignMaps->setColor(color);
}

View File

@ -36,12 +36,53 @@
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
{
return type == SPELL || type == MONSTER || type == ARTIFACT || type == SPELL_SCROLL || type == PRIMARY_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)
{
ResourceID resourceID(name, EResType::CAMPAIGN);
@ -86,10 +127,10 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
CBinaryReader reader(&stream);
ret->header = readHeaderFromMemory(reader, resourceID.getName(), modName, encoding);
int howManyScenarios = static_cast<int>(VLC->generaltexth->getCampaignLength(ret->header.mapVersion));
for(int g=0; g<howManyScenarios; ++g)
int howManyScenarios = ret->header.numberOfScenarios;
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);
}
@ -126,7 +167,7 @@ std::unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & na
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())
{
CMapService mapService;
@ -180,7 +221,7 @@ std::string CCampaignHandler::readLocalizedString(CBinaryReader & reader, std::s
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;
@ -192,7 +233,8 @@ CCampaignHeader CCampaignHandler::readHeaderFromJson(JsonNode & reader, std::str
}
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.description = reader["description"].String();
ret.difficultyChoosenByPlayer = reader["allowDifficultySelection"].Bool();
@ -204,7 +246,7 @@ CCampaignHeader CCampaignHandler::readHeaderFromJson(JsonNode & reader, std::str
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
{
@ -231,12 +273,12 @@ CCampaignScenario CCampaignHandler::readScenarioFromJson(JsonNode & reader, std:
ret.prolog = prologEpilogReader(reader["prolog"]);
ret.epilog = prologEpilogReader(reader["epilog"]);
ret.travelOptions = readScenarioTravelFromJson(reader, version);
ret.travelOptions = readScenarioTravelFromJson(reader);
return ret;
}
CScenarioTravel CCampaignHandler::readScenarioTravelFromJson(JsonNode & reader, int version )
CScenarioTravel CCampaignHandler::readScenarioTravelFromJson(JsonNode & reader)
{
CScenarioTravel ret;
@ -442,7 +484,8 @@ 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]
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.description = readLocalizedString(reader, filename, modName, encoding, "description");
if (ret.version > CampaignVersion::RoE)
@ -457,7 +500,7 @@ CCampaignHeader CCampaignHandler::readHeaderFromMemory( CBinaryReader & reader,
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
{
@ -467,7 +510,7 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
{
ret.prologVideo = 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;
};
@ -476,7 +519,7 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
ret.conquered = false;
ret.mapName = reader.readBaseString();
ret.packedMapSize = reader.readUInt32();
if(mapVersion == 18)//unholy alliance
if(header.numberOfScenarios > 0) //unholy alliance
{
ret.loadPreconditionRegions(reader.readUInt16());
}
@ -486,11 +529,11 @@ CCampaignScenario CCampaignHandler::readScenarioFromMemory( CBinaryReader & read
}
ret.regionColor = 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.epilog = prologEpilogReader(ret.mapName + ".epilog");
ret.travelOptions = readScenarioTravelFromMemory(reader, version);
ret.travelOptions = readScenarioTravelFromMemory(reader, header.version);
return ret;
}

View File

@ -37,11 +37,45 @@ namespace CampaignVersion
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
{
public:
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;
ui8 difficultyChoosenByPlayer = 0;
ui8 music = 0; //CmpMusic.txt, start from 0, field is unused in vcmi
@ -50,15 +84,28 @@ public:
std::string filename;
std::string modName;
std::string encoding;
void loadLegacyData(ui8 campId);
template <typename Handler> void serialize(Handler &h, const int formatVersion)
{
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 & description;
h & difficultyChoosenByPlayer;
h & music;
if(formatVersion < 821)
h & music; //deprecated
h & filename;
h & modName;
h & encoding;
@ -223,18 +270,16 @@ public:
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);
//parsers for VCMI campaigns (*.vcmp)
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 CScenarioTravel readScenarioTravelFromJson(JsonNode & reader, int version);
static CCampaignScenario readScenarioFromJson(JsonNode & reader);
static CScenarioTravel readScenarioTravelFromJson(JsonNode & reader);
//parsers for original H3C campaigns
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);
/// 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