mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
h3c converter implementation
This commit is contained in:
parent
ec25eb557b
commit
a345517776
9
Global.h
9
Global.h
@ -366,6 +366,15 @@ namespace vstd
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// given a map from keys to values, creates a new map from values to keys
|
||||
template<typename K, typename V>
|
||||
static std::map<V, K> reverseMap(const std::map<K, V>& m) {
|
||||
std::map<V, K> r;
|
||||
for (const auto& kv : m)
|
||||
r[kv.second] = kv.first;
|
||||
return r;
|
||||
}
|
||||
|
||||
//returns first key that maps to given value if present, returns success via found if provided
|
||||
template <typename Key, typename T>
|
||||
Key findKey(const std::map<Key, T> & map, const T & value, bool * found = nullptr)
|
||||
|
@ -50,12 +50,14 @@ void CampaignHandler::readCampaign(Campaign * ret, const std::vector<ui8> & inpu
|
||||
{
|
||||
JsonNode jsonCampaign(reinterpret_cast<const std::byte*>(input.data()), input.size(), filename);
|
||||
readHeaderFromJson(*ret, jsonCampaign, filename, modName, encoding);
|
||||
ret->overrideCampaign();
|
||||
|
||||
for(auto & scenario : jsonCampaign["scenarios"].Vector())
|
||||
{
|
||||
auto scenarioID = static_cast<CampaignScenarioID>(ret->scenarios.size());
|
||||
ret->scenarios[scenarioID] = readScenarioFromJson(scenario);
|
||||
}
|
||||
ret->overrideCampaignScenarios();
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,6 +173,26 @@ void CampaignHandler::readHeaderFromJson(CampaignHeader & ret, JsonNode & reader
|
||||
ret.outroVideo = VideoPath::fromJson(reader["outroVideo"]);
|
||||
}
|
||||
|
||||
JsonNode CampaignHandler::writeHeaderToJson(CampaignHeader & header)
|
||||
{
|
||||
JsonNode node;
|
||||
node["version"].Integer() = static_cast<ui64>(CampaignVersion::VCMI);
|
||||
node["regions"] = CampaignRegions::toJson(header.campaignRegions);
|
||||
node["name"].String() = header.name.toString();
|
||||
node["description"].String() = header.description.toString();
|
||||
node["author"].String() = header.author.toString();
|
||||
node["authorContact"].String() = header.authorContact.toString();
|
||||
node["campaignVersion"].String() = header.campaignVersion.toString();
|
||||
node["creationDateTime"].Integer() = header.creationDateTime;
|
||||
node["allowDifficultySelection"].Bool() = header.difficultyChosenByPlayer;
|
||||
node["music"].String() = header.music.getName();
|
||||
node["loadingBackground"].String() = header.loadingBackground.getName();
|
||||
node["videoRim"].String() = header.videoRim.getName();
|
||||
node["introVideo"].String() = header.introVideo.getName();
|
||||
node["outroVideo"].String() = header.outroVideo.getName();
|
||||
return node;
|
||||
}
|
||||
|
||||
CampaignScenario CampaignHandler::readScenarioFromJson(JsonNode & reader)
|
||||
{
|
||||
auto prologEpilogReader = [](JsonNode & identifier) -> CampaignScenarioPrologEpilog
|
||||
@ -203,56 +225,86 @@ CampaignScenario CampaignHandler::readScenarioFromJson(JsonNode & reader)
|
||||
return ret;
|
||||
}
|
||||
|
||||
JsonNode CampaignHandler::writeScenarioToJson(const CampaignScenario & scenario)
|
||||
{
|
||||
auto prologEpilogWriter = [](const CampaignScenarioPrologEpilog & elem) -> JsonNode
|
||||
{
|
||||
JsonNode node;
|
||||
if(elem.hasPrologEpilog)
|
||||
{
|
||||
node["video"].String() = elem.prologVideo.getName();
|
||||
node["music"].String() = elem.prologMusic.getName();
|
||||
node["voice"].String() = elem.prologVoice.getName();
|
||||
node["text"].String() = elem.prologText.toString();
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
JsonNode node;
|
||||
node["map"].String() = scenario.mapName;
|
||||
for(auto & g : scenario.preconditionRegions)
|
||||
node["preconditions"].Vector().push_back(JsonNode(static_cast<ui32>(g)));
|
||||
node["color"].Integer() = scenario.regionColor;
|
||||
node["difficulty"].Integer() = scenario.difficulty;
|
||||
node["regionText"].String() = scenario.regionText.toString();
|
||||
node["prolog"] = prologEpilogWriter(scenario.prolog);
|
||||
node["epilog"] = prologEpilogWriter(scenario.epilog);
|
||||
|
||||
writeScenarioTravelToJson(node, scenario.travelOptions);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::map<std::string, CampaignStartOptions> startOptionsMap = {
|
||||
{"none", CampaignStartOptions::NONE},
|
||||
{"bonus", CampaignStartOptions::START_BONUS},
|
||||
{"crossover", CampaignStartOptions::HERO_CROSSOVER},
|
||||
{"hero", CampaignStartOptions::HERO_OPTIONS}
|
||||
};
|
||||
|
||||
std::map<std::string, CampaignBonusType> bonusTypeMap = {
|
||||
{"spell", CampaignBonusType::SPELL},
|
||||
{"creature", CampaignBonusType::MONSTER},
|
||||
{"building", CampaignBonusType::BUILDING},
|
||||
{"artifact", CampaignBonusType::ARTIFACT},
|
||||
{"scroll", CampaignBonusType::SPELL_SCROLL},
|
||||
{"primarySkill", CampaignBonusType::PRIMARY_SKILL},
|
||||
{"secondarySkill", CampaignBonusType::SECONDARY_SKILL},
|
||||
{"resource", CampaignBonusType::RESOURCE},
|
||||
//{"prevHero", CScenarioTravel::STravelBonus::EBonusType::HEROES_FROM_PREVIOUS_SCENARIO},
|
||||
//{"hero", CScenarioTravel::STravelBonus::EBonusType::HERO},
|
||||
};
|
||||
|
||||
std::map<std::string, ui32> primarySkillsMap = {
|
||||
{"attack", 0},
|
||||
{"defence", 8},
|
||||
{"spellpower", 16},
|
||||
{"knowledge", 24},
|
||||
};
|
||||
|
||||
std::map<std::string, ui16> heroSpecialMap = {
|
||||
{"strongest", 0xFFFD},
|
||||
{"generated", 0xFFFE},
|
||||
{"random", 0xFFFF}
|
||||
};
|
||||
|
||||
std::map<std::string, ui8> resourceTypeMap = {
|
||||
//FD - wood+ore
|
||||
//FE - mercury+sulfur+crystal+gem
|
||||
{"wood", 0},
|
||||
{"mercury", 1},
|
||||
{"ore", 2},
|
||||
{"sulfur", 3},
|
||||
{"crystal", 4},
|
||||
{"gems", 5},
|
||||
{"gold", 6},
|
||||
{"common", 0xFD},
|
||||
{"rare", 0xFE}
|
||||
};
|
||||
|
||||
CampaignTravel CampaignHandler::readScenarioTravelFromJson(JsonNode & reader)
|
||||
{
|
||||
CampaignTravel ret;
|
||||
|
||||
std::map<std::string, CampaignStartOptions> startOptionsMap = {
|
||||
{"none", CampaignStartOptions::NONE},
|
||||
{"bonus", CampaignStartOptions::START_BONUS},
|
||||
{"crossover", CampaignStartOptions::HERO_CROSSOVER},
|
||||
{"hero", CampaignStartOptions::HERO_OPTIONS}
|
||||
};
|
||||
|
||||
std::map<std::string, CampaignBonusType> bonusTypeMap = {
|
||||
{"spell", CampaignBonusType::SPELL},
|
||||
{"creature", CampaignBonusType::MONSTER},
|
||||
{"building", CampaignBonusType::BUILDING},
|
||||
{"artifact", CampaignBonusType::ARTIFACT},
|
||||
{"scroll", CampaignBonusType::SPELL_SCROLL},
|
||||
{"primarySkill", CampaignBonusType::PRIMARY_SKILL},
|
||||
{"secondarySkill", CampaignBonusType::SECONDARY_SKILL},
|
||||
{"resource", CampaignBonusType::RESOURCE},
|
||||
//{"prevHero", CScenarioTravel::STravelBonus::EBonusType::HEROES_FROM_PREVIOUS_SCENARIO},
|
||||
//{"hero", CScenarioTravel::STravelBonus::EBonusType::HERO},
|
||||
};
|
||||
|
||||
std::map<std::string, ui32> primarySkillsMap = {
|
||||
{"attack", 0},
|
||||
{"defence", 8},
|
||||
{"spellpower", 16},
|
||||
{"knowledge", 24},
|
||||
};
|
||||
|
||||
std::map<std::string, ui16> heroSpecialMap = {
|
||||
{"strongest", 0xFFFD},
|
||||
{"generated", 0xFFFE},
|
||||
{"random", 0xFFFF}
|
||||
};
|
||||
|
||||
std::map<std::string, ui8> resourceTypeMap = {
|
||||
//FD - wood+ore
|
||||
//FE - mercury+sulfur+crystal+gem
|
||||
{"wood", 0},
|
||||
{"mercury", 1},
|
||||
{"ore", 2},
|
||||
{"sulfur", 3},
|
||||
{"crystal", 4},
|
||||
{"gems", 5},
|
||||
{"gold", 6},
|
||||
{"common", 0xFD},
|
||||
{"rare", 0xFE}
|
||||
};
|
||||
|
||||
for(auto & k : reader["heroKeeps"].Vector())
|
||||
{
|
||||
@ -390,6 +442,109 @@ CampaignTravel CampaignHandler::readScenarioTravelFromJson(JsonNode & reader)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CampaignHandler::writeScenarioTravelToJson(JsonNode & node, const CampaignTravel & travel)
|
||||
{
|
||||
if(travel.whatHeroKeeps.experience)
|
||||
node["heroKeeps"].Vector().push_back(JsonNode("experience"));
|
||||
if(travel.whatHeroKeeps.primarySkills)
|
||||
node["heroKeeps"].Vector().push_back(JsonNode("primarySkills"));
|
||||
if(travel.whatHeroKeeps.secondarySkills)
|
||||
node["heroKeeps"].Vector().push_back(JsonNode("secondarySkills"));
|
||||
if(travel.whatHeroKeeps.spells)
|
||||
node["heroKeeps"].Vector().push_back(JsonNode("spells"));
|
||||
if(travel.whatHeroKeeps.artifacts)
|
||||
node["heroKeeps"].Vector().push_back(JsonNode("artifacts"));
|
||||
for(auto & c : travel.monstersKeptByHero)
|
||||
node["keepCreatures"].Vector().push_back(JsonNode(CreatureID::encode(c)));
|
||||
for(auto & a : travel.artifactsKeptByHero)
|
||||
node["keepArtifacts"].Vector().push_back(JsonNode(ArtifactID::encode(a)));
|
||||
node["startOptions"].String() = vstd::reverseMap(startOptionsMap)[travel.startOptions];
|
||||
|
||||
switch(travel.startOptions)
|
||||
{
|
||||
case CampaignStartOptions::NONE:
|
||||
break;
|
||||
case CampaignStartOptions::START_BONUS:
|
||||
{
|
||||
node["playerColor"].String() = PlayerColor::encode(travel.playerColor);
|
||||
for(auto & bonus : travel.bonusesToChoose)
|
||||
{
|
||||
JsonNode bnode;
|
||||
bnode["what"].String() = vstd::reverseMap(bonusTypeMap)[bonus.type];
|
||||
switch (bonus.type)
|
||||
{
|
||||
case CampaignBonusType::RESOURCE:
|
||||
bnode["type"].String() = vstd::reverseMap(resourceTypeMap)[bonus.info1];
|
||||
bnode["amount"].Integer() = bonus.info2;
|
||||
break;
|
||||
case CampaignBonusType::BUILDING:
|
||||
bnode["type"].String() = EBuildingType::names[bonus.info1];
|
||||
break;
|
||||
default:
|
||||
if(vstd::contains(vstd::reverseMap(heroSpecialMap), bonus.info1))
|
||||
bnode["hero"].String() = vstd::reverseMap(heroSpecialMap)[bonus.info1];
|
||||
else
|
||||
bnode["hero"].String() = HeroTypeID::encode(bonus.info1);
|
||||
bnode["amount"].Integer() = bonus.info3;
|
||||
switch(bonus.type)
|
||||
{
|
||||
case CampaignBonusType::SPELL:
|
||||
bnode["type"].String() = SpellID::encode(bonus.info2);
|
||||
break;
|
||||
case CampaignBonusType::MONSTER:
|
||||
bnode["type"].String() = CreatureID::encode(bonus.info2);
|
||||
break;
|
||||
case CampaignBonusType::SECONDARY_SKILL:
|
||||
bnode["type"].String() = SecondarySkill::encode(bonus.info2);
|
||||
break;
|
||||
case CampaignBonusType::ARTIFACT:
|
||||
bnode["type"].String() = ArtifactID::encode(bonus.info2);
|
||||
break;
|
||||
case CampaignBonusType::SPELL_SCROLL:
|
||||
bnode["type"].String() = SpellID::encode(bonus.info2);
|
||||
break;
|
||||
case CampaignBonusType::PRIMARY_SKILL:
|
||||
for(auto & ps : primarySkillsMap)
|
||||
bnode[ps.first].Integer() = (bonus.info2 >> ps.second) & 0xff;
|
||||
break;
|
||||
default:
|
||||
bnode["type"].Integer() = bonus.info2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
node["bonuses"].Vector().push_back(bnode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CampaignStartOptions::HERO_CROSSOVER:
|
||||
{
|
||||
for(auto & bonus : travel.bonusesToChoose)
|
||||
{
|
||||
JsonNode bnode;
|
||||
bnode["playerColor"].Integer() = bonus.info1;
|
||||
bnode["scenario"].Integer() = bonus.info2;
|
||||
node["bonuses"].Vector().push_back(bnode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CampaignStartOptions::HERO_OPTIONS:
|
||||
{
|
||||
for(auto & bonus : travel.bonusesToChoose)
|
||||
{
|
||||
JsonNode bnode;
|
||||
bnode["playerColor"].Integer() = bonus.info1;
|
||||
|
||||
if(vstd::contains(vstd::reverseMap(heroSpecialMap), bonus.info2))
|
||||
bnode["hero"].String() = vstd::reverseMap(heroSpecialMap)[bonus.info2];
|
||||
else
|
||||
bnode["hero"].String() = HeroTypeID::encode(bonus.info2);
|
||||
|
||||
node["bonuses"].Vector().push_back(bnode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CampaignHandler::readHeaderFromMemory( CampaignHeader & ret, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding )
|
||||
{
|
||||
|
@ -26,6 +26,9 @@ class DLL_LINKAGE CampaignHandler
|
||||
static CampaignScenario readScenarioFromJson(JsonNode & reader);
|
||||
static CampaignTravel readScenarioTravelFromJson(JsonNode & reader);
|
||||
|
||||
//writer for VCMI campaigns (*.vcmp)
|
||||
static void writeScenarioTravelToJson(JsonNode & node, const CampaignTravel & travel);
|
||||
|
||||
//parsers for original H3C campaigns
|
||||
static void readHeaderFromMemory(CampaignHeader & target, CBinaryReader & reader, std::string filename, std::string modName, std::string encoding);
|
||||
static CampaignScenario readScenarioFromMemory(CBinaryReader & reader, CampaignHeader & header);
|
||||
@ -43,6 +46,10 @@ public:
|
||||
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
|
||||
|
||||
//writer for VCMI campaigns (*.vcmp)
|
||||
static JsonNode writeHeaderToJson(CampaignHeader & header);
|
||||
static JsonNode writeScenarioToJson(const CampaignScenario & scenario);
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -45,6 +45,22 @@ CampaignRegions::RegionDescription CampaignRegions::RegionDescription::fromJson(
|
||||
return rd;
|
||||
}
|
||||
|
||||
JsonNode CampaignRegions::RegionDescription::toJson(CampaignRegions::RegionDescription & rd)
|
||||
{
|
||||
JsonNode node;
|
||||
node["infix"].String() = rd.infix;
|
||||
node["x"].Float() = rd.pos.x;
|
||||
node["y"].Float() = rd.pos.y;
|
||||
if(rd.labelPos != std::nullopt)
|
||||
{
|
||||
node["labelPos"]["x"].Float() = (*rd.labelPos).x;
|
||||
node["labelPos"]["y"].Float() = (*rd.labelPos).y;
|
||||
}
|
||||
else
|
||||
node["labelPos"].clear();
|
||||
return node;
|
||||
}
|
||||
|
||||
CampaignRegions CampaignRegions::fromJson(const JsonNode & node)
|
||||
{
|
||||
CampaignRegions cr;
|
||||
@ -59,6 +75,25 @@ CampaignRegions CampaignRegions::fromJson(const JsonNode & node)
|
||||
return cr;
|
||||
}
|
||||
|
||||
JsonNode CampaignRegions::toJson(CampaignRegions cr)
|
||||
{
|
||||
JsonNode node;
|
||||
node["prefix"].String() = cr.campPrefix;
|
||||
node["colorSuffixLength"].Float() = cr.colorSuffixLength;
|
||||
if(!cr.campSuffix.size())
|
||||
node["suffix"].clear();
|
||||
else
|
||||
node["suffix"].Vector() = JsonVector{ JsonNode(cr.campSuffix[0]), JsonNode(cr.campSuffix[1]), JsonNode(cr.campSuffix[2]) };
|
||||
if(cr.campBackground.empty())
|
||||
node["background"].clear();
|
||||
else
|
||||
node["background"].String() = cr.campBackground;
|
||||
node["desc"].Vector() = JsonVector();
|
||||
for(auto & region : cr.regions)
|
||||
node["desc"].Vector().push_back(CampaignRegions::RegionDescription::toJson(region));
|
||||
return node;
|
||||
}
|
||||
|
||||
CampaignRegions CampaignRegions::getLegacy(int campId)
|
||||
{
|
||||
static std::vector<CampaignRegions> campDescriptions;
|
||||
|
@ -59,6 +59,7 @@ class DLL_LINKAGE CampaignRegions
|
||||
}
|
||||
|
||||
static CampaignRegions::RegionDescription fromJson(const JsonNode & node);
|
||||
static JsonNode toJson(CampaignRegions::RegionDescription & rd);
|
||||
};
|
||||
|
||||
std::vector<RegionDescription> regions;
|
||||
@ -86,6 +87,7 @@ public:
|
||||
}
|
||||
|
||||
static CampaignRegions fromJson(const JsonNode & node);
|
||||
static JsonNode toJson(CampaignRegions cr);
|
||||
static CampaignRegions getLegacy(int campId);
|
||||
};
|
||||
|
||||
|
@ -144,7 +144,7 @@ TModID CModHandler::findResourceOrigin(const ResourcePath & name) const
|
||||
return "core";
|
||||
|
||||
if(CResourceHandler::get("mapEditor")->existsResource(name))
|
||||
return "core"; // Workaround for loading maps via map editor
|
||||
return "mapEditor"; // Workaround for loading maps via map editor
|
||||
}
|
||||
catch( const std::out_of_range & e)
|
||||
{
|
||||
@ -189,6 +189,8 @@ std::string CModHandler::getModLanguage(const TModID& modId) const
|
||||
return VLC->generaltexth->getInstalledLanguage();
|
||||
if(modId == "map")
|
||||
return VLC->generaltexth->getPreferredLanguage();
|
||||
if(modId == "mapEditor")
|
||||
return VLC->generaltexth->getPreferredLanguage();
|
||||
return getModInfo(modId).getBaseLanguage();
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,9 @@
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/CMemoryBuffer.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/campaign/CampaignHandler.h"
|
||||
#include "../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../lib/mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../lib/mapObjects/ObjectTemplate.h"
|
||||
@ -32,6 +34,7 @@
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/mapping/CMapEditManager.h"
|
||||
#include "../lib/mapping/MapFormat.h"
|
||||
#include "../lib/mapping/MapFormatJson.h"
|
||||
#include "../lib/modding/ModIncompatibility.h"
|
||||
#include "../lib/RoadHandler.h"
|
||||
#include "../lib/RiverHandler.h"
|
||||
@ -398,6 +401,27 @@ std::unique_ptr<CMap> MainWindow::openMapInternal(const QString & filenameSelect
|
||||
throw std::runtime_error("Corrupted map");
|
||||
}
|
||||
|
||||
std::shared_ptr<CampaignState> MainWindow::openCampaignInternal(const QString & filenameSelect)
|
||||
{
|
||||
QFileInfo fi(filenameSelect);
|
||||
std::string fname = fi.fileName().toStdString();
|
||||
std::string fdir = fi.dir().path().toStdString();
|
||||
|
||||
ResourcePath resId("MAPEDITOR/" + fname, EResType::CAMPAIGN);
|
||||
|
||||
//addFilesystem takes care about memory deallocation if case of failure, no memory leak here
|
||||
auto * mapEditorFilesystem = new CFilesystemLoader("MAPEDITOR/", fdir, 0);
|
||||
CResourceHandler::removeFilesystem("local", "mapEditor");
|
||||
CResourceHandler::addFilesystem("local", "mapEditor", mapEditorFilesystem);
|
||||
|
||||
if(!CResourceHandler::get("mapEditor")->existsResource(resId))
|
||||
throw std::runtime_error("Cannot open campaign from this folder");
|
||||
if(auto campaign = CampaignHandler::getCampaign(resId.getName()))
|
||||
return campaign;
|
||||
else
|
||||
throw std::runtime_error("Corrupted campaign");
|
||||
}
|
||||
|
||||
bool MainWindow::openMap(const QString & filenameSelect)
|
||||
{
|
||||
try
|
||||
@ -1373,6 +1397,53 @@ void MainWindow::on_actionh3m_converter_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionh3c_converter_triggered()
|
||||
{
|
||||
auto campaignFile = QFileDialog::getOpenFileName(this, tr("Select campaign to convert"),
|
||||
QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string()),
|
||||
tr("HoMM3 campaigns (*.h3c)"));
|
||||
if(campaignFile.isEmpty())
|
||||
return;
|
||||
|
||||
auto campaignFileDest = QFileDialog::getSaveFileName(this, tr("Select destination file"),
|
||||
QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string()),
|
||||
tr("VCMI campaigns (*.vcmp)"));
|
||||
if(campaignFileDest.isEmpty())
|
||||
return;
|
||||
|
||||
QFileInfo fileInfo(campaignFileDest);
|
||||
if(fileInfo.suffix().toLower() != "vcmp")
|
||||
campaignFileDest += ".vcmp";
|
||||
auto campaign = openCampaignInternal(campaignFile);
|
||||
|
||||
auto jsonCampaign = CampaignHandler::writeHeaderToJson(*campaign);
|
||||
|
||||
std::shared_ptr<CIOApi> io(new CDefaultIOApi());
|
||||
auto saver = std::make_shared<CZipSaver>(io, campaignFileDest.toStdString());
|
||||
for(auto & scenario : campaign->allScenarios())
|
||||
{
|
||||
CMapService mapService;
|
||||
auto map = campaign->getMap(scenario, nullptr);
|
||||
controller.repairMap(map.get());
|
||||
CMemoryBuffer serializeBuffer;
|
||||
{
|
||||
CMapSaverJson jsonSaver(&serializeBuffer);
|
||||
jsonSaver.saveMap(map);
|
||||
}
|
||||
|
||||
auto mapName = boost::algorithm::to_lower_copy(campaign->scenario(scenario).mapName);
|
||||
mapName = boost::replace_all_copy(mapName, ".h3m", std::string("")) + ".vmap";
|
||||
|
||||
auto stream = saver->addFile(mapName);
|
||||
stream->write(reinterpret_cast<const ui8 *>(serializeBuffer.getBuffer().data()), serializeBuffer.getSize());
|
||||
|
||||
jsonCampaign["scenarios"].Vector().push_back(CampaignHandler::writeScenarioToJson(campaign->scenario(scenario)));
|
||||
jsonCampaign["scenarios"].Vector().back()["map"].String() = mapName;
|
||||
}
|
||||
|
||||
auto jsonCampaignStr = jsonCampaign.toString();
|
||||
saver->addFile("header.json")->write(reinterpret_cast<const ui8 *>(jsonCampaignStr.data()), jsonCampaignStr.length());
|
||||
}
|
||||
|
||||
void MainWindow::on_actionLock_triggered()
|
||||
{
|
||||
|
@ -11,6 +11,7 @@ class ObjectBrowserProxyModel;
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CMap;
|
||||
class CampaignState;
|
||||
class CGObjectInstance;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
@ -35,6 +36,7 @@ class MainWindow : public QMainWindow
|
||||
#endif
|
||||
|
||||
std::unique_ptr<CMap> openMapInternal(const QString &);
|
||||
std::shared_ptr<CampaignState> openCampaignInternal(const QString &);
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
@ -118,6 +120,8 @@ private slots:
|
||||
|
||||
void on_actionh3m_converter_triggered();
|
||||
|
||||
void on_actionh3c_converter_triggered();
|
||||
|
||||
void on_actionLock_triggered();
|
||||
|
||||
void on_actionUnlock_triggered();
|
||||
|
@ -71,6 +71,7 @@
|
||||
<addaction name="actionSave_as"/>
|
||||
<addaction name="actionExport"/>
|
||||
<addaction name="actionh3m_converter"/>
|
||||
<addaction name="actionh3c_converter"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuMap">
|
||||
<property name="title">
|
||||
@ -1352,6 +1353,14 @@
|
||||
<string>h3m converter</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionh3c_converter">
|
||||
<property name="text">
|
||||
<string>h3c converter</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>h3c converter</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLock">
|
||||
<property name="text">
|
||||
<string>Lock</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user