Selaa lähdekoodia

Merge pull request #6446 from Laserlicht/camp_editor

Campaign editor improvements
Ivan Savenko 4 päivää sitten
vanhempi
sitoutus
11a2f552b9

+ 48 - 2
mapeditor/campaigneditor/campaigneditor.cpp

@@ -142,19 +142,62 @@ void CampaignEditor::changed()
 	setTitle();
 }
 
-void CampaignEditor::saveCampaign()
+bool hasNullGap(const std::map<CampaignScenarioID, CampaignScenario>& scenarios)
+{
+	bool seenNonNull = false;
+	bool foundNullAfterNonNull = false;
+
+	for(const auto & r : scenarios)
+	{
+		if(r.second.mapName.empty())
+		{
+			if (seenNonNull)
+				foundNullAfterNonNull = true; // gap detected
+		}
+		else
+		{
+			if(foundNullAfterNonNull)
+				return true; // non-empty after a gap
+			seenNonNull = true;
+		}
+	}
+
+	// Leading empty elements
+	if (!scenarios.empty() && scenarios.begin()->second.mapName.empty())
+		return true;
+
+	return false;
+}
+
+bool CampaignEditor::validate()
 {
 	if(campaignState->mapPieces.size() != campaignState->campaignRegions.regions.size())
 		logGlobal->trace("Not all regions have a map");
+	
+	if(hasNullGap(campaignState->scenarios))
+	{
+		QMessageBox::critical(this, tr("Fewer Scenarios than regions"), tr("You have fewer scenarios than regions. This is only allowed if the missing scenarios occur in the last regions, not in the middle or beginning."), QMessageBox::Ok);
+		return false;
+	}
+
+	return true;
+}
+
+void CampaignEditor::saveCampaign()
+{
+	if(!validate())
+		return;
 
 	Helper::saveCampaign(campaignState, filename);
 	unsaved = false;
 }
 
-void CampaignEditor::showCampaignEditor()
+void CampaignEditor::showCampaignEditor(QWidget *parent)
 {
 	auto * dialog = new CampaignEditor();
 
+	dialog->move(parent->geometry().center() - dialog->rect().center());
+
 	dialog->setAttribute(Qt::WA_DeleteOnClose);
 }
 
@@ -172,6 +215,9 @@ void CampaignEditor::on_actionOpen_triggered()
 	campaignState = Helper::openCampaignInternal(filenameSelect);
 	selectedScenario = *campaignState->allScenarios().begin();
 
+	while(campaignState->scenarios.size() < campaignState->campaignRegions.regions.size())
+		campaignState->scenarios.emplace(CampaignScenarioID(std::prev(campaignState->scenarios.end())->first + 1), CampaignScenario()); // show als regions without scenario defined yet
+
 	redraw();
 }
 

+ 2 - 1
mapeditor/campaigneditor/campaigneditor.h

@@ -31,7 +31,7 @@ public:
 
 	void redraw();
 
-	static void showCampaignEditor();
+	static void showCampaignEditor(QWidget *parent);
 
 private slots:
 	void on_actionOpen_triggered();
@@ -45,6 +45,7 @@ private:
 	bool getAnswerAboutUnsavedChanges();
 	void setTitle();
 	void changed();
+	bool validate();
 	void saveCampaign();
 
 	void closeEvent(QCloseEvent *event) override;

+ 8 - 0
mapeditor/campaigneditor/campaignproperties.cpp

@@ -37,6 +37,10 @@ CampaignProperties::CampaignProperties(std::shared_ptr<CampaignState> campaignSt
 	ui->lineEditCampaignVersion->setText(QString::fromStdString(campaignState->campaignVersion.toString()));
 	ui->lineEditMusic->setText(QString::fromStdString(campaignState->music.getName()));
 	ui->checkBoxScenarioDifficulty->setChecked(campaignState->difficultyChosenByPlayer);
+	ui->lineEditLoadingBackground->setText(QString::fromStdString(campaignState->loadingBackground.getName()));
+	ui->lineEditVideoRim->setText(QString::fromStdString(campaignState->videoRim.getName()));
+	ui->lineEditIntroVideo->setText(QString::fromStdString(campaignState->introVideo.getName()));
+	ui->lineEditOutroVideo->setText(QString::fromStdString(campaignState->outroVideo.getName()));
 	
 	const JsonNode legacyRegionConfig(JsonPath::builtin("config/campaignRegions.json"));
 	auto legacyRegions = legacyRegionConfig.Struct();
@@ -87,6 +91,10 @@ void CampaignProperties::on_buttonBox_clicked(QAbstractButton * button)
 		campaignState->campaignVersion = MetaString::createFromRawString(ui->lineEditCampaignVersion->text().toStdString());
 		campaignState->music = AudioPath::builtin(ui->lineEditMusic->text().toStdString());
 		campaignState->difficultyChosenByPlayer = ui->checkBoxScenarioDifficulty->isChecked();
+		campaignState->loadingBackground = ImagePath::builtin(ui->lineEditLoadingBackground->text().toStdString());
+		campaignState->videoRim = ImagePath::builtin(ui->lineEditVideoRim->text().toStdString());
+		campaignState->introVideo = VideoPath::builtin(ui->lineEditIntroVideo->text().toStdString());
+		campaignState->outroVideo = VideoPath::builtin(ui->lineEditOutroVideo->text().toStdString());
 		accept();
 	}
 	close();

