1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Merge pull request #5034 from godric3/map-editor-hero-artifacts

Map editor:  customize hero artifacts
This commit is contained in:
Ivan Savenko 2024-12-06 15:00:51 +02:00 committed by GitHub
commit 7429589a0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 565 additions and 2 deletions

View File

@ -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

View File

@ -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<void(QComboBox::*) (int)> (&QComboBox::currentIndexChanged), this, &ArtifactWidget::fillArtifacts);
std::vector<ArtifactPosition> 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;
}

View File

@ -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 <QDialog>
#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;
};

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ArtifactWidget</class>
<widget class="QDialog" name="ArtifactWidget">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>150</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>150</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>150</height>
</size>
</property>
<property name="windowTitle">
<string>Artifact</string>
</property>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>80</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="1,5">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Artifact</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="artifact"/>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="possiblePositions"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Equip where:</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="saveButton">
<property name="geometry">
<rect>
<x>190</x>
<y>100</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>Save</string>
</property>
</widget>
<widget class="QPushButton" name="cancelButton">
<property name="geometry">
<rect>
<x>290</x>
<y>100</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>Cancel</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -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<const CArtifact *> 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<int>(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<int>(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<HeroArtifactsWidget *>(editor))
{
ed->obtainData();
}
else
{
QStyledItemDelegate::setEditorData(editor, index);
}
}
void HeroArtifactsDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
if (auto * ed = qobject_cast<HeroArtifactsWidget *>(editor))
{
ed->commitChanges();
}
else
{
QStyledItemDelegate::setModelData(editor, model, index);
}
}

View File

@ -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 <QDialog>
#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;
};

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HeroArtifactsWidget</class>
<widget class="QDialog" name="HeroArtifactsWidget">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>480</width>
<height>635</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>480</width>
<height>480</height>
</size>
</property>
<property name="windowTitle">
<string>Artifacts</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="addButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="artifacts">
<property name="enabled">
<bool>true</bool>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>120</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>26</number>
</attribute>
<column>
<property name="text">
<string>Slot</string>
</property>
</column>
<column>
<property name="text">
<string>Artifact</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -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

View File

@ -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;
}

View File

@ -16,5 +16,7 @@ enum MapEditorRoles
TownEventRole = Qt::UserRole + 1,
PlayerIDRole,
BuildingIDRole,
SpellIDRole
SpellIDRole,
ArtifactIDRole,
ArtifactSlotRole
};