diff --git a/mapeditor/CMakeLists.txt b/mapeditor/CMakeLists.txt index e9f7ad6cf..dd1f49493 100644 --- a/mapeditor/CMakeLists.txt +++ b/mapeditor/CMakeLists.txt @@ -34,6 +34,8 @@ set(editor_SRCS inspector/messagewidget.cpp inspector/rewardswidget.cpp inspector/questwidget.cpp + inspector/heroartifactswidget.cpp + inspector/artifactwidget.cpp inspector/heroskillswidget.cpp inspector/herospellwidget.cpp inspector/PickObjectDelegate.cpp @@ -76,6 +78,8 @@ set(editor_HEADERS inspector/messagewidget.h inspector/rewardswidget.h inspector/questwidget.h + inspector/heroartifactswidget.h + inspector/artifactwidget.h inspector/heroskillswidget.h inspector/herospellwidget.h inspector/PickObjectDelegate.h @@ -108,6 +112,8 @@ set(editor_FORMS inspector/messagewidget.ui inspector/rewardswidget.ui inspector/questwidget.ui + inspector/heroartifactswidget.ui + inspector/artifactwidget.ui inspector/heroskillswidget.ui inspector/herospellwidget.ui inspector/portraitwidget.ui diff --git a/mapeditor/inspector/artifactwidget.cpp b/mapeditor/inspector/artifactwidget.cpp new file mode 100644 index 000000000..3723eb428 --- /dev/null +++ b/mapeditor/inspector/artifactwidget.cpp @@ -0,0 +1,63 @@ +/* + * herosspellwidget.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 "artifactwidget.h" +#include "ui_artifactwidget.h" +#include "inspector.h" +#include "../../lib/ArtifactUtils.h" +#include "../../lib/constants/StringConstants.h" + +ArtifactWidget::ArtifactWidget(CArtifactFittingSet & fittingSet, QWidget * parent) : + QDialog(parent), + ui(new Ui::ArtifactWidget), + fittingSet(fittingSet) +{ + ui->setupUi(this); + + connect(ui->saveButton, &QPushButton::clicked, this, [this]() + { + emit saveArtifact(ui->artifact->currentData().toInt(), ArtifactPosition(ui->possiblePositions->currentData().toInt())); + close(); + }); + connect(ui->cancelButton, &QPushButton::clicked, this, &ArtifactWidget::close); + connect(ui->possiblePositions, static_cast (&QComboBox::currentIndexChanged), this, &ArtifactWidget::fillArtifacts); + + std::vector possiblePositions; + for(const auto & slot : ArtifactUtils::allWornSlots()) + { + if(fittingSet.isPositionFree(slot)) + { + ui->possiblePositions->addItem(QString::fromStdString(NArtifactPosition::namesHero[slot.num]), slot.num); + } + } + ui->possiblePositions->addItem(QString::fromStdString(NArtifactPosition::backpack), ArtifactPosition::BACKPACK_START); + fillArtifacts(); + + +} + +void ArtifactWidget::fillArtifacts() +{ + ui->artifact->clear(); + auto currentSlot = ui->possiblePositions->currentData().toInt(); + for (const auto& art : VLC->arth->getDefaultAllowed()) + { + auto artifact = art.toArtifact(); + // forbid spell scroll for now as require special handling + if (artifact->canBePutAt(&fittingSet, currentSlot, true) && artifact->getId() != ArtifactID::SPELL_SCROLL) { + ui->artifact->addItem(QString::fromStdString(artifact->getNameTranslated()), QVariant::fromValue(artifact->getIndex())); + } + } +} + +ArtifactWidget::~ArtifactWidget() +{ + delete ui; +} diff --git a/mapeditor/inspector/artifactwidget.h b/mapeditor/inspector/artifactwidget.h new file mode 100644 index 000000000..d2a474240 --- /dev/null +++ b/mapeditor/inspector/artifactwidget.h @@ -0,0 +1,35 @@ +/* + * ArtifactWidget.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 +#include "../../lib/mapObjects/CGHeroInstance.h" + +namespace Ui { +class ArtifactWidget; +} + +class ArtifactWidget : public QDialog +{ + Q_OBJECT + +public: + explicit ArtifactWidget(CArtifactFittingSet & fittingSet, QWidget * parent = nullptr); + ~ArtifactWidget(); + +signals: + void saveArtifact(int32_t artifactIndex, ArtifactPosition slot); + private slots: + void fillArtifacts(); + +private: + Ui::ArtifactWidget * ui; + CArtifactFittingSet & fittingSet; +}; diff --git a/mapeditor/inspector/artifactwidget.ui b/mapeditor/inspector/artifactwidget.ui new file mode 100644 index 000000000..e9c62b0ce --- /dev/null +++ b/mapeditor/inspector/artifactwidget.ui @@ -0,0 +1,92 @@ + + + ArtifactWidget + + + Qt::WindowModal + + + + 0 + 0 + 400 + 150 + + + + + 400 + 150 + + + + + 400 + 150 + + + + Artifact + + + + + 10 + 10 + 381 + 80 + + + + + + + Artifact + + + + + + + + + + + + + Equip where: + + + + + + + + + 190 + 100 + 93 + 28 + + + + Save + + + + + + 290 + 100 + 93 + 28 + + + + Cancel + + + + + + diff --git a/mapeditor/inspector/heroartifactswidget.cpp b/mapeditor/inspector/heroartifactswidget.cpp new file mode 100644 index 000000000..2c1c9d687 --- /dev/null +++ b/mapeditor/inspector/heroartifactswidget.cpp @@ -0,0 +1,144 @@ +/* + * herosspellwidget.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 "artifactwidget.h" +#include "heroartifactswidget.h" +#include "ui_heroartifactswidget.h" +#include "inspector.h" +#include "mapeditorroles.h" +#include "../../lib/ArtifactUtils.h" +#include "../../lib/constants/StringConstants.h" + +HeroArtifactsWidget::HeroArtifactsWidget(CGHeroInstance & h, QWidget * parent) : + QDialog(parent), + ui(new Ui::HeroArtifactsWidget), + hero(h), + fittingSet(CArtifactFittingSet(h)) +{ + ui->setupUi(this); +} + +HeroArtifactsWidget::~HeroArtifactsWidget() +{ + delete ui; +} + +void HeroArtifactsWidget::on_addButton_clicked() +{ + ArtifactWidget artifactWidget{ fittingSet, this }; + connect(&artifactWidget, &ArtifactWidget::saveArtifact, this, &HeroArtifactsWidget::onSaveArtifact); + artifactWidget.exec(); +} + +void HeroArtifactsWidget::on_removeButton_clicked() +{ + auto row = ui->artifacts->currentRow(); + if (row == -1) + { + return; + } + + auto slot = ui->artifacts->item(row, Column::SLOT)->data(MapEditorRoles::ArtifactSlotRole).toInt(); + fittingSet.removeArtifact(ArtifactPosition(slot)); + ui->artifacts->removeRow(row); +} + +void HeroArtifactsWidget::onSaveArtifact(int32_t artifactIndex, ArtifactPosition slot) +{ + auto artifact = ArtifactUtils::createArtifact(VLC->arth->getByIndex(artifactIndex)->getId()); + fittingSet.putArtifact(slot, artifact); + addArtifactToTable(artifactIndex, slot); +} + +void HeroArtifactsWidget::addArtifactToTable(int32_t artifactIndex, ArtifactPosition slot) +{ + auto artifact = VLC->arth->getByIndex(artifactIndex); + auto * itemArtifact = new QTableWidgetItem; + itemArtifact->setText(QString::fromStdString(artifact->getNameTranslated())); + itemArtifact->setData(MapEditorRoles::ArtifactIDRole, QVariant::fromValue(artifact->getIndex())); + + auto * itemSlot = new QTableWidgetItem; + auto slotText = ArtifactUtils::isSlotBackpack(slot) ? NArtifactPosition::backpack : NArtifactPosition::namesHero[slot.num]; + itemSlot->setData(MapEditorRoles::ArtifactSlotRole, QVariant::fromValue(slot.num)); + itemSlot->setText(QString::fromStdString(slotText)); + + ui->artifacts->insertRow(ui->artifacts->rowCount()); + ui->artifacts->setItem(ui->artifacts->rowCount() - 1, Column::ARTIFACT, itemArtifact); + ui->artifacts->setItem(ui->artifacts->rowCount() - 1, Column::SLOT, itemSlot); +} + +void HeroArtifactsWidget::obtainData() +{ + std::vector combinedArtifactsParts; + for (const auto & [artPosition, artSlotInfo] : fittingSet.artifactsWorn) + { + addArtifactToTable(VLC->arth->getById(artSlotInfo.artifact->getTypeId())->getIndex(), artPosition); + } + for (const auto & art : hero.artifactsInBackpack) + { + addArtifactToTable(VLC->arth->getById(art.artifact->getTypeId())->getIndex(), ArtifactPosition::BACKPACK_START); + } +} + +void HeroArtifactsWidget::commitChanges() +{ + while(!hero.artifactsWorn.empty()) + { + hero.removeArtifact(hero.artifactsWorn.begin()->first); + } + + while(!hero.artifactsInBackpack.empty()) + { + hero.removeArtifact(ArtifactPosition::BACKPACK_START + static_cast(hero.artifactsInBackpack.size()) - 1); + } + + for(const auto & [artPosition, artSlotInfo] : fittingSet.artifactsWorn) + { + hero.putArtifact(artPosition, artSlotInfo.artifact); + } + + for(const auto & art : fittingSet.artifactsInBackpack) + { + hero.putArtifact(ArtifactPosition::BACKPACK_START + static_cast(hero.artifactsInBackpack.size()), art.artifact); + } +} + +HeroArtifactsDelegate::HeroArtifactsDelegate(CGHeroInstance & h) : QStyledItemDelegate(), hero(h) +{ +} + +QWidget * HeroArtifactsDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const +{ + return new HeroArtifactsWidget(hero, parent); +} + +void HeroArtifactsDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const +{ + if (auto * ed = qobject_cast(editor)) + { + ed->obtainData(); + } + else + { + QStyledItemDelegate::setEditorData(editor, index); + } +} + +void HeroArtifactsDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const +{ + if (auto * ed = qobject_cast(editor)) + { + ed->commitChanges(); + } + else + { + QStyledItemDelegate::setModelData(editor, model, index); + } +} diff --git a/mapeditor/inspector/heroartifactswidget.h b/mapeditor/inspector/heroartifactswidget.h new file mode 100644 index 000000000..807a37ce5 --- /dev/null +++ b/mapeditor/inspector/heroartifactswidget.h @@ -0,0 +1,65 @@ +/* + * heroartifactswidget.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 +#include "../../lib/mapObjects/CGHeroInstance.h" + +namespace Ui { +class HeroArtifactsWidget; +} + +class HeroArtifactsWidget : public QDialog +{ + Q_OBJECT + +public: + explicit HeroArtifactsWidget(CGHeroInstance &, QWidget *parent = nullptr); + ~HeroArtifactsWidget(); + + void obtainData(); + void commitChanges(); + +private slots: + void onSaveArtifact(int32_t artifactIndex, ArtifactPosition slot); + + void on_addButton_clicked(); + + void on_removeButton_clicked(); + +private: + enum Column + { + SLOT, ARTIFACT + }; + Ui::HeroArtifactsWidget * ui; + + CGHeroInstance & hero; + CArtifactFittingSet fittingSet; + + void addArtifactToTable(int32_t artifactIndex, ArtifactPosition slot); + +}; + +class HeroArtifactsDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + using QStyledItemDelegate::QStyledItemDelegate; + + HeroArtifactsDelegate(CGHeroInstance &); + + QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override; + void setEditorData(QWidget * editor, const QModelIndex & index) const override; + void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override; + +private: + CGHeroInstance & hero; +}; diff --git a/mapeditor/inspector/heroartifactswidget.ui b/mapeditor/inspector/heroartifactswidget.ui new file mode 100644 index 000000000..c3d326618 --- /dev/null +++ b/mapeditor/inspector/heroartifactswidget.ui @@ -0,0 +1,144 @@ + + + HeroArtifactsWidget + + + Qt::NonModal + + + + 0 + 0 + 480 + 635 + + + + + 0 + 0 + + + + + 480 + 480 + + + + Artifacts + + + true + + + + 10 + + + 5 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + + 90 + 0 + + + + Add + + + + + + + true + + + + 90 + 0 + + + + Remove + + + + + + + + + true + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + 120 + + + true + + + false + + + 26 + + + + Slot + + + + + Artifact + + + + + + + + + diff --git a/mapeditor/inspector/inspector.cpp b/mapeditor/inspector/inspector.cpp index b8dceed99..3201e46d8 100644 --- a/mapeditor/inspector/inspector.cpp +++ b/mapeditor/inspector/inspector.cpp @@ -28,6 +28,7 @@ #include "messagewidget.h" #include "rewardswidget.h" #include "questwidget.h" +#include "heroartifactswidget.h" #include "heroskillswidget.h" #include "herospellwidget.h" #include "portraitwidget.h" @@ -333,6 +334,7 @@ void Inspector::updateProperties(CGHeroInstance * o) auto * delegate = new HeroSkillsDelegate(*o); addProperty("Skills", PropertyEditorPlaceholder(), delegate, false); addProperty("Spells", PropertyEditorPlaceholder(), new HeroSpellDelegate(*o), false); + addProperty("Artifacts", PropertyEditorPlaceholder(), new HeroArtifactsDelegate(*o), false); if(o->getHeroTypeID().hasValue() || o->ID == Obj::PRISON) { //Hero type diff --git a/mapeditor/mapcontroller.cpp b/mapeditor/mapcontroller.cpp index bc10d558d..e1f6abfac 100644 --- a/mapeditor/mapcontroller.cpp +++ b/mapeditor/mapcontroller.cpp @@ -640,9 +640,19 @@ ModCompatibilityInfo MapController::modAssessmentMap(const CMap & map) continue; extractEntityMod(spellID.toEntity(VLC)); } + + for(const auto & [_, slotInfo] : hero->artifactsWorn) + { + extractEntityMod(slotInfo.artifact->getTypeId().toEntity(VLC)); + } + + for(const auto & art : hero->artifactsInBackpack) + { + extractEntityMod(art.artifact->getTypeId().toEntity(VLC)); + } } } - //TODO: terrains, artifacts? + //TODO: terrains? return result; } diff --git a/mapeditor/mapeditorroles.h b/mapeditor/mapeditorroles.h index 3564ad598..1fab614c1 100644 --- a/mapeditor/mapeditorroles.h +++ b/mapeditor/mapeditorroles.h @@ -16,5 +16,7 @@ enum MapEditorRoles TownEventRole = Qt::UserRole + 1, PlayerIDRole, BuildingIDRole, - SpellIDRole + SpellIDRole, + ArtifactIDRole, + ArtifactSlotRole };