+ 4 - 3
mapeditor/campaigneditor/scenarioproperties.cpp

@@ -83,9 +83,10 @@ ScenarioProperties::ScenarioProperties(std::shared_ptr<CampaignState> campaignSt
 	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);
+	auto campaignStartOption = campaignState->scenarios.at(scenario).travelOptions.startOptions;
+	ui->radioButtonStartingOptionBonus->setChecked(campaignStartOption == CampaignStartOptions::START_BONUS || campaignStartOption == CampaignStartOptions::NONE);
+	ui->radioButtonStartingOptionHeroCrossover->setChecked(campaignStartOption == CampaignStartOptions::HERO_CROSSOVER);
+	ui->radioButtonStartingOptionStartingHero->setChecked(campaignStartOption == CampaignStartOptions::HERO_OPTIONS);
 
 	for(auto const & objectPtr : LIBRARY->arth->objects)
 	{

+ 34 - 12
mapeditor/campaigneditor/startingbonus.cpp

@@ -90,12 +90,23 @@ void StartingBonus::initControls()
 
 			if(town->pos == map->players[color].posOfMainTown)
 			{
+				if(town->getTown()->faction->getId() == FactionID::NEUTRAL)
+				{
+					ui->comboBoxBuildingBuilding->addItem(tr("Main town is of random faction"), QVariant(BuildingID::NONE));
+					ui->comboBoxBuildingBuilding->setEnabled(false);
+					break;
+				}
 				for(auto & building : town->getTown()->buildings)
 					ui->comboBoxBuildingBuilding->addItem(QString::fromStdString(building.second->getNameTranslated()), QVariant(building.first.getNum()));
 				break;
 			}
 		}
 	}
