1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

campaign editor

This commit is contained in:
Laserlicht
2025-03-23 19:52:21 +01:00
parent e1be9af5e6
commit 28169b051e
28 changed files with 3404 additions and 98 deletions

View File

@@ -431,6 +431,10 @@ std::unique_ptr<CMap> CampaignState::getMap(CampaignScenarioID scenarioId, IGame
std::string scenarioName = getFilename().substr(0, getFilename().find('.')); std::string scenarioName = getFilename().substr(0, getFilename().find('.'));
boost::to_lower(scenarioName); boost::to_lower(scenarioName);
scenarioName += ':' + std::to_string(scenarioId.getNum()); scenarioName += ':' + std::to_string(scenarioId.getNum());
if(!mapPieces.count(scenarioId) || !mapPieces.find(scenarioId)->second.size())
return nullptr;
const auto & mapContent = mapPieces.find(scenarioId)->second; const auto & mapContent = mapPieces.find(scenarioId)->second;
auto result = mapService.loadMap(mapContent.data(), mapContent.size(), scenarioName, getModName(), getEncoding(), cb); auto result = mapService.loadMap(mapContent.data(), mapContent.size(), scenarioName, getModName(), getEncoding(), cb);

View File

@@ -32,6 +32,11 @@ class IGameCallback;
class DLL_LINKAGE CampaignRegions class DLL_LINKAGE CampaignRegions
{ {
// Campaign editor
friend class CampaignEditor;
friend class CampaignProperties;
friend class ScenarioProperties;
std::string campPrefix; std::string campPrefix;
std::vector<std::string> campSuffix; std::vector<std::string> campSuffix;
std::string campBackground; std::string campBackground;
@@ -85,6 +90,11 @@ class DLL_LINKAGE CampaignHeader : public boost::noncopyable
friend class CampaignHandler; friend class CampaignHandler;
friend class Campaign; friend class Campaign;
// Campaign editor
friend class CampaignEditor;
friend class CampaignProperties;
friend class ScenarioProperties;
CampaignVersion version = CampaignVersion::NONE; CampaignVersion version = CampaignVersion::NONE;
CampaignRegions campaignRegions; CampaignRegions campaignRegions;
MetaString name; MetaString name;
@@ -251,6 +261,11 @@ class DLL_LINKAGE Campaign : public CampaignHeader, public Serializeable
{ {
friend class CampaignHandler; friend class CampaignHandler;
// Campaign editor
friend class CampaignEditor;
friend class CampaignProperties;
friend class ScenarioProperties;
std::map<CampaignScenarioID, CampaignScenario> scenarios; std::map<CampaignScenarioID, CampaignScenario> scenarios;
public: public:
@@ -273,6 +288,12 @@ public:
class DLL_LINKAGE CampaignState : public Campaign class DLL_LINKAGE CampaignState : public Campaign
{ {
friend class CampaignHandler; friend class CampaignHandler;
// Campaign editor
friend class CampaignEditor;
friend class CampaignProperties;
friend class ScenarioProperties;
using ScenarioPoolType = std::vector<JsonNode>; using ScenarioPoolType = std::vector<JsonNode>;
using CampaignPoolType = std::map<CampaignScenarioID, ScenarioPoolType>; using CampaignPoolType = std::map<CampaignScenarioID, ScenarioPoolType>;
using GlobalPoolType = std::map<HeroTypeID, JsonNode>; using GlobalPoolType = std::map<HeroTypeID, JsonNode>;

View File

@@ -14,6 +14,7 @@
#include "CCreatureHandler.h" #include "CCreatureHandler.h"
#include "CCreatureSet.h" #include "CCreatureSet.h"
#include "entities/faction/CFaction.h" #include "entities/faction/CFaction.h"
#include "entities/hero/CHero.h"
#include "texts/CGeneralTextHandler.h" #include "texts/CGeneralTextHandler.h"
#include "CSkillHandler.h" #include "CSkillHandler.h"
#include "GameConstants.h" #include "GameConstants.h"
@@ -350,6 +351,11 @@ void MetaString::appendName(const ArtifactID & id)
appendTextID(id.toEntity(LIBRARY)->getNameTextID()); appendTextID(id.toEntity(LIBRARY)->getNameTextID());
} }
void MetaString::appendName(const HeroTypeID & id)
{
appendTextID(id.toEntity(LIBRARY)->getNameTextID());
}
void MetaString::appendName(const SpellID & id) void MetaString::appendName(const SpellID & id)
{ {
appendTextID(id.toEntity(LIBRARY)->getNameTextID()); appendTextID(id.toEntity(LIBRARY)->getNameTextID());

View File

@@ -23,6 +23,7 @@ class SecondarySkill;
class SpellID; class SpellID;
class FactionID; class FactionID;
class GameResID; class GameResID;
class HeroTypeID;
using TQuantity = si32; using TQuantity = si32;
/// Strings classes that can be used as replacement in MetaString /// Strings classes that can be used as replacement in MetaString
@@ -78,6 +79,7 @@ public:
void appendNumber(int64_t value); void appendNumber(int64_t value);
void appendName(const ArtifactID& id); void appendName(const ArtifactID& id);
void appendName(const HeroTypeID& id);
void appendName(const SpellID& id); void appendName(const SpellID& id);
void appendName(const PlayerColor& id); void appendName(const PlayerColor& id);
void appendName(const CreatureID & id, TQuantity count); void appendName(const CreatureID & id, TQuantity count);

View File

@@ -69,18 +69,20 @@ namespace BitmapHandler
it = (int)size - 256 * 3; it = (int)size - 256 * 3;
for(int i = 0; i < 256; i++) for(int i = 0; i < 256; i++)
{ {
char bytes[3]; unsigned char bytes[4];
bytes[0] = pcx[it++]; bytes[0] = pcx[it++];
bytes[1] = pcx[it++]; bytes[1] = pcx[it++];
bytes[2] = pcx[it++]; bytes[2] = pcx[it++];
colorTable.append(qRgb(bytes[0], bytes[1], bytes[2])); bytes[3] = (bytes[0] == 0 && bytes[1] == 255 && bytes[2] == 255) ? 0 : 255;
colorTable.append(qRgba(bytes[0], bytes[1], bytes[2], bytes[3]));
} }
image.setColorTable(colorTable); image.setColorTable(colorTable);
return image; return image;
} }
else else
{ {
QImage image(pcx + it, width, height, width * 3, QImage::Format_RGB888); QImage image(pcx + it, width, height, width * 3, QImage::Format_BGR888);
return image; return image;
} }
} }

View File

@@ -41,6 +41,12 @@ set(editor_SRCS
inspector/PickObjectDelegate.cpp inspector/PickObjectDelegate.cpp
inspector/portraitwidget.cpp inspector/portraitwidget.cpp
resourceExtractor/ResourceConverter.cpp resourceExtractor/ResourceConverter.cpp
helper.cpp
campaigneditor/campaigneditor.cpp
campaigneditor/campaignproperties.cpp
campaigneditor/scenarioproperties.cpp
campaigneditor/startingbonus.cpp
campaigneditor/campaignview.cpp
) )
set(editor_HEADERS set(editor_HEADERS
@@ -87,6 +93,12 @@ set(editor_HEADERS
inspector/baseinspectoritemdelegate.h inspector/baseinspectoritemdelegate.h
resourceExtractor/ResourceConverter.h resourceExtractor/ResourceConverter.h
mapeditorroles.h mapeditorroles.h
helper.h
campaigneditor/campaigneditor.h
campaigneditor/campaignproperties.h
campaigneditor/scenarioproperties.h
campaigneditor/startingbonus.h
campaigneditor/campaignview.h
) )
set(editor_FORMS set(editor_FORMS
@@ -118,6 +130,10 @@ set(editor_FORMS
inspector/heroskillswidget.ui inspector/heroskillswidget.ui
inspector/herospellwidget.ui inspector/herospellwidget.ui
inspector/portraitwidget.ui inspector/portraitwidget.ui
campaigneditor/campaigneditor.ui
campaigneditor/campaignproperties.ui
campaigneditor/scenarioproperties.ui
campaigneditor/startingbonus.ui
) )
set(editor_RESOURCES set(editor_RESOURCES

View File

@@ -12,6 +12,7 @@
#include "../Global.h" #include "../Global.h"
#define VCMI_EDITOR_NAME "VCMI Map Editor" #define VCMI_EDITOR_NAME "VCMI Map Editor"
#define VCMI_CAMP_EDITOR_NAME "VCMI Campaign Editor"
#include <QtWidgets> #include <QtWidgets>
#include <QStringList> #include <QStringList>

View File

@@ -0,0 +1,251 @@
/*
* campaigneditor.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "campaigneditor.h"
#include "ui_campaigneditor.h"
#include "campaignproperties.h"
#include "scenarioproperties.h"
#include "../BitmapHandler.h"
#include "../helper.h"
#include "../../lib/VCMIDirs.h"
#include "../../lib/json/JsonNode.h"
#include "../../lib/campaign/CampaignState.h"
#include "../../lib/mapping/CMap.h"
CampaignEditor::CampaignEditor():
ui(new Ui::CampaignEditor),
selectedScenario(CampaignScenarioID::NONE)
{
ui->setupUi(this);
setWindowIcon(QIcon{":/icons/menu-game.png"});
ui->actionOpen->setIcon(QIcon{":/icons/document-open.png"});
ui->actionSave->setIcon(QIcon{":/icons/document-save.png"});
ui->actionNew->setIcon(QIcon{":/icons/document-new.png"});
ui->actionScenarioProperties->setIcon(QIcon{":/icons/menu-settings.png"});
ui->actionCampaignProperties->setIcon(QIcon{":/icons/menu-mods.png"});
campaignScene.reset(new CampaignScene());
ui->campaignView->setScene(campaignScene.get());
redraw();
setTitle();
setWindowModality(Qt::ApplicationModal);
show();
}
CampaignEditor::~CampaignEditor()
{
delete ui;
}
void CampaignEditor::redraw()
{
ui->actionSave->setEnabled(campaignState != nullptr);
ui->actionSave_as->setEnabled(campaignState != nullptr);
ui->actionScenarioProperties->setEnabled(campaignState != nullptr && campaignState->scenarios.count(selectedScenario));
ui->actionCampaignProperties->setEnabled(campaignState != nullptr);
if(!campaignState)
return;
campaignScene->clear();
auto background = BitmapHandler::loadBitmap(campaignState->getRegions().getBackgroundName().getName());
campaignScene->addItem(new QGraphicsPixmapItem(QPixmap::fromImage(background)));
for (auto & s : campaignState->scenarios)
{
auto scenario = s.first;
auto color = campaignState->scenarios.at(scenario).regionColor;
auto image = BitmapHandler::loadBitmap(campaignState->getRegions().getAvailableName(scenario, color).getName());
if(selectedScenario == scenario)
image = BitmapHandler::loadBitmap(campaignState->getRegions().getSelectedName(scenario, color).getName());
else if(campaignState->scenarios.at(scenario).mapName == "")
image = BitmapHandler::loadBitmap(campaignState->getRegions().getConqueredName(scenario, color).getName());
auto pixmap = new ClickablePixmapItem(QPixmap::fromImage(image), [this, scenario]()
{
bool redrawRequired = selectedScenario != scenario;
selectedScenario = scenario;
if(redrawRequired)
redraw();
}, [this, scenario]()
{
if(ScenarioProperties::showScenarioProperties(campaignState, scenario))
changed();
redraw();
}, [this, scenario](QGraphicsSceneContextMenuEvent * event)
{
QMenu contextMenu(this);
QAction *actionScenarioProperties = contextMenu.addAction(tr("Scenario editor"));
actionScenarioProperties->setIcon(ui->actionScenarioProperties->icon());
connect(actionScenarioProperties, &QAction::triggered, this, [this, scenario]() {
if(ScenarioProperties::showScenarioProperties(campaignState, scenario))
changed();
redraw();
});
contextMenu.exec(event->screenPos());
});
auto pos = campaignState->getRegions().getPosition(scenario);
pixmap->setPos(pos.x, pos.y);
pixmap->setToolTip(QString::fromStdString(campaignState->scenarios.at(scenario).mapName));
campaignScene->addItem(pixmap);
}
ui->campaignView->show();
}
bool CampaignEditor::getAnswerAboutUnsavedChanges()
{
if(unsaved)
{
auto sure = QMessageBox::question(this, tr("Confirmation"), tr("Unsaved changes will be lost, are you sure?"));
if(sure == QMessageBox::No)
{
return false;
}
}
return true;
}
void CampaignEditor::setTitle()
{
QFileInfo fileInfo(filename);
QString title = QString("%1%2 - %3 (%4)").arg(fileInfo.fileName(), unsaved ? "*" : "", VCMI_CAMP_EDITOR_NAME, GameConstants::VCMI_VERSION.c_str());
setWindowTitle(title);
}
void CampaignEditor::changed()
{
unsaved = true;
setTitle();
}
bool CampaignEditor::saveCampaign()
{
if(campaignState->mapPieces.size() != campaignState->campaignRegions.regions.size())
{
QMessageBox::critical(nullptr, tr("Maps missing"), tr("Not all Regions have a map. Please add them in Scenario Properties."));
return false;
}
Helper::saveCampaign(campaignState, filename);
return true;
}
void CampaignEditor::showCampaignEditor()
{
auto * dialog = new CampaignEditor();
dialog->setAttribute(Qt::WA_DeleteOnClose);
}
void CampaignEditor::on_actionOpen_triggered()
{
if(!getAnswerAboutUnsavedChanges())
return;
auto filenameSelect = QFileDialog::getOpenFileName(this, tr("Open map"),
QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string()),
tr("All supported campaigns (*.vcmp *.h3c);;VCMI campaigns(*.vcmp);;HoMM3 campaigns(*.h3c)"));
if(filenameSelect.isEmpty())
return;
campaignState = Helper::openCampaignInternal(filenameSelect);
selectedScenario = *campaignState->allScenarios().begin();
redraw();
}
void CampaignEditor::on_actionSave_as_triggered()
{
if(!campaignState)
return;
auto filenameSelect = QFileDialog::getSaveFileName(this, tr("Save campaign"), "", tr("VCMI campaigns (*.vcmp)"));
if(filenameSelect.isNull())
return;
QFileInfo fileInfo(filenameSelect);
if(fileInfo.suffix().toLower() != "vcmp")
filenameSelect += ".vcmp";
filename = filenameSelect;
if(saveCampaign())
unsaved = false;
setTitle();
}
void CampaignEditor::on_actionNew_triggered()
{
if(!getAnswerAboutUnsavedChanges())
return;
campaignState = std::make_unique<CampaignState>();
campaignState->campaignRegions = CampaignRegions::getLegacy(0);
for (int i = 0; i < campaignState->campaignRegions.regions.size(); i++)
{
CampaignScenario s;
s.travelOptions.startOptions = CampaignStartOptions::START_BONUS;
campaignState->scenarios.emplace(CampaignScenarioID(i), s);
}
campaignState->modName = "mapEditor";
changed();
redraw();
}
void CampaignEditor::on_actionSave_triggered()
{
if(!campaignState)
return;
if(filename.isNull())
on_actionSave_as_triggered();
else if(saveCampaign())
unsaved = false;
setTitle();
}
void CampaignEditor::on_actionCampaignProperties_triggered()
{
if(!campaignState)
return;
if(CampaignProperties::showCampaignProperties(campaignState))
changed();
redraw();
}
void CampaignEditor::on_actionScenarioProperties_triggered()
{
if(!campaignState || selectedScenario == CampaignScenarioID::NONE)
return;
if(ScenarioProperties::showScenarioProperties(campaignState, selectedScenario))
changed();
redraw();
}
void CampaignEditor::closeEvent(QCloseEvent *event)
{
if(getAnswerAboutUnsavedChanges())
QDialog::closeEvent(event);
else
event->ignore();
}

View File

@@ -0,0 +1,60 @@
/*
* campaigneditor.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <QDialog>
#include "campaignview.h"
#include "../StdInc.h"
#include "../../lib/constants/EntityIdentifiers.h"
class CampaignState;
namespace Ui {
class CampaignEditor;
}
class CampaignEditor : public QDialog
{
Q_OBJECT
public:
explicit CampaignEditor();
~CampaignEditor();
void redraw();
static void showCampaignEditor();
private slots:
void on_actionOpen_triggered();
void on_actionSave_as_triggered();
void on_actionNew_triggered();
void on_actionSave_triggered();
void on_actionCampaignProperties_triggered();
void on_actionScenarioProperties_triggered();
private:
bool getAnswerAboutUnsavedChanges();
void setTitle();
void changed();
bool saveCampaign();
void closeEvent(QCloseEvent *event) override;
Ui::CampaignEditor *ui;
std::unique_ptr<CampaignScene> campaignScene;
QString filename;
bool unsaved = false;
CampaignScenarioID selectedScenario;
std::shared_ptr<CampaignState> campaignState;
};

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CampaignEditor</class>
<widget class="QDialog" name="CampaignEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>820</width>
<height>720</height>
</rect>
</property>
<property name="windowTitle">
<string>VCMI Campaign Editor</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="Spacing" stdset="0">
<number>0</number>
</property>
<item>
<widget class="QMenuBar" name="menubar">
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionNew"/>
<addaction name="actionOpen"/>
<addaction name="actionSave"/>
<addaction name="actionSave_as"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>Edit</string>
</property>
<addaction name="actionCampaignProperties"/>
<addaction name="actionScenarioProperties"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>Toolbar</string>
</property>
<property name="bottomMargin" stdset="0">
<number>0</number>
</property>
<property name="topMargin" stdset="0">
<number>0</number>
</property>
<addaction name="actionNew"/>
<addaction name="actionOpen"/>
<addaction name="actionSave"/>
<addaction name="separator"/>
<addaction name="actionCampaignProperties"/>
<addaction name="actionScenarioProperties"/>
</widget>
</item>
<item>
<widget class="CampaignView" name="campaignView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
</widget>
</item>
<item>
<widget class="QStatusBar" name="statusbar"/>
</item>
</layout>
<action name="actionOpen">
<property name="text">
<string>Open</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+O</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+S</string>
</property>
</action>
<action name="actionNew">
<property name="text">
<string>New</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+N</string>
</property>
</action>
<action name="actionSave_as">
<property name="text">
<string>Save as...</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="actionCampaignProperties">
<property name="text">
<string>Campaign Properties</string>
</property>
<property name="toolTip">
<string>Campaign Properties</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+Enter</string>
</property>
</action>
<action name="actionScenarioProperties">
<property name="text">
<string>Scenario Properties</string>
</property>
<property name="toolTip">
<string>Scenario Properties</string>
</property>
<property name="shortcut">
<string notr="true">Enter</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>CampaignView</class>
<extends>QGraphicsView</extends>
<header>campaigneditor/campaignview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,193 @@
/*
* campaignproperties.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "campaignproperties.h"
#include "ui_campaignproperties.h"
#include "../../lib/GameLibrary.h"
#include "../../lib/texts/CGeneralTextHandler.h"
#include "../../lib/campaign/CampaignState.h"
#include "../../lib/constants/StringConstants.h"
CampaignProperties::CampaignProperties(std::shared_ptr<CampaignState> campaignState):
ui(new Ui::CampaignProperties),
campaignState(campaignState),
regions(campaignState->campaignRegions)
{
ui->setupUi(this);
setWindowTitle(tr("Campaign Properties"));
setWindowModality(Qt::ApplicationModal);
ui->lineEditName->setText(QString::fromStdString(campaignState->name.toString()));
ui->textEditDescription->setText(QString::fromStdString(campaignState->description.toString()));
ui->lineEditAuthor->setText(QString::fromStdString(campaignState->author.toString()));
ui->lineEditAuthorContact->setText(QString::fromStdString(campaignState->authorContact.toString()));
ui->dateTimeEditCreationDateTime->setDateTime(QDateTime::fromSecsSinceEpoch(campaignState->creationDateTime));
ui->lineEditCampaignVersion->setText(QString::fromStdString(campaignState->campaignVersion.toString()));
ui->lineEditMusic->setText(QString::fromStdString(campaignState->music.getName()));
ui->checkBoxScenarioDifficulty->setChecked(campaignState->difficultyChosenByPlayer);
for (int i = 0; i < 20; i++)
ui->comboBoxRegionPreset->insertItem(i, QString::fromStdString(LIBRARY->generaltexth->translate("core.camptext.names", i)));
ui->comboBoxRegionPreset->insertItem(20, tr("Custom"));
ui->comboBoxRegionPreset->setCurrentIndex(20);
loadRegion();
show();
}
CampaignProperties::~CampaignProperties()
{
delete ui;
}
bool CampaignProperties::showCampaignProperties(std::shared_ptr<CampaignState> campaignState)
{
if(!campaignState)
return false;
auto * dialog = new CampaignProperties(campaignState);
dialog->setAttribute(Qt::WA_DeleteOnClose);
return dialog->exec() == QDialog::Accepted;
}
void CampaignProperties::on_buttonBox_clicked(QAbstractButton * button)
{
if(button == ui->buttonBox->button(QDialogButtonBox::Ok))
{
if(!saveRegion())
return;
campaignState->name = MetaString::createFromRawString(ui->lineEditName->text().toStdString());
campaignState->description = MetaString::createFromRawString(ui->textEditDescription->toPlainText().toStdString());
campaignState->author = MetaString::createFromRawString(ui->lineEditAuthor->text().toStdString());
campaignState->authorContact = MetaString::createFromRawString(ui->lineEditAuthorContact->text().toStdString());
campaignState->creationDateTime = ui->dateTimeEditCreationDateTime->dateTime().toSecsSinceEpoch();
campaignState->campaignVersion = MetaString::createFromRawString(ui->lineEditCampaignVersion->text().toStdString());
campaignState->music = AudioPath::builtin(ui->lineEditMusic->text().toStdString());
campaignState->difficultyChosenByPlayer = ui->checkBoxScenarioDifficulty->isChecked();
accept();
}
close();
}
void CampaignProperties::on_comboBoxRegionPreset_currentIndexChanged(int index)
{
if(ui->comboBoxRegionPreset->count() == 21 && ui->comboBoxRegionPreset->currentIndex() != 20)
regions = CampaignRegions::getLegacy(ui->comboBoxRegionPreset->currentIndex());
loadRegion();
}
void CampaignProperties::on_pushButtonRegionAdd_clicked()
{
int row = ui->tableWidgetRegions->rowCount();
ui->tableWidgetRegions->insertRow(row);
ui->tableWidgetRegions->setItem(row, 0, new QTableWidgetItem("INFIX"));
ui->tableWidgetRegions->setItem(row, 1, new QTableWidgetItem(QString::number(0)));
ui->tableWidgetRegions->setItem(row, 2, new QTableWidgetItem(QString::number(0)));
ui->tableWidgetRegions->setItem(row, 3, new QTableWidgetItem(QString::number(-1)));
ui->tableWidgetRegions->setItem(row, 4, new QTableWidgetItem(QString::number(-1)));
}
void CampaignProperties::on_pushButtonRegionRemove_clicked()
{
int rows = ui->tableWidgetRegions->rowCount() - 1;
ui->tableWidgetRegions->removeRow(rows);
ui->tableWidgetRegions->setRowCount(rows);
}
void CampaignProperties::loadRegion()
{
ui->lineEditBackground->setText(QString::fromStdString(regions.campBackground.empty() ? regions.campPrefix + "_BG" : regions.campBackground));
ui->lineEditSuffix1->setText(QString::fromStdString(regions.campSuffix.size() ? regions.campSuffix[0] : "En"));
ui->lineEditSuffix2->setText(QString::fromStdString(regions.campSuffix.size() ? regions.campSuffix[1] : "Se"));
ui->lineEditSuffix3->setText(QString::fromStdString(regions.campSuffix.size() ? regions.campSuffix[2] : "Co"));
ui->lineEditPrefix->setText(QString::fromStdString(regions.campPrefix));
ui->spinBoxColorSuffixLength->setValue(regions.colorSuffixLength);
ui->tableWidgetRegions->clearContents();
ui->tableWidgetRegions->setRowCount(0);
ui->tableWidgetRegions->setColumnCount(5);
ui->tableWidgetRegions->setHorizontalHeaderLabels({tr("Infix"), tr("X"), tr("Y"), tr("Label Pos X"), tr("Label Pos Y")});
for (int i = 0; i < regions.regions.size(); ++i)
{
ui->tableWidgetRegions->insertRow(ui->tableWidgetRegions->rowCount());
ui->tableWidgetRegions->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(regions.regions[i].infix)));
ui->tableWidgetRegions->setItem(i, 1, new QTableWidgetItem(QString::number(regions.regions[i].pos.x)));
ui->tableWidgetRegions->setItem(i, 2, new QTableWidgetItem(QString::number(regions.regions[i].pos.y)));
ui->tableWidgetRegions->setItem(i, 3, new QTableWidgetItem(QString::number(regions.regions[i].labelPos.has_value() ? (*regions.regions[i].labelPos).x : -1)));
ui->tableWidgetRegions->setItem(i, 4, new QTableWidgetItem(QString::number(regions.regions[i].labelPos.has_value() ? (*regions.regions[i].labelPos).y : -1)));
}
ui->tableWidgetRegions->resizeColumnsToContents();
}
bool CampaignProperties::saveRegion()
{
regions.campBackground = ui->lineEditBackground->text().toStdString();
if(regions.campSuffix.size() == 3)
{
regions.campSuffix[0] = ui->lineEditSuffix1->text().toStdString();
regions.campSuffix[1] = ui->lineEditSuffix2->text().toStdString();
regions.campSuffix[2] = ui->lineEditSuffix3->text().toStdString();
}
else
{
regions.campSuffix.push_back(ui->lineEditSuffix1->text().toStdString());
regions.campSuffix.push_back(ui->lineEditSuffix2->text().toStdString());
regions.campSuffix.push_back(ui->lineEditSuffix3->text().toStdString());
}
regions.campPrefix = ui->lineEditPrefix->text().toStdString();
regions.colorSuffixLength = ui->spinBoxColorSuffixLength->value();
regions.regions.clear();
for (int i = 0; i < ui->tableWidgetRegions->rowCount(); ++i)
{
CampaignRegions::RegionDescription rd;
rd.infix = ui->tableWidgetRegions->item(i, 0)->text().toStdString();
rd.pos.x = ui->tableWidgetRegions->item(i, 1)->text().toInt();
rd.pos.y = ui->tableWidgetRegions->item(i, 2)->text().toInt();
auto labelX = ui->tableWidgetRegions->item(i, 3)->text().toInt();
auto labelY = ui->tableWidgetRegions->item(i, 4)->text().toInt();
if(labelX == -1 || labelY == -1)
rd.labelPos = std::nullopt;
else
Point(labelX, labelY);
regions.regions.push_back(rd);
}
if(campaignState->campaignRegions.regions.size() > regions.regions.size())
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, tr("Fewer Scenarios"), tr("New Region setup supports fewer scenarios than before. Some will removed. Continue?"), QMessageBox::Yes|QMessageBox::No);
if (reply != QMessageBox::Yes)
return false;
}
campaignState->campaignRegions = regions;
while(campaignState->scenarios.size() < campaignState->campaignRegions.regions.size())
campaignState->scenarios.emplace(CampaignScenarioID(std::prev(campaignState->scenarios.end())->first + 1), CampaignScenario());
while(campaignState->scenarios.size() > campaignState->campaignRegions.regions.size())
{
auto elem = std::prev(campaignState->scenarios.end());
campaignState->mapPieces.erase(elem->first);
campaignState->scenarios.erase(elem);
}
return true;
}

View File

@@ -0,0 +1,46 @@
/*
* campaignproperties.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <QDialog>
#include "../../lib/campaign/CampaignState.h"
class CampaignState;
class QAbstractButton;
namespace Ui {
class CampaignProperties;
}
class CampaignProperties : public QDialog
{
Q_OBJECT
public:
explicit CampaignProperties(std::shared_ptr<CampaignState> campaignState);
~CampaignProperties();
static bool showCampaignProperties(std::shared_ptr<CampaignState> campaignState);
private slots:
void on_buttonBox_clicked(QAbstractButton * button);
void on_comboBoxRegionPreset_currentIndexChanged(int index);
void on_pushButtonRegionAdd_clicked();
void on_pushButtonRegionRemove_clicked();
private:
Ui::CampaignProperties *ui;
std::shared_ptr<CampaignState> campaignState;
CampaignRegions regions;
void loadRegion();
bool saveRegion();
};

View File

@@ -0,0 +1,332 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CampaignProperties</class>
<widget class="QDialog" name="CampaignProperties">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>499</width>
<height>580</height>
</rect>
</property>
<property name="windowTitle">
<string>Campaign Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabGeneral">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="labelName">
<property name="text">
<string>Campaign name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditName"/>
</item>
<item>
<widget class="QLabel" name="labelDescription">
<property name="text">
<string>Campaign description</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEditDescription"/>
</item>
<item>
<widget class="QLabel" name="labelAuthor">
<property name="text">
<string>Author</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditAuthor"/>
</item>
<item>
<widget class="QLabel" name="labelAuthorContact">
<property name="text">
<string>Author contact (e.g. e-mail)</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditAuthorContact"/>
</item>
<item>
<widget class="QLabel" name="labelCreationDateTime">
<property name="text">
<string>Campaign creation date</string>
</property>
</widget>
</item>
<item>
<widget class="QDateTimeEdit" name="dateTimeEditCreationDateTime"/>
</item>
<item>
<widget class="QLabel" name="labelCampaignVersion">
<property name="text">
<string>Campaign version</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditCampaignVersion"/>
</item>
<item>
<widget class="QLabel" name="labelMusic">
<property name="text">
<string>Music</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditMusic"/>
</item>
<item>
<widget class="QCheckBox" name="checkBoxScenarioDifficulty">
<property name="text">
<string>Scenario difficulty is user selectable</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabRegions">
<attribute name="title">
<string>Regions</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="labelRegionPreset">
<property name="text">
<string>Regions Preset</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxRegionPreset"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelBackground">
<property name="text">
<string>Background</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditBackground"/>
</item>
<item>
<widget class="QLabel" name="labelSuffix">
<property name="text">
<string>Suffix</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="lineEditSuffix1"/>
</item>
<item>
<widget class="QLineEdit" name="lineEditSuffix2"/>
</item>
<item>
<widget class="QLineEdit" name="lineEditSuffix3"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labelPrefix">
<property name="text">
<string>Prefix</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditPrefix"/>
</item>
<item>
<widget class="QLabel" name="labelColorSuffixLength">
<property name="text">
<string>Color suffix length</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxColorSuffixLength">
<property name="maximum">
<number>2</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelRegions">
<property name="text">
<string>Regions</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="tableWidgetRegions"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButtonRegionAdd">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonRegionRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabMisc">
<attribute name="title">
<string>Misc</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="labelLoadingBackground">
<property name="text">
<string>Loading background image</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditLoadingBackground"/>
</item>
<item>
<widget class="QLabel" name="labelVideoRim">
<property name="text">
<string>Video rim image</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditVideoRim"/>
</item>
<item>
<widget class="QLabel" name="labelIntroVideo">
<property name="text">
<string>Intro video</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditIntroVideo"/>
</item>
<item>
<widget class="QLabel" name="labelOutroVideo">
<property name="text">
<string>Outro video</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditOutroVideo"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,48 @@
/*
* campaignview.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "campaignview.h"
CampaignScene::CampaignScene():
QGraphicsScene(nullptr)
{
}
CampaignView::CampaignView(QWidget * parent):
QGraphicsView(parent)
{
}
ClickablePixmapItem::ClickablePixmapItem(const QPixmap &pixmap, std::function<void()> clickedCallback, std::function<void()> doubleClickedCallback, std::function<void(QGraphicsSceneContextMenuEvent *)> contextMenuCallback):
QGraphicsPixmapItem(pixmap),
clickedCallback(clickedCallback),
doubleClickedCallback(doubleClickedCallback),
contextMenuCallback(contextMenuCallback)
{
}
void ClickablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(clickedCallback)
clickedCallback();
}
void ClickablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
if(doubleClickedCallback)
doubleClickedCallback();
}
void ClickablePixmapItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
if(contextMenuCallback)
contextMenuCallback(event);
}

View File

@@ -0,0 +1,44 @@
/*
* campaignview.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
class CampaignScene : public QGraphicsScene
{
Q_OBJECT;
public:
CampaignScene();
};
class CampaignView : public QGraphicsView
{
Q_OBJECT
public:
CampaignView(QWidget * parent);
};
class ClickablePixmapItem : public QGraphicsPixmapItem {
public:
ClickablePixmapItem(const QPixmap &pixmap, std::function<void()> clickedCallback, std::function<void()> doubleClickedCallback, std::function<void(QGraphicsSceneContextMenuEvent *)> contextMenuCallback);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
private:
std::function<void()> clickedCallback;
std::function<void()> doubleClickedCallback;
std::function<void(QGraphicsSceneContextMenuEvent *)> contextMenuCallback;
};

View File

@@ -0,0 +1,529 @@
/*
* scenarioproperties.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "scenarioproperties.h"
#include "ui_scenarioproperties.h"
#include "startingbonus.h"
#include "../../lib/GameLibrary.h"
#include "../../lib/CArtHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/texts/CGeneralTextHandler.h"
#include "../../lib/entities/hero/CHeroHandler.h"
#include "../../lib/campaign/CampaignState.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/constants/StringConstants.h"
ScenarioProperties::ScenarioProperties(std::shared_ptr<CampaignState> campaignState, CampaignScenarioID scenario):
ui(new Ui::ScenarioProperties),
campaignState(campaignState),
map(campaignState->getMap(scenario, nullptr)),
scenario(scenario)
{
ui->setupUi(this);
setWindowTitle(tr("Scenario Properties"));
setWindowModality(Qt::ApplicationModal);
ui->lineEditRegionName->setText(getRegionChar(scenario.getNum()));
ui->plainTextEditRightClickText->setPlainText(QString::fromStdString(campaignState->scenarios.at(scenario).regionText.toString()));
for(int i = 0, index = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
{
MetaString str;
str.appendName(PlayerColor(i));
ui->comboBoxRegionColor->addItem(QString::fromStdString(str.toString()), QVariant(i));
if(i == campaignState->scenarios.at(scenario).regionColor)
ui->comboBoxRegionColor->setCurrentIndex(index);
++index;
}
for(int i = 0, index = 0; i < 5; ++i)
{
ui->comboBoxDefaultDifficulty->addItem(QString::fromStdString(LIBRARY->generaltexth->arraytxt[142 + i]), QVariant(i));
if(i == campaignState->scenarios.at(scenario).difficulty)
ui->comboBoxDefaultDifficulty->setCurrentIndex(index);
++index;
}
for(int i = 0; i < scenario.getNum(); ++i)
{
auto tmpScenario = CampaignScenarioID(i);
auto * item = new QListWidgetItem(getRegionChar(tmpScenario.getNum()) + " - " + QString::fromStdString(campaignState->scenarios.at(tmpScenario).mapName));
item->setData(Qt::UserRole, QVariant::fromValue(i));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(campaignState->scenarios.at(scenario).preconditionRegions.count(tmpScenario) ? Qt::Checked : Qt::Unchecked);
ui->listWidgetPrerequisites->addItem(item);
}
ui->checkBoxPrologueEnabled->setChecked(campaignState->scenarios.at(scenario).prolog.hasPrologEpilog);
ui->lineEditPrologueVideo->setText(QString::fromStdString(campaignState->scenarios.at(scenario).prolog.prologVideo.getName()));
ui->lineEditPrologueMusic->setText(QString::fromStdString(campaignState->scenarios.at(scenario).prolog.prologMusic.getName()));
ui->lineEditPrologueVoice->setText(QString::fromStdString(campaignState->scenarios.at(scenario).prolog.prologVoice.getName()));
ui->plainTextEditPrologueText->setPlainText(QString::fromStdString(campaignState->scenarios.at(scenario).prolog.prologText.toString()));
ui->checkBoxEpilogueEnabled->setChecked(campaignState->scenarios.at(scenario).epilog.hasPrologEpilog);
ui->lineEditEpilogueVideo->setText(QString::fromStdString(campaignState->scenarios.at(scenario).epilog.prologVideo.getName()));
ui->lineEditEpilogueMusic->setText(QString::fromStdString(campaignState->scenarios.at(scenario).epilog.prologMusic.getName()));
ui->lineEditEpilogueVoice->setText(QString::fromStdString(campaignState->scenarios.at(scenario).epilog.prologVoice.getName()));
ui->plainTextEditEpilogueText->setPlainText(QString::fromStdString(campaignState->scenarios.at(scenario).epilog.prologText.toString()));
ui->checkBoxCrossoverExperience->setChecked(campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.experience);
ui->checkBoxCrossoverPrimarySkills->setChecked(campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.primarySkills);
ui->checkBoxCrossoverSecondarySkills->setChecked(campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.secondarySkills);
ui->checkBoxCrossoverSpells->setChecked(campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.spells);
ui->checkBoxCrossoverArtifacts->setChecked(campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.artifacts);
ui->radioButtonStartingOptionBonus->setChecked(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::START_BONUS);
ui->radioButtonStartingOptionHeroCrossover->setChecked(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::HERO_CROSSOVER);
ui->radioButtonStartingOptionStartingHero->setChecked(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::HERO_OPTIONS);
for(auto const & objectPtr : LIBRARY->arth->objects)
{
auto * item = new QListWidgetItem(QString::fromStdString(objectPtr->getNameTranslated()));
item->setData(Qt::UserRole, QVariant::fromValue(objectPtr->getIndex()));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(campaignState->scenarios.at(scenario).travelOptions.artifactsKeptByHero.count(objectPtr->getId()) ? Qt::Checked : Qt::Unchecked);
ui->listWidgetCrossoverArtifacts->addItem(item);
}
for(auto const & objectPtr : LIBRARY->creh->objects)
{
auto * item = new QListWidgetItem(QString::fromStdString(objectPtr->getNameSingularTranslated()));
item->setData(Qt::UserRole, QVariant::fromValue(objectPtr->getIndex()));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(campaignState->scenarios.at(scenario).travelOptions.monstersKeptByHero.count(objectPtr->getId()) ? Qt::Checked : Qt::Unchecked);
ui->listWidgetCrossoverCreatures->addItem(item);
}
ui->tabWidgetStartOptions->tabBar()->hide();
ui->tabWidgetStartOptions->setStyleSheet("QTabWidget::pane { border: 0; }");
ui->tableWidgetStartingCrossover->setColumnCount(2);
LIBRARY->heroTypes()->forEach([this](const HeroType * hero, bool &)
{
heroSelection.emplace(hero->getId().getNum(), hero->getNameTranslated());
});
heroSelection.emplace(0xFFFD, tr("Strongest").toStdString());
heroSelection.emplace(0xFFFE, tr("Generated").toStdString());
heroSelection.emplace(0xFFFF, tr("Random").toStdString());
reloadMapRelatedUi();
show();
}
ScenarioProperties::~ScenarioProperties()
{
delete ui;
}
void ScenarioProperties::reloadMapRelatedUi()
{
map = campaignState->getMap(scenario, nullptr);
ui->lineEditMapFile->setText(QString::fromStdString(campaignState->scenarios.at(scenario).mapName));
ui->lineEditScenarioName->setText(map ? QString::fromStdString(map->name.toString()) : tr("No map"));
if(!map)
ui->lineEditScenarioName->setStyleSheet("background-color: red;");
else
ui->lineEditScenarioName->setStyleSheet("");
ui->pushButtonExport->setEnabled(map != nullptr);
ui->pushButtonRemove->setEnabled(map != nullptr);
ui->radioButtonStartingOptionHeroCrossover->setEnabled(scenario.getNum() > 0);
bool allowSelectingStartHero = false;
if(map != nullptr)
for(auto & player : map->players)
if(player.generateHeroAtMainTown)
allowSelectingStartHero = true;
ui->radioButtonStartingOptionStartingHero->setEnabled(allowSelectingStartHero);
ui->tabPrologueEpilogue->setEnabled(map != nullptr);
ui->tabCrossover->setEnabled(map != nullptr);
ui->tabStarting->setEnabled(map != nullptr);
ui->comboBoxDefaultDifficulty->setEnabled(map != nullptr);
ui->listWidgetPrerequisites->setEnabled(map != nullptr);
ui->plainTextEditRightClickText->setEnabled(map != nullptr);
ui->tableWidgetStartingCrossover->clearContents();
ui->tableWidgetStartingCrossover->setRowCount(0);
ui->listWidgetStartingBonusOption->clear();
if(map != nullptr)
{
std::vector<PlayerColor> selectableColors;
for(int i = 0; i < map->players.size(); i++)
if(map->players[i].canHumanPlay)
selectableColors.push_back(PlayerColor(i));
ui->comboBoxStartingBonusPlayerPosition->clear();
for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
{
if(!vstd::contains(selectableColors, PlayerColor(i)))
continue;
MetaString str;
str.appendRawString((tr("Player") + " ").toStdString());
str.appendNumber(i + 1);
str.appendRawString(" (");
str.appendName(PlayerColor(i));
str.appendRawString(")");
ui->comboBoxStartingBonusPlayerPosition->addItem(QString::fromStdString(str.toString()), QVariant(i));
}
int index = ui->comboBoxStartingBonusPlayerPosition->findData(campaignState->scenarios.at(scenario).travelOptions.playerColor.getNum());
if(index != -1)
ui->comboBoxStartingBonusPlayerPosition->setCurrentIndex(index);
}
if(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::HERO_CROSSOVER || campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::HERO_OPTIONS)
{
if(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::HERO_OPTIONS)
on_radioButtonStartingOptionStartingHero_toggled();
else
on_radioButtonStartingOptionHeroCrossover_toggled();
for(int i = 0; i < campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose.size(); i++)
{
auto bonus = campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose[i];
ui->tableWidgetStartingCrossover->insertRow(i);
QComboBox* comboBoxOption = new QComboBox();
if(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::HERO_OPTIONS)
{
for(auto & hero : heroSelection)
comboBoxOption->addItem(QString::fromStdString(hero.second), hero.first);
}
else
{
for(int i = 0; i < scenario.getNum(); ++i)
{
auto tmpScenario = CampaignScenarioID(i);
auto text = getRegionChar(tmpScenario.getNum()) + " - " + QString::fromStdString(campaignState->scenarios.at(tmpScenario).mapName);
comboBoxOption->addItem(text, i);
}
}
QComboBox* comboBoxPlayer = new QComboBox();
for(int i = 0; i < ui->comboBoxStartingBonusPlayerPosition->count(); ++i) // copy from player dropdown
comboBoxPlayer->addItem(ui->comboBoxStartingBonusPlayerPosition->itemText(i), ui->comboBoxStartingBonusPlayerPosition->itemData(i));
// set selected
int index = comboBoxPlayer->findData(bonus.info1);
if(index != -1)
comboBoxPlayer->setCurrentIndex(index);
index = comboBoxOption->findData(bonus.info2);
if(index != -1)
comboBoxOption->setCurrentIndex(index);
ui->tableWidgetStartingCrossover->setCellWidget(i, 0, comboBoxOption);
ui->tableWidgetStartingCrossover->setCellWidget(i, 1, comboBoxPlayer);
}
ui->tableWidgetStartingCrossover->resizeColumnsToContents();
}
else if(campaignState->scenarios.at(scenario).travelOptions.startOptions == CampaignStartOptions::START_BONUS)
{
ui->listWidgetStartingBonusOption->clear();
for(auto & bonus : campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose)
{
QListWidgetItem * item = new QListWidgetItem(StartingBonus::getBonusListTitle(bonus, map));
item->setData(Qt::UserRole, QVariant::fromValue(bonus));
ui->listWidgetStartingBonusOption->addItem(item);
}
}
reloadEnableState();
}
void ScenarioProperties::reloadEnableState()
{
ui->pushButtonStartingAdd->setEnabled(ui->tableWidgetStartingCrossover->rowCount() < 3 && ui->listWidgetStartingBonusOption->count() < 3);
ui->pushButtonStartingRemove->setEnabled(ui->tableWidgetStartingCrossover->rowCount() > 0 || ui->listWidgetStartingBonusOption->count() > 0);
}
bool ScenarioProperties::showScenarioProperties(std::shared_ptr<CampaignState> campaignState, CampaignScenarioID scenario)
{
if(!campaignState || scenario == CampaignScenarioID::NONE)
return false;
auto * dialog = new ScenarioProperties(campaignState, scenario);
dialog->setAttribute(Qt::WA_DeleteOnClose);
return dialog->exec() == QDialog::Accepted;
}
void ScenarioProperties::on_buttonBox_clicked(QAbstractButton * button)
{
if(button == ui->buttonBox->button(QDialogButtonBox::Ok))
{
campaignState->scenarios.at(scenario).regionText = MetaString::createFromRawString(ui->plainTextEditRightClickText->toPlainText().toStdString());
campaignState->scenarios.at(scenario).regionColor = ui->comboBoxRegionColor->currentData().toInt();
campaignState->scenarios.at(scenario).difficulty = ui->comboBoxDefaultDifficulty->currentData().toInt();
campaignState->scenarios.at(scenario).prolog.hasPrologEpilog = ui->checkBoxPrologueEnabled->isChecked();
campaignState->scenarios.at(scenario).prolog.prologVideo = VideoPath::builtin(ui->lineEditPrologueVideo->text().toStdString());
campaignState->scenarios.at(scenario).prolog.prologMusic = AudioPath::builtin(ui->lineEditPrologueMusic->text().toStdString());
campaignState->scenarios.at(scenario).prolog.prologVoice = AudioPath::builtin(ui->lineEditPrologueVoice->text().toStdString());
campaignState->scenarios.at(scenario).prolog.prologText = MetaString::createFromRawString(ui->plainTextEditPrologueText->toPlainText().toStdString());
campaignState->scenarios.at(scenario).epilog.hasPrologEpilog = ui->checkBoxEpilogueEnabled->isChecked();
campaignState->scenarios.at(scenario).epilog.prologVideo = VideoPath::builtin(ui->lineEditEpilogueVideo->text().toStdString());
campaignState->scenarios.at(scenario).epilog.prologMusic = AudioPath::builtin(ui->lineEditEpilogueMusic->text().toStdString());
campaignState->scenarios.at(scenario).epilog.prologVoice = AudioPath::builtin(ui->lineEditEpilogueVoice->text().toStdString());
campaignState->scenarios.at(scenario).epilog.prologText = MetaString::createFromRawString(ui->plainTextEditEpilogueText->toPlainText().toStdString());
campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.experience = ui->checkBoxCrossoverExperience->isChecked();
campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.primarySkills = ui->checkBoxCrossoverPrimarySkills->isChecked();
campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.secondarySkills = ui->checkBoxCrossoverSecondarySkills->isChecked();
campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.spells = ui->checkBoxCrossoverSpells->isChecked();
campaignState->scenarios.at(scenario).travelOptions.whatHeroKeeps.artifacts = ui->checkBoxCrossoverArtifacts->isChecked();
CampaignStartOptions startOption = CampaignStartOptions::NONE;
if(ui->radioButtonStartingOptionBonus->isChecked())
startOption = CampaignStartOptions::START_BONUS;
else if(ui->radioButtonStartingOptionHeroCrossover->isChecked())
startOption = CampaignStartOptions::HERO_CROSSOVER;
else if(ui->radioButtonStartingOptionStartingHero->isChecked())
startOption = CampaignStartOptions::HERO_OPTIONS;
campaignState->scenarios.at(scenario).travelOptions.startOptions = startOption;
campaignState->scenarios.at(scenario).travelOptions.artifactsKeptByHero.clear();
for(int i = 0; i < ui->listWidgetCrossoverArtifacts->count(); ++i)
{
auto * item = ui->listWidgetCrossoverArtifacts->item(i);
if(item->checkState() == Qt::Checked)
campaignState->scenarios.at(scenario).travelOptions.artifactsKeptByHero.emplace(i);
}
campaignState->scenarios.at(scenario).travelOptions.monstersKeptByHero.clear();
for(int i = 0; i < ui->listWidgetCrossoverCreatures->count(); ++i)
{
auto * item = ui->listWidgetCrossoverCreatures->item(i);
if(item->checkState() == Qt::Checked)
campaignState->scenarios.at(scenario).travelOptions.monstersKeptByHero.emplace(i);
}
campaignState->scenarios.at(scenario).preconditionRegions.clear();
for(int i = 0; i < ui->listWidgetPrerequisites->count(); ++i)
{
auto * item = ui->listWidgetPrerequisites->item(i);
if(item->checkState() == Qt::Checked)
campaignState->scenarios.at(scenario).preconditionRegions.emplace(i);
}
campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose.clear();
if(ui->radioButtonStartingOptionBonus->isChecked())
{
campaignState->scenarios.at(scenario).travelOptions.playerColor = PlayerColor(ui->comboBoxStartingBonusPlayerPosition->currentData().toInt());
campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose.clear();
for (int i = 0; i < ui->listWidgetStartingBonusOption->count(); ++i) {
QListWidgetItem *item = ui->listWidgetStartingBonusOption->item(i);
campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose.push_back(item->data(Qt::UserRole).value<CampaignBonus>());
}
}
else if(ui->radioButtonStartingOptionHeroCrossover->isChecked() || ui->radioButtonStartingOptionStartingHero->isChecked())
{
for (int i = 0; i < ui->tableWidgetStartingCrossover->rowCount(); ++i)
{
CampaignBonus bonus;
bonus.type = ui->radioButtonStartingOptionHeroCrossover->isChecked() ? CampaignBonusType::HEROES_FROM_PREVIOUS_SCENARIO : CampaignBonusType::HERO;
QComboBox* comboBoxOption = qobject_cast<QComboBox*>(ui->tableWidgetStartingCrossover->cellWidget(i, 0));
QComboBox* comboBoxPlayer = qobject_cast<QComboBox*>(ui->tableWidgetStartingCrossover->cellWidget(i, 1));
bonus.info1 = comboBoxPlayer->currentData().toInt();
bonus.info2 = comboBoxOption->currentData().toInt();
campaignState->scenarios.at(scenario).travelOptions.bonusesToChoose.push_back(bonus);
}
}
accept();
}
close();
}
void ScenarioProperties::on_pushButtonCreatureTypeAll_clicked()
{
for(int i = 0; i < ui->listWidgetCrossoverCreatures->count(); ++i)
ui->listWidgetCrossoverCreatures->item(i)->setCheckState(Qt::CheckState::Checked);
}
void ScenarioProperties::on_pushButtonCreatureTypeNone_clicked()
{
for(int i = 0; i < ui->listWidgetCrossoverCreatures->count(); ++i)
ui->listWidgetCrossoverCreatures->item(i)->setCheckState(Qt::CheckState::Unchecked);
}
void ScenarioProperties::on_pushButtonImport_clicked()
{
auto filename = QFileDialog::getOpenFileName(this, tr("Open map"), "", tr("All supported maps (*.vmap *.h3m);;VCMI maps(*.vmap);;HoMM3 maps(*.h3m)"));
if(filename.isEmpty())
return;
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(nullptr, tr("Error"), tr("Could not open the file."));
return;
}
QByteArray fileData = file.readAll();
std::vector<uint8_t> byteArray(fileData.begin(), fileData.end());
campaignState->mapPieces[scenario] = byteArray;
QFileInfo fileInfo(filename);
QString baseName = fileInfo.fileName();
campaignState->scenarios.at(scenario).mapName = baseName.toStdString();
reloadMapRelatedUi();
}
void ScenarioProperties::on_pushButtonExport_clicked()
{
auto mapName = QString::fromStdString(campaignState->scenarios.at(scenario).mapName);
bool isVmap = mapName.toLower().endsWith(".vmap");
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save map"), mapName, isVmap ? tr("VCMI maps (*.vmap);") : tr("HoMM3 maps (*.h3m);"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::critical(nullptr, tr("Error"), tr("Could not open the file."));
return;
}
auto byteArray = campaignState->mapPieces[scenario];
QByteArray fileData(reinterpret_cast<const char*>(byteArray.data()), byteArray.size());
file.write(fileData);
}
void ScenarioProperties::on_pushButtonRemove_clicked()
{
campaignState->mapPieces.erase(scenario);
campaignState->scenarios.at(scenario).mapName = "";
reloadMapRelatedUi();
}
void ScenarioProperties::on_radioButtonStartingOptionBonus_toggled()
{
ui->tabWidgetStartOptions->setCurrentIndex(0);
ui->listWidgetStartingBonusOption->clear();
ui->pushButtonStartingEdit->setEnabled(true);
}
void ScenarioProperties::on_radioButtonStartingOptionHeroCrossover_toggled()
{
ui->tabWidgetStartOptions->setCurrentIndex(1);
ui->tableWidgetStartingCrossover->clearContents();
ui->tableWidgetStartingCrossover->setRowCount(0);
ui->tableWidgetStartingCrossover->setHorizontalHeaderLabels({tr("Source scenario"), tr("Player position")});
ui->tableWidgetStartingCrossover->resizeColumnsToContents();
ui->pushButtonStartingEdit->setEnabled(false);
}
void ScenarioProperties::on_radioButtonStartingOptionStartingHero_toggled()
{
ui->tabWidgetStartOptions->setCurrentIndex(1);
ui->tableWidgetStartingCrossover->clearContents();
ui->tableWidgetStartingCrossover->setRowCount(0);
ui->tableWidgetStartingCrossover->setHorizontalHeaderLabels({tr("Hero"), tr("Player position")});
ui->tableWidgetStartingCrossover->resizeColumnsToContents();
ui->pushButtonStartingEdit->setEnabled(false);
}
void ScenarioProperties::on_pushButtonStartingAdd_clicked()
{
if(ui->radioButtonStartingOptionHeroCrossover->isChecked() || ui->radioButtonStartingOptionStartingHero->isChecked())
{
int row = ui->tableWidgetStartingCrossover->rowCount();
ui->tableWidgetStartingCrossover->insertRow(row);
QComboBox* comboBoxOption = new QComboBox();
if(ui->radioButtonStartingOptionStartingHero->isChecked())
{
for(auto & hero : heroSelection)
comboBoxOption->addItem(QString::fromStdString(hero.second), hero.first);
}
else
{
for(int i = 0; i < scenario.getNum(); ++i)
{
auto tmpScenario = CampaignScenarioID(i);
auto text = getRegionChar(tmpScenario.getNum()) + " - " + QString::fromStdString(campaignState->scenarios.at(tmpScenario).mapName);
comboBoxOption->addItem(text, i);
}
}
QComboBox* comboBoxPlayer = new QComboBox();
for(int i = 0; i < ui->comboBoxStartingBonusPlayerPosition->count(); ++i) // copy from player dropdown
comboBoxPlayer->addItem(ui->comboBoxStartingBonusPlayerPosition->itemText(i), ui->comboBoxStartingBonusPlayerPosition->itemData(i));
ui->tableWidgetStartingCrossover->setCellWidget(row, 0, comboBoxOption);
ui->tableWidgetStartingCrossover->setCellWidget(row, 1, comboBoxPlayer);
ui->tableWidgetStartingCrossover->resizeColumnsToContents();
}
else
{
CampaignBonus bonus;
bonus.type = CampaignBonusType::SPELL;
if(StartingBonus::showStartingBonus(PlayerColor(ui->comboBoxStartingBonusPlayerPosition->currentData().toInt()), map, bonus))
{
QListWidgetItem * item = new QListWidgetItem(StartingBonus::getBonusListTitle(bonus, map));
item->setData(Qt::UserRole, QVariant::fromValue(bonus));
ui->listWidgetStartingBonusOption->addItem(item);
}
}
reloadEnableState();
}
void ScenarioProperties::on_pushButtonStartingEdit_clicked()
{
if(ui->radioButtonStartingOptionBonus->isChecked())
{
QList<QListWidgetItem *> selectedItems = ui->listWidgetStartingBonusOption->selectedItems();
QListWidgetItem * item = selectedItems.takeFirst();
CampaignBonus bonus = item->data(Qt::UserRole).value<CampaignBonus>();
if(StartingBonus::showStartingBonus(PlayerColor(ui->comboBoxStartingBonusPlayerPosition->currentData().toInt()), map, bonus))
{
item->setText(StartingBonus::getBonusListTitle(bonus, map));
item->setData(Qt::UserRole, QVariant::fromValue(bonus));
}
}
}
void ScenarioProperties::on_pushButtonStartingRemove_clicked()
{
if(ui->radioButtonStartingOptionHeroCrossover->isChecked() || ui->radioButtonStartingOptionStartingHero->isChecked())
{
int rows = ui->tableWidgetStartingCrossover->rowCount() - 1;
ui->tableWidgetStartingCrossover->removeRow(rows);
ui->tableWidgetStartingCrossover->setRowCount(rows);
ui->tableWidgetStartingCrossover->resizeColumnsToContents();
}
else if(ui->radioButtonStartingOptionBonus->isChecked())
{
QList<QListWidgetItem *> selectedItems = ui->listWidgetStartingBonusOption->selectedItems();
for (QListWidgetItem *item : selectedItems)
delete ui->listWidgetStartingBonusOption->takeItem(ui->listWidgetStartingBonusOption->row(item));
}
reloadEnableState();
}
QString ScenarioProperties::getRegionChar(int no)
{
return QString(static_cast<char>('A' + no));
}

View File

@@ -0,0 +1,65 @@
/*
* scenarioproperties.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <QDialog>
#include "lib/constants/EntityIdentifiers.h"
#include "lib/campaign/CampaignState.h"
class CMap;
class CampaignState;
class QAbstractButton;
namespace Ui {
class ScenarioProperties;
}
Q_DECLARE_METATYPE(CampaignBonus)
class ScenarioProperties : public QDialog
{
Q_OBJECT
public:
explicit ScenarioProperties(std::shared_ptr<CampaignState> campaignState, CampaignScenarioID scenario);
~ScenarioProperties();
static bool showScenarioProperties(std::shared_ptr<CampaignState> campaignState, CampaignScenarioID scenario);
private slots:
void on_buttonBox_clicked(QAbstractButton * button);
void on_pushButtonCreatureTypeAll_clicked();
void on_pushButtonCreatureTypeNone_clicked();
void on_pushButtonImport_clicked();
void on_pushButtonExport_clicked();
void on_pushButtonRemove_clicked();
void on_radioButtonStartingOptionBonus_toggled();
void on_radioButtonStartingOptionHeroCrossover_toggled();
void on_radioButtonStartingOptionStartingHero_toggled();
void on_pushButtonStartingAdd_clicked();
void on_pushButtonStartingEdit_clicked();
void on_pushButtonStartingRemove_clicked();
private:
Ui::ScenarioProperties *ui;
std::shared_ptr<CMap> map;
std::shared_ptr<CampaignState> campaignState;
CampaignScenarioID scenario;
std::map<int, std::string> heroSelection;
void reloadMapRelatedUi();
void reloadEnableState();
QString getRegionChar(int no);
};

View File

@@ -0,0 +1,569 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScenarioProperties</class>
<widget class="QDialog" name="ScenarioProperties">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>499</width>
<height>660</height>
</rect>
</property>
<property name="windowTitle">
<string>Scenario Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabGeneral">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="labelRegionName">
<property name="text">
<string>Region name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditRegionName">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelRegionColor">
<property name="text">
<string>Region color</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxRegionColor"/>
</item>
<item>
<widget class="QLabel" name="labelScenarioName">
<property name="text">
<string>Scenario name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditScenarioName">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelMapFIle">
<property name="text">
<string>Map file</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditMapFile">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButtonImport">
<property name="text">
<string>Import...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonExport">
<property name="text">
<string>Export...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labelDefaultDifficulty">
<property name="text">
<string>Default difficulty</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxDefaultDifficulty"/>
</item>
<item>
<widget class="QLabel" name="labelPrerequisites">
<property name="text">
<string>Prerequisites</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidgetPrerequisites"/>
</item>
<item>
<widget class="QLabel" name="labelRIghtClickText">
<property name="text">
<string>Region right-click text</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEditRightClickText"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabPrologueEpilogue">
<attribute name="title">
<string>Prologue/Epilogue</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBoxPrologue">
<property name="title">
<string>Prologue</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QCheckBox" name="checkBoxPrologueEnabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelPrologueVideo">
<property name="text">
<string>Video</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditPrologueVideo"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelPrologueMusic">
<property name="text">
<string>Music</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditPrologueMusic"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelPrologueVoice">
<property name="text">
<string>Voice</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditPrologueVoice"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labelPrologueText">
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEditPrologueText"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxEpilogue">
<property name="title">
<string>Epilogue</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QCheckBox" name="checkBoxEpilogueEnabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelEpilogueVideo">
<property name="text">
<string>Video</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditEpilogueVideo"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelEpilogueMusic">
<property name="text">
<string>Music</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditEpilogueMusic"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelEpilogueVoice">
<property name="text">
<string>Voice</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditEpilogueVoice"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labelEpilogueText">
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEditEpilogueText"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabCrossover">
<attribute name="title">
<string>Crossover</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBoxCrossoverHeroes">
<property name="title">
<string>Crossover heroes retain</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="checkBoxCrossoverExperience">
<property name="text">
<string>Experience</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCrossoverPrimarySkills">
<property name="text">
<string>Primary skills</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCrossoverSecondarySkills">
<property name="text">
<string>Secondary skills</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCrossoverSpells">
<property name="text">
<string>Spells</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCrossoverArtifacts">
<property name="text">
<string>Artifacts</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QListWidget" name="listWidgetCrossoverCreatures">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
</property>
<property name="batchSize">
<number>30</number>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="leftMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButtonCreatureTypeAll">
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonCreatureTypeNone">
<property name="text">
<string>None</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxArtifacts">
<property name="title">
<string>Crossover artifacts</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QListWidget" name="listWidgetCrossoverArtifacts">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
</property>
<property name="batchSize">
<number>30</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabStarting">
<attribute name="title">
<string>Starting</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QLabel" name="labelStartingOption">
<property name="text">
<string>Starting options are</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonStartingOptionBonus">
<property name="text">
<string>Starting bonus options</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonStartingOptionHeroCrossover">
<property name="text">
<string>Hero crossover options</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonStartingOptionStartingHero">
<property name="text">
<string>Starting hero options</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidgetStartOptions">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabBonus">
<attribute name="title">
<string>Bonus</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QLabel" name="labelStartingBonusPlayerPosition">
<property name="text">
<string>Player position</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxStartingBonusPlayerPosition"/>
</item>
<item>
<widget class="QLabel" name="labelStartingBonusOption">
<property name="text">
<string>Starting bonus option</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidgetStartingBonusOption"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabCrossoverStartingHero">
<attribute name="title">
<string>Crossover/ Starting hero</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QTableWidget" name="tableWidgetStartingCrossover"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="pushButtonStartingAdd">
<property name="text">
<string>Add...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonStartingEdit">
<property name="text">
<string>Edit...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonStartingRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,370 @@
/*
* startingbonus.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "startingbonus.h"
#include "ui_startingbonus.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/campaign/CampaignState.h"
#include "../../lib/entities/building/CBuilding.h"
#include "../../lib/entities/hero/CHero.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/CArtHandler.h"
#include "../../lib/CSkillHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/spells/CSpellHandler.h"
StartingBonus::StartingBonus(PlayerColor color, std::shared_ptr<CMap> map, CampaignBonus bonus):
ui(new Ui::StartingBonus),
bonus(bonus),
map(map),
color(color)
{
ui->setupUi(this);
setWindowTitle(tr("Edit Starting Bonus"));
setWindowModality(Qt::ApplicationModal);
ui->tabWidget->tabBar()->hide();
ui->tabWidget->setStyleSheet("QTabWidget::pane { border: 0; }");
initControls();
loadBonus();
show();
}
StartingBonus::~StartingBonus()
{
delete ui;
}
void StartingBonus::initControls()
{
std::map<int, std::string> heroSelection;
for(auto & hero : map->heroesOnMap)
if(hero->getOwner() == color || color == PlayerColor::CANNOT_DETERMINE)
heroSelection.emplace(hero->getHeroTypeID(), hero->getNameTranslated());
heroSelection.emplace(0xFFFD, tr("Strongest").toStdString());
heroSelection.emplace(0xFFFE, tr("Generated").toStdString());
heroSelection.emplace(0xFFFF, tr("Random").toStdString());
for(auto & hero : heroSelection)
{
ui->comboBoxSpellRecipient->addItem(QString::fromStdString(hero.second), QVariant(hero.first));
ui->comboBoxCreatureRecipient->addItem(QString::fromStdString(hero.second), QVariant(hero.first));
ui->comboBoxArtifactRecipient->addItem(QString::fromStdString(hero.second), QVariant(hero.first));
ui->comboBoxSpellScrollRecipient->addItem(QString::fromStdString(hero.second), QVariant(hero.first));
ui->comboBoxPrimarySkillRecipient->addItem(QString::fromStdString(hero.second), QVariant(hero.first));
ui->comboBoxSecondarySkillRecipient->addItem(QString::fromStdString(hero.second), QVariant(hero.first));
}
for(auto const & objectPtr : LIBRARY->spellh->objects)
{
ui->comboBoxSpellSpell->addItem(QString::fromStdString(objectPtr->getNameTranslated()), QVariant(objectPtr->getId()));
ui->comboBoxSpellScrollSpell->addItem(QString::fromStdString(objectPtr->getNameTranslated()), QVariant(objectPtr->getId()));
}
for(auto const & objectPtr : LIBRARY->creh->objects)
ui->comboBoxCreatureCreatureType->addItem(QString::fromStdString(objectPtr->getNameSingularTranslated()), QVariant(objectPtr->getId()));
if(map->players[color].hasMainTown)
for(auto & town : map->towns)
if(town->pos == map->players[color].posOfMainTown)
{
for(auto & building : town->getTown()->buildings)
ui->comboBoxBuildingBuilding->addItem(QString::fromStdString(building.second->getNameTranslated()), QVariant(building.first.getNum()));
break;
}
for(auto const & objectPtr : LIBRARY->arth->objects)
if(!vstd::contains(std::vector<ArtifactID>({
ArtifactID::SPELL_SCROLL,
ArtifactID::SPELLBOOK,
ArtifactID::GRAIL,
ArtifactID::AMMO_CART,
ArtifactID::BALLISTA,
ArtifactID::CATAPULT,
ArtifactID::FIRST_AID_TENT,
}), objectPtr->getId()))
ui->comboBoxArtifactArtifact->addItem(QString::fromStdString(objectPtr->getNameTranslated()), QVariant(objectPtr->getId()));
for(auto const & objectPtr : LIBRARY->skillh->objects)
ui->comboBoxSecondarySkillSecondarySkill->addItem(QString::fromStdString(objectPtr->getNameTranslated()), QVariant(objectPtr->getId()));
ui->comboBoxSecondarySkillMastery->addItem(tr("Basic"), QVariant(0));
ui->comboBoxSecondarySkillMastery->addItem(tr("Advanced"), QVariant(1));
ui->comboBoxSecondarySkillMastery->addItem(tr("Expert"), QVariant(2));
ui->comboBoxResourceResourceType->addItem(tr("Wood"), QVariant(0));
ui->comboBoxResourceResourceType->addItem(tr("Mercury"), QVariant(1));
ui->comboBoxResourceResourceType->addItem(tr("Ore"), QVariant(2));
ui->comboBoxResourceResourceType->addItem(tr("Sulfur"), QVariant(3));
ui->comboBoxResourceResourceType->addItem(tr("Crystal"), QVariant(4));
ui->comboBoxResourceResourceType->addItem(tr("Gems"), QVariant(5));
ui->comboBoxResourceResourceType->addItem(tr("Gold"), QVariant(6));
ui->comboBoxResourceResourceType->addItem(tr("Common (Wood and Ore)"), QVariant(0xFD));
ui->comboBoxResourceResourceType->addItem(tr("Rare (Mercury, Sulfur, Crystal, Gems)"), QVariant(0xFE));
}
void StartingBonus::loadBonus()
{
auto setComboBoxValue = [](QComboBox * comboBox, QVariant data){
int index = comboBox->findData(data);
if(index != -1)
comboBox->setCurrentIndex(index);
};
switch (bonus.type)
{
case CampaignBonusType::SPELL:
ui->radioButtonSpell->setChecked(true);
on_radioButtonSpell_toggled();
setComboBoxValue(ui->comboBoxSpellRecipient, bonus.info1);
setComboBoxValue(ui->comboBoxSpellSpell, bonus.info2);
break;
case CampaignBonusType::MONSTER:
ui->radioButtonCreature->setChecked(true);
on_radioButtonCreature_toggled();
setComboBoxValue(ui->comboBoxCreatureRecipient, bonus.info1);
setComboBoxValue(ui->comboBoxCreatureCreatureType, bonus.info2);
ui->spinBoxCreatureQuantity->setValue(bonus.info3);
break;
case CampaignBonusType::BUILDING:
ui->radioButtonBuilding->setChecked(true);
on_radioButtonBuilding_toggled();
setComboBoxValue(ui->comboBoxBuildingBuilding, bonus.info1);
break;
case CampaignBonusType::ARTIFACT:
ui->radioButtonArtifact->setChecked(true);
on_radioButtonArtifact_toggled();
setComboBoxValue(ui->comboBoxArtifactRecipient, bonus.info1);
setComboBoxValue(ui->comboBoxArtifactArtifact, bonus.info2);
break;
case CampaignBonusType::SPELL_SCROLL:
ui->radioButtonSpellScroll->setChecked(true);
on_radioButtonSpellScroll_toggled();
setComboBoxValue(ui->comboBoxSpellScrollRecipient, bonus.info1);
setComboBoxValue(ui->comboBoxSpellScrollSpell, bonus.info2);
break;
case CampaignBonusType::PRIMARY_SKILL:
ui->radioButtonPrimarySkill->setChecked(true);
on_radioButtonPrimarySkill_toggled();
setComboBoxValue(ui->comboBoxPrimarySkillRecipient, bonus.info1);
ui->spinBoxPrimarySkillAttack->setValue((bonus.info2 >> 0) & 0xff);
ui->spinBoxPrimarySkillDefense->setValue((bonus.info2 >> 8) & 0xff);
ui->spinBoxPrimarySkillSpell->setValue((bonus.info2 >> 16) & 0xff);
ui->spinBoxPrimarySkillKnowledge->setValue((bonus.info2 >> 24) & 0xff);
break;
case CampaignBonusType::SECONDARY_SKILL:
ui->radioButtonSecondarySkill->setChecked(true);
on_radioButtonSecondarySkill_toggled();
setComboBoxValue(ui->comboBoxSecondarySkillRecipient, bonus.info1);
setComboBoxValue(ui->comboBoxSecondarySkillSecondarySkill, bonus.info2);
setComboBoxValue(ui->comboBoxSecondarySkillMastery, bonus.info3);
break;
case CampaignBonusType::RESOURCE:
ui->radioButtonResource->setChecked(true);
on_radioButtonResource_toggled();
setComboBoxValue(ui->comboBoxResourceResourceType, bonus.info1);
ui->spinBoxResourceQuantity->setValue(bonus.info2);
break;
default:
break;
}
}
void StartingBonus::saveBonus()
{
if(ui->radioButtonSpell->isChecked())
bonus.type = CampaignBonusType::SPELL;
else if(ui->radioButtonCreature->isChecked())
bonus.type = CampaignBonusType::MONSTER;
else if(ui->radioButtonBuilding->isChecked())
bonus.type = CampaignBonusType::BUILDING;
else if(ui->radioButtonArtifact->isChecked())
bonus.type = CampaignBonusType::ARTIFACT;
else if(ui->radioButtonSpellScroll->isChecked())
bonus.type = CampaignBonusType::SPELL_SCROLL;
else if(ui->radioButtonPrimarySkill->isChecked())
bonus.type = CampaignBonusType::PRIMARY_SKILL;
else if(ui->radioButtonSecondarySkill->isChecked())
bonus.type = CampaignBonusType::SECONDARY_SKILL;
else if(ui->radioButtonResource->isChecked())
bonus.type = CampaignBonusType::RESOURCE;
bonus.info1 = 0;
bonus.info2 = 0;
bonus.info3 = 0;
switch (bonus.type)
{
case CampaignBonusType::SPELL:
bonus.info1 = ui->comboBoxSpellRecipient->currentData().toInt();
bonus.info2 = ui->comboBoxSpellSpell->currentData().toInt();
break;
case CampaignBonusType::MONSTER:
bonus.info1 = ui->comboBoxCreatureRecipient->currentData().toInt();
bonus.info2 = ui->comboBoxCreatureCreatureType->currentData().toInt();
bonus.info3 = ui->spinBoxCreatureQuantity->value();
break;
case CampaignBonusType::BUILDING:
bonus.info1 = ui->comboBoxBuildingBuilding->currentData().toInt();
break;
case CampaignBonusType::ARTIFACT:
bonus.info1 = ui->comboBoxArtifactRecipient->currentData().toInt();
bonus.info2 = ui->comboBoxArtifactArtifact->currentData().toInt();
break;
case CampaignBonusType::SPELL_SCROLL:
bonus.info1 = ui->comboBoxSpellScrollRecipient->currentData().toInt();
bonus.info2 = ui->comboBoxSpellScrollSpell->currentData().toInt();
break;
case CampaignBonusType::PRIMARY_SKILL:
bonus.info1 = ui->comboBoxPrimarySkillRecipient->currentData().toInt();
bonus.info2 |= ui->spinBoxPrimarySkillAttack->value() << 0;
bonus.info2 |= ui->spinBoxPrimarySkillDefense->value() << 8;
bonus.info2 |= ui->spinBoxPrimarySkillSpell->value() << 16;
bonus.info2 |= ui->spinBoxPrimarySkillKnowledge->value() << 24;
break;
case CampaignBonusType::SECONDARY_SKILL:
bonus.info1 = ui->comboBoxSecondarySkillRecipient->currentData().toInt();
bonus.info2 = ui->comboBoxSecondarySkillSecondarySkill->currentData().toInt();
bonus.info3 = ui->comboBoxSecondarySkillMastery->currentData().toInt();
break;
case CampaignBonusType::RESOURCE:
bonus.info1 = ui->comboBoxResourceResourceType->currentData().toInt();
bonus.info2 = ui->spinBoxResourceQuantity->value();
break;
default:
break;
}
}
void StartingBonus::on_buttonBox_clicked(QAbstractButton * button)
{
if(button == ui->buttonBox->button(QDialogButtonBox::Ok))
{
saveBonus();
accept();
}
close();
}
bool StartingBonus::showStartingBonus(PlayerColor color, std::shared_ptr<CMap> map, CampaignBonus & bonus)
{
auto * dialog = new StartingBonus(color, map, bonus);
dialog->setAttribute(Qt::WA_DeleteOnClose);
auto result = dialog->exec();
if(result == QDialog::Accepted)
bonus = dialog->bonus;
return result == QDialog::Accepted;
}
QString StartingBonus::getBonusListTitle(CampaignBonus bonus, std::shared_ptr<CMap> map)
{
auto getHeroName = [](int id){
MetaString tmp;
if(0xFFFD)
tmp.appendRawString(tr("strongest hero").toStdString());
else if(0xFFFE)
tmp.appendRawString(tr("generated hero").toStdString());
else if(0xFFFF)
tmp.appendRawString(tr("random hero").toStdString());
else
tmp.appendName(HeroTypeID(id));
return QString::fromStdString(tmp.toString());
};
auto getSpellName = [](int id){
MetaString tmp;
tmp.appendName(SpellID(id));
return QString::fromStdString(tmp.toString());
};
auto getMonsterName = [](int id, int amount){
MetaString tmp;
tmp.appendName(CreatureID(id), amount);
return QString::fromStdString(tmp.toString());
};
auto getArtifactName = [](int id){
MetaString tmp;
tmp.appendName(ArtifactID(id));
return QString::fromStdString(tmp.toString());
};
switch (bonus.type)
{
case CampaignBonusType::SPELL:
return tr("%1 spell for %2").arg(getSpellName(bonus.info2)).arg(getHeroName(bonus.info1));
case CampaignBonusType::MONSTER:
return tr("%1 %2 for %3").arg(bonus.info3).arg(getMonsterName(bonus.info2, bonus.info3)).arg(getHeroName(bonus.info1));
case CampaignBonusType::BUILDING:
return tr("Building");
case CampaignBonusType::ARTIFACT:
return tr("%1 artifact for %2").arg(getArtifactName(bonus.info2)).arg(getHeroName(bonus.info1));
case CampaignBonusType::SPELL_SCROLL:
return tr("%1 spell scroll for %2").arg(getSpellName(bonus.info2)).arg(getHeroName(bonus.info1));
case CampaignBonusType::PRIMARY_SKILL:
return tr("Primary skill (Attack: %1, Defense: %2, Spell: %3, Knowledge: %4) for %5").arg((bonus.info2 >> 0) & 0xff).arg((bonus.info2 >> 8) & 0xff).arg((bonus.info2 >> 16) & 0xff).arg((bonus.info2 >> 24) & 0xff).arg(getHeroName(bonus.info1));
case CampaignBonusType::SECONDARY_SKILL:
return tr("Secondary skill");
case CampaignBonusType::RESOURCE:
return tr("Resource");
}
return {};
}
void StartingBonus::on_radioButtonSpell_toggled()
{
ui->tabWidget->setCurrentIndex(0);
}
void StartingBonus::on_radioButtonCreature_toggled()
{
ui->tabWidget->setCurrentIndex(1);
}
void StartingBonus::on_radioButtonBuilding_toggled()
{
ui->tabWidget->setCurrentIndex(2);
}
void StartingBonus::on_radioButtonArtifact_toggled()
{
ui->tabWidget->setCurrentIndex(3);
}
void StartingBonus::on_radioButtonSpellScroll_toggled()
{
ui->tabWidget->setCurrentIndex(4);
}
void StartingBonus::on_radioButtonPrimarySkill_toggled()
{
ui->tabWidget->setCurrentIndex(5);
}
void StartingBonus::on_radioButtonSecondarySkill_toggled()
{
ui->tabWidget->setCurrentIndex(6);
}
void StartingBonus::on_radioButtonResource_toggled()
{
ui->tabWidget->setCurrentIndex(7);
}

View File

@@ -0,0 +1,55 @@
/*
* startingbonus.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <QDialog>
#include "lib/constants/EntityIdentifiers.h"
#include "lib/campaign/CampaignState.h"
struct CampaignBonus;
class CMap;
namespace Ui {
class StartingBonus;
}
class StartingBonus : public QDialog
{
Q_OBJECT
public:
explicit StartingBonus(PlayerColor color, std::shared_ptr<CMap> map, CampaignBonus bonus);
~StartingBonus();
static bool showStartingBonus(PlayerColor color, std::shared_ptr<CMap> map, CampaignBonus & bonus);
static QString getBonusListTitle(CampaignBonus bonus, std::shared_ptr<CMap> map);
private slots:
void on_radioButtonSpell_toggled();
void on_radioButtonCreature_toggled();
void on_radioButtonBuilding_toggled();
void on_radioButtonArtifact_toggled();
void on_radioButtonSpellScroll_toggled();
void on_radioButtonPrimarySkill_toggled();
void on_radioButtonSecondarySkill_toggled();
void on_radioButtonResource_toggled();
void on_buttonBox_clicked(QAbstractButton * button);
private:
Ui::StartingBonus *ui;
CampaignBonus bonus;
std::shared_ptr<CMap> map;
PlayerColor color;
void initControls();
void loadBonus();
void saveBonus();
};

View File

@@ -0,0 +1,468 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StartingBonus</class>
<widget class="QDialog" name="StartingBonus">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>499</width>
<height>644</height>
</rect>
</property>
<property name="windowTitle">
<string>Scenario Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelSelBonusType">
<property name="text">
<string>Select a bonus type</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonSpell">
<property name="text">
<string>Spell</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonCreature">
<property name="text">
<string>Creature</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonBuilding">
<property name="text">
<string>Building</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonArtifact">
<property name="text">
<string>Artifact</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonSpellScroll">
<property name="text">
<string>Spell scroll</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonPrimarySkill">
<property name="text">
<string>Primary skill</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonSecondarySkill">
<property name="text">
<string>Secondary skill</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonResource">
<property name="text">
<string>Resource</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabSpell">
<attribute name="title">
<string>Spell</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="labelSpellRecipient">
<property name="text">
<string>Recipient</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSpellRecipient"/>
</item>
<item>
<widget class="QLabel" name="labelSpellSpell">
<property name="text">
<string>Spell</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSpellSpell"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabCreature">
<attribute name="title">
<string>Creature</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="labelCreatureRecipient">
<property name="text">
<string>Recipient</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxCreatureRecipient"/>
</item>
<item>
<widget class="QLabel" name="labelCreatureCreatureType">
<property name="text">
<string>Creature type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxCreatureCreatureType"/>
</item>
<item>
<widget class="QLabel" name="labelCreatureQuantity">
<property name="text">
<string>Quantity</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxCreatureQuantity"/>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabBuilding">
<attribute name="title">
<string>Building</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="labelBuildingBuilding">
<property name="text">
<string>Building</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxBuildingBuilding"/>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabArtifact">
<attribute name="title">
<string>Artifact</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="labelArtifactRecipient">
<property name="text">
<string>Recipient</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxArtifactRecipient"/>
</item>
<item>
<widget class="QLabel" name="labelArtifactArtifact">
<property name="text">
<string>Artifact</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxArtifactArtifact"/>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabSpellScroll">
<attribute name="title">
<string>Spell scroll</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="labelSpellScrollRecipient">
<property name="text">
<string>Recipient</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSpellScrollRecipient"/>
</item>
<item>
<widget class="QLabel" name="labelSpellScrollSpell">
<property name="text">
<string>Spell</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSpellScrollSpell"/>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabPrimarySkill">
<attribute name="title">
<string>Primary skill</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QLabel" name="labelPrimarySkillRecipient">
<property name="text">
<string>Recipient</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxPrimarySkillRecipient"/>
</item>
<item>
<widget class="QLabel" name="labelPrimarySkillAttack">
<property name="text">
<string>Attack skill</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxPrimarySkillAttack"/>
</item>
<item>
<widget class="QLabel" name="labelPrimarySkillDefense">
<property name="text">
<string>Defense skill</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxPrimarySkillDefense"/>
</item>
<item>
<widget class="QLabel" name="labelPrimarySkillSpell">
<property name="text">
<string>Spell power</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxPrimarySkillSpell"/>
</item>
<item>
<widget class="QLabel" name="labelPrimarySkillKnowledge">
<property name="text">
<string>Knowledge</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxPrimarySkillKnowledge"/>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabSecondarySkill">
<attribute name="title">
<string>Scondary skill</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QLabel" name="labelSecondarySkillRecipient">
<property name="text">
<string>Recipient</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSecondarySkillRecipient"/>
</item>
<item>
<widget class="QLabel" name="labelSecondarySkillSecondarySkill">
<property name="text">
<string>Secondary skill</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSecondarySkillSecondarySkill"/>
</item>
<item>
<widget class="QLabel" name="labelSecondarySkillMastery">
<property name="text">
<string>Mastery</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSecondarySkillMastery"/>
</item>
<item>
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabResource">
<attribute name="title">
<string>Resource</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="labelResourceResourceType">
<property name="text">
<string>Resource type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxResourceResourceType"/>
</item>
<item>
<widget class="QLabel" name="labelResourceQuantity">
<property name="text">
<string>Quantity</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxResourceQuantity"/>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

109
mapeditor/helper.cpp Normal file
View File

@@ -0,0 +1,109 @@
/*
* helper.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "helper.h"
#include "mapcontroller.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CMemoryBuffer.h"
#include "../lib/filesystem/CFilesystemLoader.h"
#include "../lib/filesystem/CZipSaver.h"
#include "../lib/campaign/CampaignHandler.h"
#include "../lib/mapping/CMapService.h"
#include "../lib/mapping/CMap.h"
#include "../lib/mapping/CMap.h"
#include "../lib/mapping/MapFormatJson.h"
#include "../lib/modding/ModIncompatibility.h"
std::unique_ptr<CMap> Helper::openMapInternal(const QString & filenameSelect)
{
QFileInfo fi(filenameSelect);
std::string fname = fi.fileName().toStdString();
std::string fdir = fi.dir().path().toStdString();
ResourcePath resId("MAPEDITOR/" + fname, EResType::MAP);
//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 map from this folder");
CMapService mapService;
if(auto header = mapService.loadMapHeader(resId))
{
auto missingMods = CMapService::verifyMapHeaderMods(*header);
ModIncompatibility::ModList modList;
for(const auto & m : missingMods)
modList.push_back(m.second.name);
if(!modList.empty())
throw ModIncompatibility(modList);
return mapService.loadMap(resId, nullptr);
}
else
throw std::runtime_error("Corrupted map");
}
std::shared_ptr<CampaignState> Helper::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");
}
void Helper::saveCampaign(std::shared_ptr<CampaignState> campaignState, const QString & filename)
{
auto jsonCampaign = CampaignHandler::writeHeaderToJson(*campaignState);
std::shared_ptr<CIOApi> io(new CDefaultIOApi());
auto saver = std::make_shared<CZipSaver>(io, filename.toStdString());
for(auto & scenario : campaignState->allScenarios())
{
auto map = campaignState->getMap(scenario, nullptr);
MapController::repairMap(map.get());
CMemoryBuffer serializeBuffer;
{
CMapSaverJson jsonSaver(&serializeBuffer);
jsonSaver.saveMap(map);
}
auto mapName = boost::algorithm::to_lower_copy(campaignState->scenario(scenario).mapName);
if(!boost::ends_with(mapName, ".vmap"))
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(campaignState->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());
}

21
mapeditor/helper.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* helper.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
class CMap;
class CampaignState;
namespace Helper
{
std::unique_ptr<CMap> openMapInternal(const QString &);
std::shared_ptr<CampaignState> openCampaignInternal(const QString &);
void saveCampaign(std::shared_ptr<CampaignState> campaignState, const QString & filename);
}

View File

@@ -25,14 +25,11 @@
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "../lib/CConsoleHandler.h" #include "../lib/CConsoleHandler.h"
#include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CMemoryBuffer.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "../lib/campaign/CampaignHandler.h" #include "../lib/campaign/CampaignHandler.h"
#include "../lib/mapObjectConstructors/AObjectTypeHandler.h" #include "../lib/mapObjectConstructors/AObjectTypeHandler.h"
#include "../lib/mapObjectConstructors/CObjectClassesHandler.h" #include "../lib/mapObjectConstructors/CObjectClassesHandler.h"
#include "../lib/mapObjects/ObjectTemplate.h" #include "../lib/mapObjects/ObjectTemplate.h"
#include "../lib/mapping/CMapService.h"
#include "../lib/mapping/CMap.h"
#include "../lib/mapping/CMapEditManager.h" #include "../lib/mapping/CMapEditManager.h"
#include "../lib/mapping/MapFormat.h" #include "../lib/mapping/MapFormat.h"
#include "../lib/mapping/MapFormatJson.h" #include "../lib/mapping/MapFormatJson.h"
@@ -40,7 +37,6 @@
#include "../lib/RoadHandler.h" #include "../lib/RoadHandler.h"
#include "../lib/RiverHandler.h" #include "../lib/RiverHandler.h"
#include "../lib/TerrainHandler.h" #include "../lib/TerrainHandler.h"
#include "../lib/filesystem/CFilesystemLoader.h"
#include "maphandler.h" #include "maphandler.h"
#include "graphics.h" #include "graphics.h"
@@ -51,6 +47,8 @@
#include "mapsettings/translations.h" #include "mapsettings/translations.h"
#include "playersettings.h" #include "playersettings.h"
#include "validator.h" #include "validator.h"
#include "helper.h"
#include "campaigneditor/campaigneditor.h"
QJsonValue jsonFromPixmap(const QPixmap &p) QJsonValue jsonFromPixmap(const QPixmap &p)
{ {
@@ -237,6 +235,7 @@ MainWindow::MainWindow(QWidget* parent) :
ui->actionZoom_in->setIcon(QIcon{":/icons/zoom_plus.png"}); ui->actionZoom_in->setIcon(QIcon{":/icons/zoom_plus.png"});
ui->actionZoom_out->setIcon(QIcon{":/icons/zoom_minus.png"}); ui->actionZoom_out->setIcon(QIcon{":/icons/zoom_minus.png"});
ui->actionZoom_reset->setIcon(QIcon{":/icons/zoom_zero.png"}); ui->actionZoom_reset->setIcon(QIcon{":/icons/zoom_zero.png"});
ui->actionCampaignEditor->setIcon(QIcon{":/icons/mapeditor.64x64.png"});
loadUserSettings(); //For example window size loadUserSettings(); //For example window size
setTitle(); setTitle();
@@ -363,65 +362,11 @@ void MainWindow::initializeMap(bool isNew)
onPlayersChanged(); onPlayersChanged();
} }
std::unique_ptr<CMap> MainWindow::openMapInternal(const QString & filenameSelect)
{
QFileInfo fi(filenameSelect);
std::string fname = fi.fileName().toStdString();
std::string fdir = fi.dir().path().toStdString();
ResourcePath resId("MAPEDITOR/" + fname, EResType::MAP);
//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 map from this folder");
CMapService mapService;
if(auto header = mapService.loadMapHeader(resId))
{
auto missingMods = CMapService::verifyMapHeaderMods(*header);
ModIncompatibility::ModList modList;
for(const auto & m : missingMods)
modList.push_back(m.second.name);
if(!modList.empty())
throw ModIncompatibility(modList);
return mapService.loadMap(resId, nullptr);
}
else
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) bool MainWindow::openMap(const QString & filenameSelect)
{ {
try try
{ {
controller.setMap(openMapInternal(filenameSelect)); controller.setMap(Helper::openMapInternal(filenameSelect));
} }
catch(const ModIncompatibility & e) catch(const ModIncompatibility & e)
{ {
@@ -623,6 +568,14 @@ void MainWindow::on_actionSave_as_triggered()
saveMap(); saveMap();
} }
void MainWindow::on_actionCampaignEditor_triggered()
{
if(!getAnswerAboutUnsavedChanges())
return;
hide();
CampaignEditor::showCampaignEditor();
}
void MainWindow::on_actionNew_triggered() void MainWindow::on_actionNew_triggered()
{ {
@@ -1382,7 +1335,7 @@ void MainWindow::on_actionh3m_converter_triggered()
for(auto & m : mapFiles) for(auto & m : mapFiles)
{ {
CMapService mapService; CMapService mapService;
auto map = openMapInternal(m); auto map = Helper::openMapInternal(m);
controller.repairMap(map.get()); controller.repairMap(map.get());
mapService.saveMap(map, (saveDirectory + '/' + QFileInfo(m).completeBaseName() + ".vmap").toStdString()); mapService.saveMap(map, (saveDirectory + '/' + QFileInfo(m).completeBaseName() + ".vmap").toStdString());
} }
@@ -1411,35 +1364,9 @@ void MainWindow::on_actionh3c_converter_triggered()
QFileInfo fileInfo(campaignFileDest); QFileInfo fileInfo(campaignFileDest);
if(fileInfo.suffix().toLower() != "vcmp") if(fileInfo.suffix().toLower() != "vcmp")
campaignFileDest += ".vcmp"; campaignFileDest += ".vcmp";
auto campaign = openCampaignInternal(campaignFile); auto campaign = Helper::openCampaignInternal(campaignFile);
auto jsonCampaign = CampaignHandler::writeHeaderToJson(*campaign); Helper::saveCampaign(campaign, campaignFileDest);
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() void MainWindow::on_actionLock_triggered()

View File

@@ -10,8 +10,6 @@ class ObjectBrowser;
class ObjectBrowserProxyModel; class ObjectBrowserProxyModel;
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
class CMap;
class CampaignState;
class CConsoleHandler; class CConsoleHandler;
class CBasicLogConfigurator; class CBasicLogConfigurator;
class CGObjectInstance; class CGObjectInstance;
@@ -42,9 +40,6 @@ class MainWindow : public QMainWindow
#endif #endif
std::unique_ptr<CBasicLogConfigurator> logConfig; std::unique_ptr<CBasicLogConfigurator> logConfig;
std::unique_ptr<CMap> openMapInternal(const QString &);
std::shared_ptr<CampaignState> openCampaignInternal(const QString &);
public: public:
explicit MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
@@ -75,6 +70,8 @@ private slots:
void on_actionSave_as_triggered(); void on_actionSave_as_triggered();
void on_actionCampaignEditor_triggered();
void on_actionNew_triggered(); void on_actionNew_triggered();
void on_actionLevel_triggered(); void on_actionLevel_triggered();

View File

@@ -70,6 +70,9 @@
<addaction name="actionSave"/> <addaction name="actionSave"/>
<addaction name="actionSave_as"/> <addaction name="actionSave_as"/>
<addaction name="actionExport"/> <addaction name="actionExport"/>
<addaction name="separator"/>
<addaction name="actionCampaignEditor"/>
<addaction name="separator"/>
<addaction name="actionh3m_converter"/> <addaction name="actionh3m_converter"/>
<addaction name="actionh3c_converter"/> <addaction name="actionh3c_converter"/>
</widget> </widget>
@@ -144,6 +147,8 @@
<addaction name="actionOpenRecent"/> <addaction name="actionOpenRecent"/>
<addaction name="actionSave"/> <addaction name="actionSave"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionCampaignEditor"/>
<addaction name="separator"/>
<addaction name="actionUndo"/> <addaction name="actionUndo"/>
<addaction name="actionRedo"/> <addaction name="actionRedo"/>
<addaction name="separator"/> <addaction name="separator"/>
@@ -1065,6 +1070,14 @@
<string>Ctrl+Shift+S</string> <string>Ctrl+Shift+S</string>
</property> </property>
</action> </action>
<action name="actionCampaignEditor">
<property name="text">
<string>Campaign editor</string>
</property>
<property name="toolTip">
<string>Campaign editor</string>
</property>
</action>
<action name="actionLevel"> <action name="actionLevel">
<property name="text"> <property name="text">
<string>View underground</string> <string>View underground</string>

View File

@@ -93,7 +93,7 @@ void MapController::repairMap()
repairMap(map()); repairMap(map());
} }
void MapController::repairMap(CMap * map) const void MapController::repairMap(CMap * map)
{ {
if(!map) if(!map)
return; return;

View File

@@ -31,7 +31,7 @@ public:
void setMap(std::unique_ptr<CMap>); void setMap(std::unique_ptr<CMap>);
void initObstaclePainters(CMap * map); void initObstaclePainters(CMap * map);
void repairMap(CMap * map) const; static void repairMap(CMap * map);
void repairMap(); void repairMap();
const std::unique_ptr<CMap> & getMapUniquePtr() const; //to be used for map saving const std::unique_ptr<CMap> & getMapUniquePtr() const; //to be used for map saving