فهرست منبع

map editor: Allow to customize hero spells

godric3 1 سال پیش
والد
کامیت
acceca0139

+ 8 - 0
lib/constants/EntityIdentifiers.cpp

@@ -362,6 +362,10 @@ const HeroType * HeroTypeID::toEntity(const Services * services) const
 
 si32 SpellID::decode(const std::string & identifier)
 {
+	if (identifier == "preset")
+		return SpellID::PRESET;
+	if (identifier == "spellbook_preset")
+		return SpellID::SPELLBOOK_PRESET;
 	return resolveIdentifier("spell", identifier);
 }
 
@@ -369,6 +373,10 @@ std::string SpellID::encode(const si32 index)
 {
 	if (index == -1)
 		return "";
+	if (index == SpellID::PRESET)
+		return "preset";
+	if (index == SpellID::SPELLBOOK_PRESET)
+		return "spellbook_preset";
 	return VLC->spells()->getByIndex(index)->getJsonKey();
 }
 

+ 2 - 0
lib/modding/IdentifierStorage.cpp

@@ -83,6 +83,8 @@ CIdentifierStorage::CIdentifierStorage()
 	registerObject(ModScope::scopeBuiltin(), "bonusSubtype", "creatureLevel5", 5);
 	registerObject(ModScope::scopeBuiltin(), "bonusSubtype", "creatureLevel6", 6);
 	registerObject(ModScope::scopeBuiltin(), "bonusSubtype", "creatureLevel7", 7);
+	registerObject(ModScope::scopeBuiltin(), "spell", "preset", SpellID::PRESET);
+	registerObject(ModScope::scopeBuiltin(), "spell", "spellbook_preset", SpellID::SPELLBOOK_PRESET);
 }
 
 void CIdentifierStorage::checkIdentifier(std::string & ID)

+ 3 - 0
mapeditor/CMakeLists.txt