+	else
+	{
+		ui->comboBoxBuildingBuilding->addItem(tr("Player does not have a main town!"), QVariant(BuildingID::NONE));
+		ui->comboBoxBuildingBuilding->setEnabled(false);
+	}
 
 	for(auto const & objectPtr : LIBRARY->arth->objects)
 		if(!vstd::contains(std::vector<ArtifactID>({
@@ -162,6 +173,8 @@ void StartingBonus::loadBonus()
 		}
 		case CampaignBonusType::BUILDING:
 		{
+			if(ui->comboBoxBuildingBuilding->currentData().toInt() == BuildingID::NONE)
+				break;
 			const auto & bonusValue = bonus.getValue<CampaignBonusBuilding>();
 			ui->radioButtonBuilding->setChecked(true);
 			on_radioButtonBuilding_toggled();
@@ -243,17 +256,17 @@ void StartingBonus::saveBonus()
 		};
 	else if(ui->radioButtonArtifact->isChecked())
 		bonus = CampaignBonusArtifact{
-			HeroTypeID(ui->comboBoxCreatureRecipient->currentData().toInt()),
+			HeroTypeID(ui->comboBoxArtifactRecipient->currentData().toInt()),
 			ArtifactID(ui->comboBoxArtifactArtifact->currentData().toInt())
 		};
 	else if(ui->radioButtonSpellScroll->isChecked())
 		bonus = CampaignBonusSpellScroll{
-			HeroTypeID(ui->comboBoxCreatureRecipient->currentData().toInt()),
+			HeroTypeID(ui->comboBoxSpellScrollRecipient->currentData().toInt()),
 			SpellID(ui->comboBoxSpellScrollSpell->currentData().toInt())
 		};
 	else if(ui->radioButtonPrimarySkill->isChecked())
 		bonus = CampaignBonusPrimarySkill{
-			HeroTypeID(ui->comboBoxCreatureRecipient->currentData().toInt()),
+			HeroTypeID(ui->comboBoxPrimarySkillRecipient->currentData().toInt()),
 			{
 				uint8_t(ui->spinBoxPrimarySkillAttack->value()),
 				uint8_t(ui->spinBoxPrimarySkillDefense->value()),
@@ -263,7 +276,7 @@ void StartingBonus::saveBonus()
 		};
 	else if(ui->radioButtonSecondarySkill->isChecked())
 		bonus = CampaignBonusSecondarySkill{
-			HeroTypeID(ui->comboBoxCreatureRecipient->currentData().toInt()),
+			HeroTypeID(ui->comboBoxSecondarySkillRecipient->currentData().toInt()),
 			SecondarySkill(ui->comboBoxSecondarySkillSecondarySkill->currentData().toInt()),
 			int32_t(ui->comboBoxSecondarySkillMastery->currentData().toInt())
 		};
@@ -381,43 +394,52 @@ QString StartingBonus::getBonusListTitle(CampaignBonus bonus, std::shared_ptr<CM
 	return {};
 }
 
+void StartingBonus::radioButtonToggled(int index)
+{
+	if(index == 2 && ui->comboBoxBuildingBuilding->currentData().toInt() == BuildingID::NONE)
+		ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+	else
+		ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+	ui->tabWidget->setCurrentIndex(index);
+}
+
 void StartingBonus::on_radioButtonSpell_toggled()
 {
-	ui->tabWidget->setCurrentIndex(0);
+	radioButtonToggled(0);
 }
 
 void StartingBonus::on_radioButtonCreature_toggled()
 {
-	ui->tabWidget->setCurrentIndex(1);
+	radioButtonToggled(1);
 }
 
 void StartingBonus::on_radioButtonBuilding_toggled()
 {
-	ui->tabWidget->setCurrentIndex(2);
+	radioButtonToggled(2);
 }
 
 void StartingBonus::on_radioButtonArtifact_toggled()
 {
-	ui->tabWidget->setCurrentIndex(3);
+	radioButtonToggled(3);
 }
 
 void StartingBonus::on_radioButtonSpellScroll_toggled()
 {
-	ui->tabWidget->setCurrentIndex(4);
+	radioButtonToggled(4);
 }
 
 void StartingBonus::on_radioButtonPrimarySkill_toggled()
 {
-	ui->tabWidget->setCurrentIndex(5);
+	radioButtonToggled(5);
 }
 
 void StartingBonus::on_radioButtonSecondarySkill_toggled()
 {
-	ui->tabWidget->setCurrentIndex(6);
+	radioButtonToggled(6);
 }
 
 void StartingBonus::on_radioButtonResource_toggled()
 {
-	ui->tabWidget->setCurrentIndex(7);
+	radioButtonToggled(7);
 }
 

+ 1 - 0
mapeditor/campaigneditor/startingbonus.h

@@ -52,4 +52,5 @@ private:
 	void initControls();
 	void loadBonus();
 	void saveBonus();
+	void radioButtonToggled(int index);
 };

+ 2 - 2
mapeditor/mainwindow.cpp

@@ -686,7 +686,7 @@ void MainWindow::on_actionCampaignEditor_triggered()
 		return;
 
 	hide();
-	CampaignEditor::showCampaignEditor();
+	CampaignEditor::showCampaignEditor(this);
 }
 
 void MainWindow::on_actionTemplateEditor_triggered()
@@ -696,7 +696,7 @@ void MainWindow::on_actionTemplateEditor_triggered()
 		return;
 
 	hide();
-	TemplateEditor::showTemplateEditor();
+	TemplateEditor::showTemplateEditor(this);
 #endif
 }
 

+ 3 - 1
mapeditor/templateeditor/templateeditor.cpp

@@ -613,9 +613,11 @@ void TemplateEditor::saveTemplate()
 	unsaved = false;
 }
 
-void TemplateEditor::showTemplateEditor()
+void TemplateEditor::showTemplateEditor(QWidget *parent)
 {
 	auto * dialog = new TemplateEditor();
+	
+	dialog->move(parent->geometry().center() - dialog->rect().center());
 
 	dialog->setAttribute(Qt::WA_DeleteOnClose);
 }

+ 1 - 1
mapeditor/templateeditor/templateeditor.h

@@ -35,7 +35,7 @@ public:
 	explicit TemplateEditor();
 	~TemplateEditor();
 
-	static void showTemplateEditor();
+	static void showTemplateEditor(QWidget *parent);
 
 private slots:
 	void on_actionOpen_triggered();