mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Use inheritance instead of composition for campaign header
This commit is contained in:
parent
a08fe09517
commit
f6b2f58da9
@ -64,7 +64,7 @@ CBonusSelection::CBonusSelection()
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
|
||||
std::string bgName = getCampaign()->getHeader().campaignRegions.campPrefix + "_BG.BMP";
|
||||
std::string bgName = getCampaign()->getRegions().campPrefix + "_BG.BMP";
|
||||
setBackground(bgName);
|
||||
|
||||
panelBackground = std::make_shared<CPicture>("CAMPBRF.BMP", 456, 6);
|
||||
@ -78,7 +78,7 @@ CBonusSelection::CBonusSelection()
|
||||
iconsMapSizes = std::make_shared<CAnimImage>("SCNRMPSZ", 4, 0, 735, 26);
|
||||
|
||||
labelCampaignDescription = std::make_shared<CLabel>(481, 63, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[38]);
|
||||
campaignDescription = std::make_shared<CTextBox>(getCampaign()->getHeader().description, Rect(480, 86, 286, 117), 1);
|
||||
campaignDescription = std::make_shared<CTextBox>(getCampaign()->getDescription(), Rect(480, 86, 286, 117), 1);
|
||||
|
||||
mapName = std::make_shared<CLabel>(481, 219, FONT_BIG, ETextAlignment::TOPLEFT, Colors::YELLOW, CSH->mi->getName());
|
||||
labelMapDescription = std::make_shared<CLabel>(481, 253, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[496]);
|
||||
@ -99,7 +99,7 @@ CBonusSelection::CBonusSelection()
|
||||
difficultyIcons[b] = std::make_shared<CAnimImage>("GSPBUT" + std::to_string(b + 3) + ".DEF", 0, 0, 709, 455);
|
||||
}
|
||||
|
||||
if(getCampaign()->getHeader().difficultyChoosenByPlayer)
|
||||
if(getCampaign()->playerSelectedDifficulty())
|
||||
{
|
||||
buttonDifficultyLeft = std::make_shared<CButton>(Point(694, 508), "SCNRBLF.DEF", CButton::tooltip(), std::bind(&CBonusSelection::decreaseDifficulty, this));
|
||||
buttonDifficultyRight = std::make_shared<CButton>(Point(738, 508), "SCNRBRT.DEF", CButton::tooltip(), std::bind(&CBonusSelection::increaseDifficulty, this));
|
||||
@ -108,9 +108,9 @@ CBonusSelection::CBonusSelection()
|
||||
for(auto scenarioID : getCampaign()->allScenarios())
|
||||
{
|
||||
if(getCampaign()->isAvailable(scenarioID))
|
||||
regions.push_back(std::make_shared<CRegion>(scenarioID, true, true, getCampaign()->getHeader().campaignRegions));
|
||||
regions.push_back(std::make_shared<CRegion>(scenarioID, true, true, getCampaign()->getRegions()));
|
||||
else if(getCampaign()->isConquered(scenarioID)) //display as striped
|
||||
regions.push_back(std::make_shared<CRegion>(scenarioID, false, false, getCampaign()->getHeader().campaignRegions));
|
||||
regions.push_back(std::make_shared<CRegion>(scenarioID, false, false, getCampaign()->getRegions()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ void CBonusSelection::createBonusesIcons()
|
||||
assert(faction != -1);
|
||||
|
||||
BuildingID buildID;
|
||||
if(getCampaign()->getHeader().version == CampaignVersion::VCMI)
|
||||
if(getCampaign()->formatVCMI())
|
||||
buildID = BuildingID(bonDescs[i].info1);
|
||||
else
|
||||
buildID = CBuildingHandler::campToERMU(bonDescs[i].info1, faction, std::set<BuildingID>());
|
||||
|
@ -104,13 +104,11 @@ bool mapSorter::operator()(const std::shared_ptr<CMapInfo> aaa, const std::share
|
||||
switch(sortBy)
|
||||
{
|
||||
case _numOfMaps: //by number of maps in campaign
|
||||
return aaa->campaignHeader->numberOfScenarios <
|
||||
bbb->campaignHeader->numberOfScenarios;
|
||||
break;
|
||||
return aaa->campaign->scenariosCount() < bbb->campaign->scenariosCount();
|
||||
case _name: //by name
|
||||
return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name);
|
||||
return boost::ilexicographical_compare(aaa->campaign->getName(), bbb->campaign->getName());
|
||||
default:
|
||||
return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name);
|
||||
return boost::ilexicographical_compare(aaa->campaign->getName(), bbb->campaign->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -623,7 +621,7 @@ void SelectionTab::parseCampaigns(const std::unordered_set<ResourceID> & files)
|
||||
//allItems[i].date = std::asctime(std::localtime(&files[i].date));
|
||||
info->fileURI = file.getName();
|
||||
info->campaignInit();
|
||||
if(info->campaignHeader)
|
||||
if(info->campaign)
|
||||
allItems.push_back(info);
|
||||
}
|
||||
}
|
||||
@ -677,7 +675,7 @@ void SelectionTab::ListItem::updateItem(std::shared_ptr<CMapInfo> info, bool sel
|
||||
}
|
||||
|
||||
auto color = selected ? Colors::YELLOW : Colors::WHITE;
|
||||
if(info->campaignHeader)
|
||||
if(info->campaign)
|
||||
{
|
||||
labelAmountOfPlayers->disable();
|
||||
labelMapSizeLetter->disable();
|
||||
@ -686,7 +684,7 @@ void SelectionTab::ListItem::updateItem(std::shared_ptr<CMapInfo> info, bool sel
|
||||
iconLossCondition->disable();
|
||||
labelNumberOfCampaignMaps->enable();
|
||||
std::ostringstream ostr(std::ostringstream::out);
|
||||
ostr << info->campaignHeader->numberOfScenarios;
|
||||
ostr << info->campaign->scenariosCount();
|
||||
labelNumberOfCampaignMaps->setText(ostr.str());
|
||||
labelNumberOfCampaignMaps->setColor(color);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config)
|
||||
status = config["open"].Bool() ? CCampaignScreen::ENABLED : CCampaignScreen::DISABLED;
|
||||
|
||||
auto header = CampaignHandler::getHeader(campFile);
|
||||
hoverText = header->name;
|
||||
hoverText = header->getName();
|
||||
|
||||
if(status != CCampaignScreen::DISABLED)
|
||||
{
|
||||
|
@ -923,7 +923,7 @@ void CCastleBuildings::enterMagesGuild()
|
||||
const StartInfo *si = LOCPLINT->cb->getStartInfo();
|
||||
// it would be nice to find a way to move this hack to config/mapOverrides.json
|
||||
if(si && si->campState && si->campState && // We're in campaign,
|
||||
(si->campState->getHeader().filename == "DATA/YOG.H3C") && // which is "Birth of a Barbarian",
|
||||
(si->campState->getFilename() == "DATA/YOG.H3C") && // which is "Birth of a Barbarian",
|
||||
(hero->subID == 45)) // and the hero is Yog (based on Solmyr)
|
||||
{
|
||||
// "Yog has given up magic in all its forms..."
|
||||
|
@ -62,8 +62,8 @@ PlayerSettings * StartInfo::getPlayersSettings(const ui8 connectedPlayerId)
|
||||
|
||||
std::string StartInfo::getCampaignName() const
|
||||
{
|
||||
if(campState->getHeader().name.empty())
|
||||
return campState->getHeader().name;
|
||||
if(campState->getName().empty())
|
||||
return campState->getName();
|
||||
else
|
||||
return VLC->generaltexth->allTexts[508];
|
||||
}
|
||||
|
@ -27,26 +27,49 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
std::unique_ptr<CampaignHeader> CampaignHandler::getHeader( const std::string & name)
|
||||
void CampaignHandler::readCampaign(Campaign * ret, const std::vector<ui8> & input, std::string filename, std::string modName, std::string encoding)
|
||||
{
|
||||
if (input.front() < uint8_t(' ')) // binary format
|
||||
{
|
||||
CMemoryStream stream(input.data(), input.size());
|
||||
CBinaryReader reader(&stream);
|
||||
|
||||
readHeaderFromMemory(*ret, reader, filename, modName, encoding);
|
||||
|
||||
for(int g = 0; g < ret->numberOfScenarios; ++g)
|
||||
{
|
||||
auto scenarioID = static_cast<CampaignScenarioID>(ret->scenarios.size());
|
||||
ret->scenarios[scenarioID] = readScenarioFromMemory(reader, *ret);
|
||||
}
|
||||
}
|
||||
else // text format (json)
|
||||
{
|
||||
JsonNode jsonCampaign((const char*)input.data(), input.size());
|
||||
readHeaderFromJson(*ret, jsonCampaign, filename, modName, encoding);
|
||||
|
||||
for(auto & scenario : jsonCampaign["scenarios"].Vector())
|
||||
{
|
||||
auto scenarioID = static_cast<CampaignScenarioID>(ret->scenarios.size());
|
||||
ret->scenarios[scenarioID] = readScenarioFromJson(scenario);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Campaign> CampaignHandler::getHeader( const std::string & name)
|
||||
{
|
||||
ResourceID resourceID(name, EResType::CAMPAIGN);
|
||||
std::string modName = VLC->modh->findResourceOrigin(resourceID);
|
||||
std::string language = VLC->modh->getModLanguage(modName);
|
||||
std::string encoding = Languages::getLanguageOptions(language).encoding;
|
||||
|
||||
auto ret = std::make_unique<Campaign>();
|
||||
auto fileStream = CResourceHandler::get(modName)->load(resourceID);
|
||||
std::vector<ui8> cmpgn = getFile(std::move(fileStream), true)[0];
|
||||
JsonNode jsonCampaign((const char*)cmpgn.data(), cmpgn.size());
|
||||
if(jsonCampaign.isNull())
|
||||
{
|
||||
//legacy OH3 campaign (*.h3c)
|
||||
CMemoryStream stream(cmpgn.data(), cmpgn.size());
|
||||
CBinaryReader reader(&stream);
|
||||
return std::make_unique<CampaignHeader>(readHeaderFromMemory(reader, resourceID.getName(), modName, encoding));
|
||||
}
|
||||
|
||||
//VCMI (*.vcmp)
|
||||
return std::make_unique<CampaignHeader>(readHeaderFromJson(jsonCampaign, resourceID.getName(), modName, encoding));
|
||||
|
||||
readCampaign(ret.get(), cmpgn, resourceID.getName(), modName, encoding);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<CampaignState> CampaignHandler::getCampaign( const std::string & name )
|
||||
@ -62,32 +85,10 @@ std::shared_ptr<CampaignState> CampaignHandler::getCampaign( const std::string &
|
||||
|
||||
std::vector<std::vector<ui8>> files = getFile(std::move(fileStream), false);
|
||||
|
||||
if (files[0].front() < uint8_t(' ')) // binary format
|
||||
{
|
||||
CMemoryStream stream(files[0].data(), files[0].size());
|
||||
CBinaryReader reader(&stream);
|
||||
ret->header = readHeaderFromMemory(reader, resourceID.getName(), modName, encoding);
|
||||
|
||||
for(int g = 0; g < ret->header.numberOfScenarios; ++g)
|
||||
{
|
||||
auto scenarioID = static_cast<CampaignScenarioID>(ret->scenarios.size());
|
||||
ret->scenarios[scenarioID] = readScenarioFromMemory(reader, ret->header);
|
||||
}
|
||||
}
|
||||
else // text format (json)
|
||||
{
|
||||
JsonNode jsonCampaign((const char*)files[0].data(), files[0].size());
|
||||
ret->header = readHeaderFromJson(jsonCampaign, resourceID.getName(), modName, encoding);
|
||||
|
||||
for(auto & scenario : jsonCampaign["scenarios"].Vector())
|
||||
{
|
||||
auto scenarioID = static_cast<CampaignScenarioID>(ret->scenarios.size());
|
||||
ret->scenarios[scenarioID] = readScenarioFromJson(scenario);
|
||||
}
|
||||
}
|
||||
readCampaign(ret.get(), files[0], resourceID.getName(), modName, encoding);
|
||||
|
||||
//first entry is campaign header. start loop from 1
|
||||
for(int scenarioID = 0, g = 1; g < files.size() && scenarioID < ret->header.numberOfScenarios; ++g)
|
||||
for(int scenarioID = 0, g = 1; g < files.size() && scenarioID < ret->numberOfScenarios; ++g)
|
||||
{
|
||||
auto id = static_cast<CampaignScenarioID>(scenarioID);
|
||||
|
||||
@ -140,15 +141,13 @@ std::string CampaignHandler::readLocalizedString(CBinaryReader & reader, std::st
|
||||
return VLC->generaltexth->translate(stringID.get());
|
||||
}
|
||||
|
||||
CampaignHeader CampaignHandler::readHeaderFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding)
|
||||
void CampaignHandler::readHeaderFromJson(CampaignHeader & ret, JsonNode & reader, std::string filename, std::string modName, std::string encoding)
|
||||
{
|
||||
CampaignHeader ret;
|
||||
|
||||
ret.version = static_cast<CampaignVersion>(reader["version"].Integer());
|
||||
if(ret.version < CampaignVersion::VCMI_MIN || ret.version > CampaignVersion::VCMI_MAX)
|
||||
{
|
||||
logGlobal->info("VCMP Loading: Unsupported campaign %s version %d", filename, static_cast<int>(ret.version));
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
ret.version = CampaignVersion::VCMI;
|
||||
@ -161,7 +160,6 @@ CampaignHeader CampaignHandler::readHeaderFromJson(JsonNode & reader, std::strin
|
||||
ret.filename = filename;
|
||||
ret.modName = modName;
|
||||
ret.encoding = encoding;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CampaignScenario CampaignHandler::readScenarioFromJson(JsonNode & reader)
|
||||
@ -383,10 +381,8 @@ CampaignTravel CampaignHandler::readScenarioTravelFromJson(JsonNode & reader)
|
||||
}
|
||||
|
||||
|
||||
CampaignHeader CampaignHandler::readHeaderFromMemory( CBinaryReader & reader, std::string filename, std::string modName, std::string encoding )
|
||||
void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding )
|
||||
{
|
||||
CampaignHeader ret;
|
||||
|
||||
ret.version = static_cast<CampaignVersion>(reader.readUInt32());
|
||||
ui8 campId = reader.readUInt8() - 1;//change range of it from [1, 20] to [0, 19]
|
||||
ret.loadLegacyData(campId);
|
||||
@ -400,7 +396,6 @@ CampaignHeader CampaignHandler::readHeaderFromMemory( CBinaryReader & reader, st
|
||||
ret.filename = filename;
|
||||
ret.modName = modName;
|
||||
ret.encoding = encoding;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CampaignScenario CampaignHandler::readScenarioFromMemory( CBinaryReader & reader, const CampaignHeader & header)
|
||||
|
@ -16,14 +16,16 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
class DLL_LINKAGE CampaignHandler
|
||||
{
|
||||
static std::string readLocalizedString(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding, std::string identifier);
|
||||
|
||||
|
||||
static void readCampaign(Campaign * target, const std::vector<ui8> & stream, std::string filename, std::string modName, std::string encoding);
|
||||
|
||||
//parsers for VCMI campaigns (*.vcmp)
|
||||
static CampaignHeader readHeaderFromJson(JsonNode & reader, std::string filename, std::string modName, std::string encoding);
|
||||
static void readHeaderFromJson(CampaignHeader & target, JsonNode & reader, std::string filename, std::string modName, std::string encoding);
|
||||
static CampaignScenario readScenarioFromJson(JsonNode & reader);
|
||||
static CampaignTravel readScenarioTravelFromJson(JsonNode & reader);
|
||||
|
||||
//parsers for original H3C campaigns
|
||||
static CampaignHeader readHeaderFromMemory(CBinaryReader & reader, std::string filename, std::string modName, std::string encoding);
|
||||
static void readHeaderFromMemory(CampaignHeader & target, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding);
|
||||
static CampaignScenario readScenarioFromMemory(CBinaryReader & reader, const CampaignHeader & header);
|
||||
static CampaignTravel readScenarioTravelFromMemory(CBinaryReader & reader, CampaignVersion version);
|
||||
/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
|
||||
@ -35,7 +37,7 @@ class DLL_LINKAGE CampaignHandler
|
||||
static std::string prologVoiceName(ui8 index);
|
||||
|
||||
public:
|
||||
static std::unique_ptr<CampaignHeader> getHeader( const std::string & name); //name - name of appropriate file
|
||||
static std::unique_ptr<Campaign> getHeader( const std::string & name); //name - name of appropriate file
|
||||
|
||||
static std::shared_ptr<CampaignState> getCampaign(const std::string & name); //name - name of appropriate file
|
||||
};
|
||||
|
@ -83,6 +83,36 @@ void CampaignHeader::loadLegacyData(ui8 campId)
|
||||
numberOfScenarios = VLC->generaltexth->getCampaignLength(campId);
|
||||
}
|
||||
|
||||
bool CampaignHeader::playerSelectedDifficulty() const
|
||||
{
|
||||
return difficultyChoosenByPlayer;
|
||||
}
|
||||
|
||||
bool CampaignHeader::formatVCMI() const
|
||||
{
|
||||
return version == CampaignVersion::VCMI;
|
||||
}
|
||||
|
||||
std::string CampaignHeader::getDescription() const
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
std::string CampaignHeader::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string CampaignHeader::getFilename() const
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
const CampaignRegions & CampaignHeader::getRegions() const
|
||||
{
|
||||
return campaignRegions;
|
||||
}
|
||||
|
||||
bool CampaignState::isConquered(CampaignScenarioID whichScenario) const
|
||||
{
|
||||
return vstd::contains(mapsConquered, whichScenario);
|
||||
@ -91,7 +121,7 @@ bool CampaignState::isConquered(CampaignScenarioID whichScenario) const
|
||||
bool CampaignState::isAvailable(CampaignScenarioID whichScenario) const
|
||||
{
|
||||
//check for void scenraio
|
||||
if (!scenarios.at(whichScenario).isNotVoid())
|
||||
if (!scenario(whichScenario).isNotVoid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -101,7 +131,7 @@ bool CampaignState::isAvailable(CampaignScenarioID whichScenario) const
|
||||
return false;
|
||||
}
|
||||
//check preconditioned regions
|
||||
for (auto const & it : scenarios.at(whichScenario).preconditionRegions)
|
||||
for (auto const & it : scenario(whichScenario).preconditionRegions)
|
||||
{
|
||||
if (!vstd::contains(mapsConquered, it))
|
||||
return false;
|
||||
@ -174,23 +204,21 @@ void CampaignState::setCurrentMapAsConquered(const std::vector<CGHeroInstance *>
|
||||
mapsConquered.push_back(*currentMap);
|
||||
}
|
||||
|
||||
std::optional<CampaignBonus> CampaignState::getBonusForCurrentMap() const
|
||||
std::optional<CampaignBonus> CampaignState::getBonus(CampaignScenarioID which) const
|
||||
{
|
||||
auto bonuses = getCurrentScenario().travelOptions.bonusesToChoose;
|
||||
auto bonuses = scenario(which).travelOptions.bonusesToChoose;
|
||||
assert(chosenCampaignBonuses.count(*currentMap) || bonuses.size() == 0);
|
||||
|
||||
if(bonuses.empty())
|
||||
return std::optional<CampaignBonus>();
|
||||
else
|
||||
return bonuses[currentBonusID()];
|
||||
|
||||
if (!getBonusID(which))
|
||||
return std::optional<CampaignBonus>();
|
||||
|
||||
return bonuses[getBonusID(which).value()];
|
||||
}
|
||||
|
||||
const CampaignScenario & CampaignState::getCurrentScenario() const
|
||||
{
|
||||
return scenarios.at(*currentMap);
|
||||
}
|
||||
|
||||
std::optional<ui8> CampaignState::getBonusID(CampaignScenarioID & which) const
|
||||
std::optional<ui8> CampaignState::getBonusID(CampaignScenarioID which) const
|
||||
{
|
||||
if (!chosenCampaignBonuses.count(which))
|
||||
return std::nullopt;
|
||||
@ -198,11 +226,6 @@ std::optional<ui8> CampaignState::getBonusID(CampaignScenarioID & which) const
|
||||
return chosenCampaignBonuses.at(which);
|
||||
}
|
||||
|
||||
ui8 CampaignState::currentBonusID() const
|
||||
{
|
||||
return chosenCampaignBonuses.at(*currentMap);
|
||||
}
|
||||
|
||||
std::unique_ptr<CMap> CampaignState::getMap(CampaignScenarioID scenarioId) const
|
||||
{
|
||||
// FIXME: there is certainly better way to handle maps inside campaigns
|
||||
@ -210,12 +233,12 @@ std::unique_ptr<CMap> CampaignState::getMap(CampaignScenarioID scenarioId) const
|
||||
scenarioId = currentMap.value();
|
||||
|
||||
CMapService mapService;
|
||||
std::string scenarioName = header.filename.substr(0, header.filename.find('.'));
|
||||
std::string scenarioName = filename.substr(0, filename.find('.'));
|
||||
boost::to_lower(scenarioName);
|
||||
scenarioName += ':' + std::to_string(static_cast<int>(scenarioId));
|
||||
const std::string & mapContent = mapPieces.find(scenarioId)->second;
|
||||
const auto * buffer = reinterpret_cast<const ui8 *>(mapContent.data());
|
||||
return mapService.loadMap(buffer, static_cast<int>(mapContent.size()), scenarioName, header.modName, header.encoding);
|
||||
return mapService.loadMap(buffer, static_cast<int>(mapContent.size()), scenarioName, modName, encoding);
|
||||
}
|
||||
|
||||
std::unique_ptr<CMapHeader> CampaignState::getMapHeader(CampaignScenarioID scenarioId) const
|
||||
@ -224,12 +247,12 @@ std::unique_ptr<CMapHeader> CampaignState::getMapHeader(CampaignScenarioID scena
|
||||
scenarioId = currentMap.value();
|
||||
|
||||
CMapService mapService;
|
||||
std::string scenarioName = header.filename.substr(0, header.filename.find('.'));
|
||||
std::string scenarioName = filename.substr(0, filename.find('.'));
|
||||
boost::to_lower(scenarioName);
|
||||
scenarioName += ':' + std::to_string(static_cast<int>(scenarioId));
|
||||
const std::string & mapContent = mapPieces.find(scenarioId)->second;
|
||||
const auto * buffer = reinterpret_cast<const ui8 *>(mapContent.data());
|
||||
return mapService.loadMapHeader(buffer, static_cast<int>(mapContent.size()), scenarioName, header.modName, header.encoding);
|
||||
return mapService.loadMapHeader(buffer, static_cast<int>(mapContent.size()), scenarioName, modName, encoding);
|
||||
}
|
||||
|
||||
std::shared_ptr<CMapInfo> CampaignState::getMapInfo(CampaignScenarioID scenarioId) const
|
||||
@ -238,7 +261,7 @@ std::shared_ptr<CMapInfo> CampaignState::getMapInfo(CampaignScenarioID scenarioI
|
||||
scenarioId = currentMap.value();
|
||||
|
||||
auto mapInfo = std::make_shared<CMapInfo>();
|
||||
mapInfo->fileURI = header.filename;
|
||||
mapInfo->fileURI = filename;
|
||||
mapInfo->mapHeader = getMapHeader(scenarioId);
|
||||
mapInfo->countPlayers();
|
||||
return mapInfo;
|
||||
@ -263,8 +286,7 @@ CGHeroInstance * CampaignState::crossoverDeserialize(const JsonNode & node)
|
||||
|
||||
void CampaignState::setCurrentMap(CampaignScenarioID which)
|
||||
{
|
||||
assert(scenarios.count(which));
|
||||
assert(scenarios.at(which).isNotVoid());
|
||||
assert(scenario(which).isNotVoid());
|
||||
|
||||
currentMap = which;
|
||||
}
|
||||
@ -293,7 +315,7 @@ std::set<CampaignScenarioID> CampaignState::conqueredScenarios() const
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<CampaignScenarioID> CampaignState::allScenarios() const
|
||||
std::set<CampaignScenarioID> Campaign::allScenarios() const
|
||||
{
|
||||
std::set<CampaignScenarioID> result;
|
||||
|
||||
@ -306,7 +328,12 @@ std::set<CampaignScenarioID> CampaignState::allScenarios() const
|
||||
return result;
|
||||
}
|
||||
|
||||
const CampaignScenario & CampaignState::scenario(CampaignScenarioID which) const
|
||||
int Campaign::scenariosCount() const
|
||||
{
|
||||
return allScenarios().size();
|
||||
}
|
||||
|
||||
const CampaignScenario & Campaign::scenario(CampaignScenarioID which) const
|
||||
{
|
||||
assert(scenarios.count(which));
|
||||
assert(scenarios.at(which).isNotVoid());
|
||||
@ -318,8 +345,3 @@ bool CampaignState::isCampaignFinished() const
|
||||
{
|
||||
return conqueredScenarios() == allScenarios();
|
||||
}
|
||||
|
||||
const CampaignHeader & CampaignState::getHeader() const
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
@ -57,9 +57,10 @@ struct DLL_LINKAGE CampaignRegions
|
||||
static CampaignRegions getLegacy(int campId);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CampaignHeader
|
||||
class DLL_LINKAGE CampaignHeader : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
friend class CampaignHandler;
|
||||
|
||||
int numberOfScenarios = 0;
|
||||
CampaignVersion version = CampaignVersion::NONE;
|
||||
CampaignRegions campaignRegions;
|
||||
@ -69,10 +70,21 @@ public:
|
||||
|
||||
void loadLegacyData(ui8 campId);
|
||||
|
||||
protected:
|
||||
std::string filename;
|
||||
std::string modName;
|
||||
std::string encoding;
|
||||
|
||||
public:
|
||||
bool playerSelectedDifficulty() const;
|
||||
bool formatVCMI() const;
|
||||
|
||||
std::string getDescription() const;
|
||||
std::string getName() const;
|
||||
std::string getFilename() const;
|
||||
|
||||
const CampaignRegions & getRegions() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & version;
|
||||
@ -195,34 +207,48 @@ struct DLL_LINKAGE CampaignHeroes
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CampaignState
|
||||
/// Class that represents loaded campaign information
|
||||
class DLL_LINKAGE Campaign : public CampaignHeader
|
||||
{
|
||||
friend class CampaignHandler;
|
||||
|
||||
std::map<CampaignScenarioID, CampaignScenario> scenarios;
|
||||
|
||||
public:
|
||||
const CampaignScenario & scenario(CampaignScenarioID which) const;
|
||||
std::set<CampaignScenarioID> allScenarios() const;
|
||||
int scenariosCount() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CampaignHeader&>(*this);
|
||||
h & scenarios;
|
||||
}
|
||||
};
|
||||
|
||||
/// Class that represent campaign that is being played at
|
||||
/// Contains campaign itself as well as current state of the campaign
|
||||
class DLL_LINKAGE CampaignState : public Campaign
|
||||
{
|
||||
friend class CampaignHandler;
|
||||
|
||||
/// List of all maps completed by player, in order of their completion
|
||||
std::vector<CampaignScenarioID> mapsConquered;
|
||||
|
||||
std::map<CampaignScenarioID, CampaignScenario> scenarios;
|
||||
std::map<CampaignScenarioID, std::string > mapPieces; //binary h3ms, scenario number -> map data
|
||||
std::map<CampaignScenarioID, ui8> chosenCampaignBonuses;
|
||||
std::optional<CampaignScenarioID> currentMap;
|
||||
|
||||
CampaignHeader header;
|
||||
CampaignHeroes crossover;
|
||||
|
||||
public:
|
||||
std::optional<CampaignScenarioID> lastScenario() const;
|
||||
std::optional<CampaignScenarioID> currentScenario() const;
|
||||
std::set<CampaignScenarioID> allScenarios() const;
|
||||
std::set<CampaignScenarioID> conqueredScenarios() const;
|
||||
|
||||
const CampaignScenario & scenario(CampaignScenarioID which) const;
|
||||
std::optional<CampaignBonus> getBonus(CampaignScenarioID which) const;
|
||||
|
||||
std::optional<CampaignBonus> getBonusForCurrentMap() const;
|
||||
const CampaignScenario & getCurrentScenario() const;
|
||||
|
||||
std::optional<ui8> getBonusID(CampaignScenarioID & which) const;
|
||||
ui8 currentBonusID() const;
|
||||
std::optional<ui8> getBonusID(CampaignScenarioID which) const;
|
||||
|
||||
/// Returns true if selected scenario can be selected and started by player
|
||||
bool isAvailable(CampaignScenarioID whichScenario) const;
|
||||
@ -233,8 +259,6 @@ public:
|
||||
/// Returns true if all available scenarios have been completed and campaign is finished
|
||||
bool isCampaignFinished() const;
|
||||
|
||||
const CampaignHeader & getHeader() const;
|
||||
|
||||
std::unique_ptr<CMap> getMap(CampaignScenarioID scenarioId) const;
|
||||
std::unique_ptr<CMapHeader> getMapHeader(CampaignScenarioID scenarioId) const;
|
||||
std::shared_ptr<CMapInfo> getMapInfo(CampaignScenarioID scenarioId) const;
|
||||
@ -257,8 +281,7 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & header;
|
||||
h & scenarios;
|
||||
h & static_cast<Campaign&>(*this);
|
||||
h & crossover;
|
||||
h & mapPieces;
|
||||
h & mapsConquered;
|
||||
|
@ -54,12 +54,19 @@ CGameStateCampaign::CGameStateCampaign(CGameState * owner):
|
||||
assert(gameState->scenarioOps->campState != nullptr);
|
||||
}
|
||||
|
||||
std::optional<CampaignBonus> CGameStateCampaign::currentBonus() const
|
||||
{
|
||||
auto campaignState = gameState->scenarioOps->campState;
|
||||
return campaignState->getBonus(*campaignState->currentScenario());
|
||||
|
||||
}
|
||||
|
||||
CrossoverHeroesList CGameStateCampaign::getCrossoverHeroesFromPreviousScenarios() const
|
||||
{
|
||||
CrossoverHeroesList crossoverHeroes;
|
||||
|
||||
auto campaignState = gameState->scenarioOps->campState;
|
||||
auto bonus = campaignState->getBonusForCurrentMap();
|
||||
auto bonus = currentBonus();
|
||||
if(bonus && bonus->type == CampaignBonusType::HEROES_FROM_PREVIOUS_SCENARIO)
|
||||
{
|
||||
auto scenarioID = static_cast<CampaignScenarioID>(bonus->info2);
|
||||
@ -253,7 +260,8 @@ void CGameStateCampaign::placeCampaignHeroes()
|
||||
// - exception: if starting bonus is 'select player' then power placeholders are taken from 'scenario pool' of linked map
|
||||
|
||||
// place bonus hero
|
||||
auto campaignBonus = gameState->scenarioOps->campState->getBonusForCurrentMap();
|
||||
auto campaignState = gameState->scenarioOps->campState;
|
||||
auto campaignBonus = campaignState->getBonus(*campaignState->currentScenario());
|
||||
bool campaignGiveHero = campaignBonus && campaignBonus->type == CampaignBonusType::HERO;
|
||||
|
||||
if(campaignGiveHero)
|
||||
@ -281,7 +289,7 @@ void CGameStateCampaign::placeCampaignHeroes()
|
||||
auto campaignHeroReplacements = generateCampaignHeroesToReplace(crossoverHeroes);
|
||||
|
||||
logGlobal->debug("\tPrepare crossover heroes");
|
||||
trimCrossoverHeroesParameters(campaignHeroReplacements, gameState->scenarioOps->campState->getCurrentScenario().travelOptions);
|
||||
trimCrossoverHeroesParameters(campaignHeroReplacements, campaignState->scenario(*campaignState->currentScenario()).travelOptions);
|
||||
|
||||
// remove same heroes on the map which will be added through crossover heroes
|
||||
// INFO: we will remove heroes because later it may be possible that the API doesn't allow having heroes
|
||||
@ -338,7 +346,7 @@ void CGameStateCampaign::placeCampaignHeroes()
|
||||
|
||||
void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
|
||||
{
|
||||
const std::optional<CampaignBonus> & curBonus = gameState->scenarioOps->campState->getBonusForCurrentMap();
|
||||
auto curBonus = currentBonus();
|
||||
if(!curBonus)
|
||||
return;
|
||||
|
||||
@ -513,7 +521,7 @@ std::vector<CampaignHeroReplacement> CGameStateCampaign::generateCampaignHeroesT
|
||||
|
||||
void CGameStateCampaign::initHeroes()
|
||||
{
|
||||
auto chosenBonus = gameState->scenarioOps->campState->getBonusForCurrentMap();
|
||||
auto chosenBonus = currentBonus();
|
||||
if (chosenBonus && chosenBonus->isBonusForHero() && chosenBonus->info1 != 0xFFFE) //exclude generated heroes
|
||||
{
|
||||
//find human player
|
||||
@ -573,7 +581,7 @@ void CGameStateCampaign::initStartingResources()
|
||||
return ret;
|
||||
};
|
||||
|
||||
auto chosenBonus = gameState->scenarioOps->campState->getBonusForCurrentMap();
|
||||
auto chosenBonus = currentBonus();
|
||||
if(chosenBonus && chosenBonus->type == CampaignBonusType::RESOURCE)
|
||||
{
|
||||
std::vector<const PlayerSettings *> people = getHumanPlayerInfo(); //players we will give resource bonus
|
||||
@ -610,7 +618,7 @@ void CGameStateCampaign::initStartingResources()
|
||||
|
||||
void CGameStateCampaign::initTowns()
|
||||
{
|
||||
auto chosenBonus = gameState->scenarioOps->campState->getBonusForCurrentMap();
|
||||
auto chosenBonus = currentBonus();
|
||||
|
||||
if (chosenBonus && chosenBonus->type == CampaignBonusType::BUILDING)
|
||||
{
|
||||
@ -625,7 +633,7 @@ void CGameStateCampaign::initTowns()
|
||||
gameState->map->towns[g]->pos == pi.posOfMainTown)
|
||||
{
|
||||
BuildingID buildingId;
|
||||
if(gameState->scenarioOps->campState->getHeader().version == CampaignVersion::VCMI)
|
||||
if(gameState->scenarioOps->campState->formatVCMI())
|
||||
buildingId = BuildingID(chosenBonus->info1);
|
||||
else
|
||||
buildingId = CBuildingHandler::campToERMU(chosenBonus->info1, gameState->map->towns[g]->subID, gameState->map->towns[g]->builtBuildings);
|
||||
@ -640,7 +648,7 @@ void CGameStateCampaign::initTowns()
|
||||
|
||||
bool CGameStateCampaign::playerHasStartingHero(PlayerColor playerColor) const
|
||||
{
|
||||
auto campaignBonus = gameState->scenarioOps->campState->getBonusForCurrentMap();
|
||||
auto campaignBonus = currentBonus();
|
||||
|
||||
if (!campaignBonus)
|
||||
return false;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct CampaignBonus;
|
||||
class CampaignTravel;
|
||||
class CGHeroInstance;
|
||||
class CGameState;
|
||||
@ -42,6 +43,8 @@ class CGameStateCampaign
|
||||
/// returns heroes and placeholders in where heroes will be put
|
||||
std::vector<CampaignHeroReplacement> generateCampaignHeroesToReplace(CrossoverHeroesList & crossoverHeroes);
|
||||
|
||||
std::optional<CampaignBonus> currentBonus() const;
|
||||
|
||||
/// Trims hero parameters that should not transfer between scenarios according to travelOptions flags
|
||||
void trimCrossoverHeroesParameters(std::vector<CampaignHeroReplacement> & campaignHeroReplacements, const CampaignTravel & travelOptions);
|
||||
|
||||
|
@ -66,7 +66,7 @@ void CMapInfo::saveInit(const ResourceID & file)
|
||||
|
||||
void CMapInfo::campaignInit()
|
||||
{
|
||||
campaignHeader = CampaignHandler::getHeader(fileURI);
|
||||
campaign = CampaignHandler::getHeader(fileURI);
|
||||
}
|
||||
|
||||
void CMapInfo::countPlayers()
|
||||
@ -92,8 +92,8 @@ void CMapInfo::countPlayers()
|
||||
|
||||
std::string CMapInfo::getName() const
|
||||
{
|
||||
if(campaignHeader && !campaignHeader->name.empty())
|
||||
return campaignHeader->name;
|
||||
if(campaign && !campaign->getName().empty())
|
||||
return campaign->getName();
|
||||
else if(mapHeader && mapHeader->name.length())
|
||||
return mapHeader->name;
|
||||
else
|
||||
@ -117,8 +117,8 @@ std::string CMapInfo::getNameForList() const
|
||||
|
||||
std::string CMapInfo::getDescription() const
|
||||
{
|
||||
if(campaignHeader)
|
||||
return campaignHeader->description;
|
||||
if(campaign)
|
||||
return campaign->getDescription();
|
||||
else
|
||||
return mapHeader->description;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
struct StartInfo;
|
||||
|
||||
class CMapHeader;
|
||||
class CampaignHeader;
|
||||
class Campaign;
|
||||
class ResourceID;
|
||||
|
||||
/**
|
||||
@ -25,7 +25,7 @@ class DLL_LINKAGE CMapInfo
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<CMapHeader> mapHeader; //may be nullptr if campaign
|
||||
std::unique_ptr<CampaignHeader> campaignHeader; //may be nullptr if scenario
|
||||
std::unique_ptr<Campaign> campaign; //may be nullptr if scenario
|
||||
StartInfo * scenarioOptionsOfSave; // Options with which scenario has been started (used only with saved games)
|
||||
std::string fileURI;
|
||||
std::string date;
|
||||
@ -58,7 +58,7 @@ public:
|
||||
template <typename Handler> void serialize(Handler &h, const int Version)
|
||||
{
|
||||
h & mapHeader;
|
||||
h & campaignHeader;
|
||||
h & campaign;
|
||||
h & scenarioOptionsOfSave;
|
||||
h & fileURI;
|
||||
h & date;
|
||||
|
@ -684,7 +684,7 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo,
|
||||
}
|
||||
else if(si->mode == StartInfo::NEW_GAME || si->mode == StartInfo::CAMPAIGN)
|
||||
{
|
||||
if(mi->campaignHeader)
|
||||
if(mi->campaign)
|
||||
return;
|
||||
|
||||
for(int i = 0; i < mi->mapHeader->players.size(); i++)
|
||||
|
@ -211,7 +211,7 @@ void ApplyOnServerNetPackVisitor::visitLobbySetMap(LobbySetMap & pack)
|
||||
|
||||
void ApplyOnServerNetPackVisitor::visitLobbySetCampaign(LobbySetCampaign & pack)
|
||||
{
|
||||
srv.si->mapname = pack.ourCampaign->getHeader().filename;
|
||||
srv.si->mapname = pack.ourCampaign->getFilename();
|
||||
srv.si->mode = StartInfo::CAMPAIGN;
|
||||
srv.si->campState = pack.ourCampaign;
|
||||
srv.si->turnTime = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user