@@ -34,6 +34,7 @@ set(editor_SRCS
 		inspector/rewardswidget.cpp
 		inspector/questwidget.cpp
 		inspector/heroskillswidget.cpp
+		inspector/herospellwidget.cpp
 		inspector/PickObjectDelegate.cpp
 		inspector/portraitwidget.cpp
 		resourceExtractor/ResourceConverter.cpp
@@ -74,6 +75,7 @@ set(editor_HEADERS
 		inspector/rewardswidget.h
 		inspector/questwidget.h
 		inspector/heroskillswidget.h
+		inspector/herospellwidget.h
 		inspector/PickObjectDelegate.h
 		inspector/portraitwidget.h
 		resourceExtractor/ResourceConverter.h
@@ -101,6 +103,7 @@ set(editor_FORMS
 		inspector/rewardswidget.ui
 		inspector/questwidget.ui
 		inspector/heroskillswidget.ui
+		inspector/herospellwidget.ui
 		inspector/portraitwidget.ui
 )
 

+ 133 - 0
mapeditor/inspector/herospellwidget.cpp

@@ -0,0 +1,133 @@
+/*
+ * 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 "herospellwidget.h"
+#include "ui_herospellwidget.h"
+#include "inspector.h"
+#include "../../lib/constants/StringConstants.h"
+#include "../../lib/spells/CSpellHandler.h"
+
+HeroSpellWidget::HeroSpellWidget(CGHeroInstance & h, QWidget * parent) :
+	QDialog(parent),
+	ui(new Ui::HeroSpellWidget),
+	hero(h)
+{
+	ui->setupUi(this);
+}
+
+HeroSpellWidget::~HeroSpellWidget()
+{
+	delete ui;
+}
+
+
+void HeroSpellWidget::obtainData()
+{
+	initSpellLists();
+	if (hero.spellbookContainsSpell(SpellID::PRESET)) {
+		ui->customizeSpells->setChecked(true);
+	}
+	else
+	{
+		ui->customizeSpells->setChecked(false);
+		ui->tabWidget->setEnabled(false);
+	}
+}
+
+void HeroSpellWidget::initSpellLists()
+{
+	QListWidget * spellLists[] = { ui->spellList1, ui->spellList2, ui->spellList3, ui->spellList4, ui->spellList5 };
+	auto spells = VLC->spellh->objects;
+	for (int i = 0; i < 5; i++)
+	{
+		std::vector<ConstTransitivePtr<CSpell>> spellsByLevel;
+		auto getSpellsByLevel = [i](auto spell) {
+			return spell->getLevel() == i + 1 && !spell->isSpecial() && !spell->isCreatureAbility();
+		};
+		vstd::copy_if(spells, std::back_inserter(spellsByLevel), getSpellsByLevel);
+		spellLists[i]->clear();
+		for (auto spell : spellsByLevel)
+		{
+			auto* item = new QListWidgetItem(QString::fromStdString(spell->getNameTranslated()));
+			item->setData(Qt::UserRole, QVariant::fromValue(spell->getIndex()));
+			item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
+			item->setCheckState(hero.spellbookContainsSpell(spell->getId()) ? Qt::Checked : Qt::Unchecked);
+			spellLists[i]->addItem(item);
+		}
+	}
+}
+
+void HeroSpellWidget::commitChanges()
+{
+	QListWidget * spellLists[] = { ui->spellList1, ui->spellList2, ui->spellList3, ui->spellList4, ui->spellList5 };
+	for (auto spellList : spellLists)
+	{
+		for (int i = 0; i < spellList->count(); i++)
+		{
+			auto * item = spellList->item(i);
+			if (item->checkState() == Qt::Checked)
+			{
+				hero.addSpellToSpellbook(item->data(Qt::UserRole).toInt());
+			}
+			else
+			{
+				hero.removeSpellFromSpellbook(item->data(Qt::UserRole).toInt());
+			}
+		}
+	}
+}
+
+void HeroSpellWidget::on_customizeSpells_toggled(bool checked)
+{
+	if (checked)
+	{
+		hero.addSpellToSpellbook(SpellID::PRESET);
+	}
+	else
+	{
+		hero.removeSpellFromSpellbook(SpellID::PRESET);
+		hero.removeSpellbook();
+	}
+	ui->tabWidget->setEnabled(checked);
+	initSpellLists();
+}
+
+HeroSpellDelegate::HeroSpellDelegate(CGHeroInstance & h) : hero(h), QStyledItemDelegate()
+{
+}
+
+QWidget * HeroSpellDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
+{
+	return new HeroSpellWidget(hero, parent);
+}
+
+void HeroSpellDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
+{
+	if (auto * ed = qobject_cast<HeroSpellWidget *>(editor))
+	{
+		ed->obtainData();
+	}
+	else
+	{
+		QStyledItemDelegate::setEditorData(editor, index);
+	}
+}
+
+void HeroSpellDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
+{
+	if (auto * ed = qobject_cast<HeroSpellWidget *>(editor))
+	{
+		ed->commitChanges();
+	}
+	else
+	{
+		QStyledItemDelegate::setModelData(editor, model, index);
+	}
+}

+ 56 - 0
mapeditor/inspector/herospellwidget.h

@@ -0,0 +1,56 @@
+/*
+ * herospellwidget.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 HeroSpellWidget;
+}
+
+
+class HeroSpellWidget : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit HeroSpellWidget(CGHeroInstance &, QWidget * parent = nullptr);
+	~HeroSpellWidget();
+
+	void obtainData();
+	void commitChanges();
+
+private slots:
+	void on_customizeSpells_toggled(bool checked);
+
+private:
+	Ui::HeroSpellWidget * ui;
+
+	CGHeroInstance & hero;
+
+	void initSpellLists();
+};
+
+class HeroSpellDelegate : public QStyledItemDelegate
+{
+	Q_OBJECT
+public:
+	using QStyledItemDelegate::QStyledItemDelegate;
+
+	HeroSpellDelegate(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;
+};

+ 264 - 0
mapeditor/inspector/herospellwidget.ui

@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HeroSpellWidget</class>
+ <widget class="QDialog" name="HeroSpellWidget">
+  <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>Spells</string>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </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>
+    <widget class="QCheckBox" name="customizeSpells">
+     <property name="text">
+      <string>Customize spells</string>
+     </property>
+     <property name="checked">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <property name="documentMode">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="level1">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 1</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level1">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <widget class="QListWidget" name="spellList1">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="alternatingRowColors">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level2">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 2</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level2">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <widget class="QListWidget" name="spellList2">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="alternatingRowColors">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level3">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 3</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level3">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <widget class="QListWidget" name="spellList3">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="alternatingRowColors">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level4">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 4</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level4">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <widget class="QListWidget" name="spellList4">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="alternatingRowColors">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level5">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 5</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level5">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <widget class="QListWidget" name="spellList5">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+         <property name="alternatingRowColors">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 2 - 0
mapeditor/inspector/inspector.cpp

@@ -26,6 +26,7 @@
 #include "rewardswidget.h"
 #include "questwidget.h"
 #include "heroskillswidget.h"
+#include "herospellwidget.h"
 #include "portraitwidget.h"
 #include "PickObjectDelegate.h"
 #include "../mapcontroller.h"
@@ -314,6 +315,7 @@ void Inspector::updateProperties(CGHeroInstance * o)
 	
 	auto * delegate = new HeroSkillsDelegate(*o);
 	addProperty("Skills", PropertyEditorPlaceholder(), delegate, false);
+	addProperty("Spells", PropertyEditorPlaceholder(), new HeroSpellDelegate(*o), false);
 	
 	if(o->type)
 	{ //Hero type

+ 1 - 7
mapeditor/mapcontroller.cpp

@@ -157,13 +157,7 @@ void MapController::repairMap(CMap * map) const
 			
 			if(nih->ID == Obj::HERO) //not prison
 				nih->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
-			//fix spells
-			if(nih->spellbookContainsSpell(SpellID::PRESET))
-			{
-				nih->removeSpellFromSpellbook(SpellID::PRESET);
-				for(auto spellID : type->spells)
-					nih->addSpellToSpellbook(spellID);
-			}
+			//fix spellbook
 			if(nih->spellbookContainsSpell(SpellID::SPELLBOOK_PRESET))
 			{
 				nih->removeSpellFromSpellbook(SpellID::SPELLBOOK_PRESET);