1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Implemented properties for some object types, player settings supported

This commit is contained in:
nordsoft 2022-09-06 05:46:22 +04:00
parent dcef991b84
commit 667f05843a
10 changed files with 399 additions and 127 deletions

View File

@ -2,6 +2,9 @@
#include "../Global.h"
#define VCMI_EDITOR_VERSION "0.1"
#define VCMI_EDITOR_NAME "VCMI Map Editor"
#include <QtWidgets>
#include <QStringList>
#include <QSet>

View File

@ -1,23 +1,151 @@
#include "StdInc.h"
#include "inspector.h"
#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/mapObjects/CGTownInstance.h"
#include "../lib/mapObjects/MiscObjects.h"
#include "../lib/CArtHandler.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/CRandomGenerator.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//===============IMPLEMENT OBJECT INITIALIZATION FUNCTIONS================
Initializer::Initializer(CGObjectInstance * o)
{
///IMPORTANT! initialize order should be from base objects to derived objects
INIT_OBJ_TYPE(CGResource);
INIT_OBJ_TYPE(CGArtifact);
INIT_OBJ_TYPE(CArmedInstance);
INIT_OBJ_TYPE(CGMine);
INIT_OBJ_TYPE(CGTownInstance);
}
void initialize(CArmedInstance * o)
{
if(!o) return;
o->tempOwner = PlayerColor::NEUTRAL;
}
void initialize(CGTownInstance * o)
{
if(!o) return;
o->builtBuildings.insert(BuildingID::FORT);
o->builtBuildings.insert(BuildingID::DEFAULT);
for(auto spell : VLC->spellh->objects) //add all regular spells to town
{
if(!spell->isSpecial() && !spell->isCreatureAbility())
o->possibleSpells.push_back(spell->id);
}
}
void initialize(CGArtifact * o)
{
if(!o) return;
if(o->ID == Obj::SPELL_SCROLL)
{
std::vector<SpellID> out;
for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
{
if(/*map.isAllowedSpell(spell->id) && spell->level == i + 1*/ true)
{
out.push_back(spell->id);
}
}
auto a = CArtifactInstance::createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
o->storedArtifact = a;
}
}
void initialize(CGMine * o)
{
if(!o) return;
o->producedResource = Res::ERes(o->subID);
o->producedQuantity = o->defaultResProduction();
}
void initialize(CGResource * o)
{
if(!o) return;
o->amount = CGResource::RANDOM_AMOUNT;
}
//===============IMPLEMENT PROPERTIES SETUP===============================
void Inspector::updateProperties(CArmedInstance * o)
{
if(!o) return;
addProperty("Owner", o->tempOwner);
}
void Inspector::updateProperties(CGTownInstance * o)
{
if(!o) return;
addProperty("Owner", o->tempOwner, false);
addProperty("Town name", o->name, false);
}
void Inspector::updateProperties(CGArtifact * o)
{
if(!o) return;
}
void Inspector::updateProperties(CGMine * o)
{
if(!o) return;
addProperty("Owner", o->tempOwner, false);
addProperty("Resource", o->producedResource);
addProperty("Productivity", o->producedQuantity, false);
}
void Inspector::updateProperties(CGResource * o)
{
if(!o) return;
addProperty("Amount", o->amount, false);
}
void Inspector::updateProperties()
{
if(!obj)
return;
table->setRowCount(0); //cleanup table
addProperty("Indentifier", obj);
addProperty("ID", obj->ID.getNum());
addProperty("SubID", obj->subID);
addProperty("InstanceName", obj->instanceName);
addProperty("TypeName", obj->typeName);
addProperty("SubTypeName", obj->subTypeName);
auto factory = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID);
addProperty("IsStatic", factory->isStaticObject());
UPDATE_OBJ_PROPERTIES(CArmedInstance);
UPDATE_OBJ_PROPERTIES(CGTownInstance);
UPDATE_OBJ_PROPERTIES(CGArtifact);
UPDATE_OBJ_PROPERTIES(CGMine);
UPDATE_OBJ_PROPERTIES(CGResource);
table->show();
}
//===============IMPLEMENT PROPERTY UPDATE================================
void Inspector::setProperty(const QString & key, const QVariant & value)
{
if(!obj)
return;
setProperty(dynamic_cast<CGTownInstance*>(obj), key, value);
//updateProperties();
SET_PROPERTIES(CArmedInstance);
SET_PROPERTIES(CGTownInstance);
SET_PROPERTIES(CGArtifact);
SET_PROPERTIES(CGMine);
SET_PROPERTIES(CGResource);
}
void Inspector::setProperty(CGTownInstance * object, const QString & key, const QVariant & value)
void Inspector::setProperty(CArmedInstance * object, const QString & key, const QVariant & value)
{
if(!object)
return;
@ -34,93 +162,40 @@ void Inspector::setProperty(CGTownInstance * object, const QString & key, const
}
}
CGTownInstance * initialize(CGTownInstance * o)
void Inspector::setProperty(CGTownInstance * object, const QString & key, const QVariant & value)
{
if(!o)
return nullptr;
o->tempOwner = PlayerColor::NEUTRAL;
o->builtBuildings.insert(BuildingID::FORT);
o->builtBuildings.insert(BuildingID::DEFAULT);
for(auto spell : VLC->spellh->objects) //add all regular spells to town
{
if(!spell->isSpecial() && !spell->isCreatureAbility())
o->possibleSpells.push_back(spell->id);
}
return o;
}
CGArtifact * initialize(CGArtifact * o)
{
if(!o)
return nullptr;
if(o->ID == Obj::SPELL_SCROLL)
{
std::vector<SpellID> out;
for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
{
if(/*map.isAllowedSpell(spell->id) && spell->level == i + 1*/ true)
{
out.push_back(spell->id);
}
}
auto a = CArtifactInstance::createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
o->storedArtifact = a;
}
return o;
}
Initializer::Initializer(CGObjectInstance * o)
{
initialize(dynamic_cast<CGTownInstance*>(o));
initialize(dynamic_cast<CGArtifact*>(o));
}
Inspector::Inspector(CGObjectInstance * o, QTableWidget * t): obj(o), table(t)
{
/*
/// Position of bottom-right corner of object on map
int3 pos;
/// Type of object, e.g. town, hero, creature.
Obj ID;
/// Subtype of object, depends on type
si32 subID;
/// Current owner of an object (when below PLAYER_LIMIT)
PlayerColor tempOwner;
/// Index of object in map's list of objects
ObjectInstanceID id;
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
ObjectTemplate appearance;
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
bool blockVisit;
std::string instanceName;
std::string typeName;
std::string subTypeName;*/
}
void Inspector::updateProperties()
{
if(!obj)
if(!object)
return;
addProperty("Indentifier", obj);
addProperty("ID", obj->ID.getNum());
addProperty("SubID", obj->subID);
addProperty("InstanceName", obj->instanceName);
addProperty("TypeName", obj->typeName);
addProperty("SubTypeName", obj->subTypeName);
addProperty("Owner", obj->tempOwner, false);
auto factory = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID);
addProperty("IsStatic", factory->isStaticObject());
table->show();
if(key == "Town name")
object->name = value.toString().toStdString();
}
void Inspector::setProperty(CGMine * object, const QString & key, const QVariant & value)
{
if(!object)
return;
if(key == "Productivity")
object->producedQuantity = value.toString().toInt();
}
void Inspector::setProperty(CGArtifact * object, const QString & key, const QVariant & value)
{
if(!object)
return;
}
void Inspector::setProperty(CGResource * object, const QString & key, const QVariant & value)
{
if(!object)
return;
if(key == "Amount")
object->amount = value.toString().toInt();
}
//===============IMPLEMENT PROPERTY VALUE TYPE============================
QTableWidgetItem * Inspector::addProperty(CGObjectInstance * value)
{
using NumericPointer = unsigned long long;
@ -129,6 +204,11 @@ QTableWidgetItem * Inspector::addProperty(CGObjectInstance * value)
return new QTableWidgetItem(QString::number(reinterpret_cast<NumericPointer>(value)));
}
QTableWidgetItem * Inspector::addProperty(unsigned int value)
{
return new QTableWidgetItem(QString::number(value));
}
QTableWidgetItem * Inspector::addProperty(int value)
{
return new QTableWidgetItem(QString::number(value));
@ -165,6 +245,47 @@ QTableWidgetItem * Inspector::addProperty(const PlayerColor & value)
return new QTableWidgetItem(str);
}
QTableWidgetItem * Inspector::addProperty(const Res::ERes & value)
{
QString str;
switch (value) {
case Res::ERes::WOOD:
str = "WOOD";
break;
case Res::ERes::ORE:
str = "ORE";
break;
case Res::ERes::SULFUR:
str = "SULFUR";
break;
case Res::ERes::GEMS:
str = "GEMS";
break;
case Res::ERes::MERCURY:
str = "MERCURY";
break;
case Res::ERes::CRYSTAL:
str = "CRYSTAL";
break;
case Res::ERes::GOLD:
str = "GOLD";
break;
default:
break;
}
return new QTableWidgetItem(str);
}
//========================================================================
Inspector::Inspector(CGObjectInstance * o, QTableWidget * t): obj(o), table(t)
{
}
/*
* Delegates
*/
QWidget * PlayerColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.data().canConvert<int>())

View File

@ -6,18 +6,47 @@
#include <QStyledItemDelegate>
#include "../lib/int3.h"
#include "../lib/GameConstants.h"
#include "../lib/mapObjects/MapObjects.h"
#include "../lib/ResourceSet.h"
class CGObjectInstance;
class CGTownInstance;
#define DECLARE_OBJ_TYPE(x) void initialize(x*);
#define DECLARE_OBJ_PROPERTY_METHODS(x) \
void updateProperties(x*); \
void setProperty(x*, const QString &, const QVariant &);
class Initializer
{
public:
Initializer(CGObjectInstance *);
};
#define INIT_OBJ_TYPE(x) initialize(dynamic_cast<x*>(o))
#define UPDATE_OBJ_PROPERTIES(x) updateProperties(dynamic_cast<x*>(obj))
#define SET_PROPERTIES(x) setProperty(dynamic_cast<x*>(obj), key, value)
//===============DECLARE MAP OBJECTS======================================
DECLARE_OBJ_TYPE(CArmedInstance);
DECLARE_OBJ_TYPE(CGTownInstance);
DECLARE_OBJ_TYPE(CGArtifact);
DECLARE_OBJ_TYPE(CGMine);
DECLARE_OBJ_TYPE(CGResource);
class Inspector
{
protected:
//===============DECLARE PROPERTIES SETUP=================================
DECLARE_OBJ_PROPERTY_METHODS(CArmedInstance);
DECLARE_OBJ_PROPERTY_METHODS(CGTownInstance);
DECLARE_OBJ_PROPERTY_METHODS(CGArtifact);
DECLARE_OBJ_PROPERTY_METHODS(CGMine);
DECLARE_OBJ_PROPERTY_METHODS(CGResource);
//===============DECLARE PROPERTY VALUE TYPE==============================
QTableWidgetItem * addProperty(unsigned int value);
QTableWidgetItem * addProperty(int value);
QTableWidgetItem * addProperty(const std::string & value);
QTableWidgetItem * addProperty(const QString & value);
QTableWidgetItem * addProperty(const int3 & value);
QTableWidgetItem * addProperty(const PlayerColor & value);
QTableWidgetItem * addProperty(const Res::ERes & value);
QTableWidgetItem * addProperty(bool value);
QTableWidgetItem * addProperty(CGObjectInstance * value);
//===============END OF DECLARATION=======================================
public:
Inspector(CGObjectInstance *, QTableWidget *);
@ -26,36 +55,45 @@ public:
void updateProperties();
protected:
QTableWidgetItem * addProperty(int value);
QTableWidgetItem * addProperty(const std::string & value);
QTableWidgetItem * addProperty(const QString & value);
QTableWidgetItem * addProperty(const int3 & value);
QTableWidgetItem * addProperty(const PlayerColor & value);
QTableWidgetItem * addProperty(bool value);
QTableWidgetItem * addProperty(CGObjectInstance * value);
void setProperty(CGTownInstance * obj, const QString & key, const QVariant & value);
template<class T>
void addProperty(const QString & key, const T & value, bool restricted = true)
{
auto * itemKey = new QTableWidgetItem(key);
auto * itemValue = addProperty(value);
itemKey->setFlags(Qt::NoItemFlags);
if(restricted)
itemValue->setFlags(Qt::NoItemFlags);
if(table->rowCount() < row + 1)
QTableWidgetItem * itemKey = nullptr;
if(keyItems.contains(key))
{
itemKey = keyItems[key];
table->setItem(table->row(itemKey), 1, itemValue);
}
else
{
itemKey = new QTableWidgetItem(key);
itemKey->setFlags(Qt::NoItemFlags);
keyItems[key] = itemKey;
table->setRowCount(row + 1);
table->setItem(row, 0, itemKey);
table->setItem(row, 1, itemValue);
++row;
}
}
protected:
int row = 0;
QTableWidget * table;
CGObjectInstance * obj;
QMap<QString, QTableWidgetItem*> keyItems;
};
class Initializer
{
public:
Initializer(CGObjectInstance *);
};
class PlayerColorDelegate : public QStyledItemDelegate

View File

@ -62,6 +62,7 @@ MainWindow::MainWindow(QWidget *parent) :
controller(this)
{
ui->setupUi(this);
setTitle();
// Set current working dir to executable folder.
// This is important on Mac for relative paths to work inside DMG.
@ -158,22 +159,24 @@ void MainWindow::reloadMap(int level)
//sceneMini->addPixmap(minimap);
}
void MainWindow::setTitle()
{
QString title = QString("%1%2 - %3 (v%4)").arg(filename, unsaved ? "*" : "", VCMI_EDITOR_NAME, VCMI_EDITOR_VERSION);
setWindowTitle(title);
}
void MainWindow::mapChanged()
{
unsaved = true;
setWindowTitle(filename + "* - VCMI Map Editor");
setTitle();
}
void MainWindow::initializeMap(bool isNew)
{
unsaved = isNew;
if(isNew)
{
filename.clear();
setWindowTitle("* - VCMI Map Editor");
}
else
setWindowTitle(filename + " - VCMI Map Editor");
setTitle();
mapLevel = 0;
ui->mapView->setScene(controller.scene(mapLevel));
@ -239,7 +242,7 @@ void MainWindow::saveMap()
}
unsaved = false;
setWindowTitle(filename + " - VCMI Map Editor");
setTitle();
}
void MainWindow::on_actionSave_as_triggered()
@ -793,7 +796,7 @@ void MainWindow::on_actionMapSettings_triggered()
void MainWindow::on_actionPlayers_settings_triggered()
{
auto settingsDialog = new PlayerSettings(*controller.map(), this);
auto settingsDialog = new PlayerSettings(controller, this);
settingsDialog->setWindowModality(Qt::WindowModal);
settingsDialog->setModal(true);
}

View File

@ -97,6 +97,7 @@ private:
void addGroupIntoCatalog(const std::string & groupName, bool staticOnly, int ID);
void changeBrushState(int idx);
void setTitle();
private:
Ui::MainWindow *ui;

View File

@ -1,21 +1,68 @@
#include "StdInc.h"
#include "playerparams.h"
#include "ui_playerparams.h"
#include "../lib/CTownHandler.h"
PlayerParams::PlayerParams(const CMapHeader & mapHeader, int playerId, QWidget *parent) :
PlayerParams::PlayerParams(MapController & ctrl, int playerId, QWidget *parent) :
QWidget(parent),
ui(new Ui::PlayerParams)
ui(new Ui::PlayerParams),
controller(ctrl)
{
ui->setupUi(this);
playerColor = playerId;
assert(mapHeader.players.size() > playerColor);
playerInfo = mapHeader.players[playerColor];
assert(controller.map()->players.size() > playerColor);
playerInfo = controller.map()->players[playerColor];
if(playerInfo.canComputerPlay)
//load factions
for(auto idx : VLC->townh->getAllowedFactions())
{
CFaction * faction = VLC->townh->objects.at(idx);
auto * item = new QListWidgetItem(QString::fromStdString(faction->name));
item->setData(Qt::UserRole, QVariant::fromValue(idx));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
ui->allowedFactions->addItem(item);
if(playerInfo.allowedFactions.count(idx))
item->setCheckState(Qt::Checked);
else
item->setCheckState(Qt::Unchecked);
}
QObject::connect(ui->allowedFactions, SIGNAL(itemChanged(QListWidgetItem*)),
this, SLOT(allowedFactionsCheck(QListWidgetItem*)));
//load checks
bool canHumanPlay = playerInfo.canHumanPlay; //need variable to restore after signal received
playerInfo.canComputerPlay = true; //computer always can play
ui->radioCpu->setChecked(true);
if(playerInfo.canHumanPlay)
if(canHumanPlay)
ui->radioHuman->setChecked(true);
if(playerInfo.isFactionRandom)
ui->randomFaction->setChecked(true);
if(playerInfo.generateHeroAtMainTown)
ui->generateHero->setChecked(true);
//load towns
int foundMainTown = -1;
for(int i = 0; i < controller.map()->towns.size(); ++i)
{
auto town = controller.map()->towns[i];
if(town->getOwner().getNum() == playerColor)
{
if(playerInfo.hasMainTown && playerInfo.posOfMainTown == town->pos)
foundMainTown = i;
ui->mainTown->addItem(QString::fromStdString(town->getObjectName()), QVariant::fromValue(i));
}
}
if(foundMainTown > -1)
{
ui->mainTown->setCurrentIndex(foundMainTown + 1);
}
else
{
playerInfo.hasMainTown = false;
playerInfo.posOfMainTown = int3(-1, -1, -1);
}
ui->playerColor->setTitle(QString("PlayerID: %1").arg(playerId));
show();
@ -39,3 +86,40 @@ void PlayerParams::on_radioCpu_toggled(bool checked)
playerInfo.canHumanPlay = false;
}
void PlayerParams::on_generateHero_stateChanged(int arg1)
{
playerInfo.generateHeroAtMainTown = ui->generateHero->isChecked();
}
void PlayerParams::on_randomFaction_stateChanged(int arg1)
{
playerInfo.isFactionRandom = ui->randomFaction->isChecked();
}
void PlayerParams::allowedFactionsCheck(QListWidgetItem * item)
{
if(item->checkState() == Qt::Checked)
playerInfo.allowedFactions.insert(item->data(Qt::UserRole).toInt());
else
playerInfo.allowedFactions.erase(item->data(Qt::UserRole).toInt());
}
void PlayerParams::on_mainTown_activated(int index)
{
if(index == 0) //default
{
playerInfo.hasMainTown = false;
playerInfo.posOfMainTown = int3(-1, -1, -1);
}
else
{
auto town = controller.map()->towns.at(ui->mainTown->currentData().toInt());
playerInfo.hasMainTown = true;
playerInfo.posOfMainTown = town->pos;
}
}

View File

@ -3,6 +3,7 @@
#include <QWidget>
#include "../lib/mapping/CMap.h"
#include "mapcontroller.h"
namespace Ui {
class PlayerParams;
@ -13,7 +14,7 @@ class PlayerParams : public QWidget
Q_OBJECT
public:
explicit PlayerParams(const CMapHeader & mapHeader, int playerId, QWidget *parent = nullptr);
explicit PlayerParams(MapController & controller, int playerId, QWidget *parent = nullptr);
~PlayerParams();
PlayerInfo playerInfo;
@ -24,8 +25,18 @@ private slots:
void on_radioCpu_toggled(bool checked);
void on_mainTown_activated(int index);
void on_generateHero_stateChanged(int arg1);
void on_randomFaction_stateChanged(int arg1);
void allowedFactionsCheck(QListWidgetItem *);
private:
Ui::PlayerParams *ui;
MapController & controller;
};
#endif // PLAYERPARAMS_H

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>505</width>
<height>146</height>
<height>160</height>
</rect>
</property>
<property name="sizePolicy">
@ -101,23 +101,34 @@
</property>
</widget>
</item>
<item row="1" column="2" rowspan="2">
<item row="1" column="1">
<widget class="QComboBox" name="mainTown">
<item>
<property name="text">
<string>(default)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2" rowspan="3">
<widget class="QListWidget" name="allowedFactions">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mainTown"/>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>All factions allowed</string>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>

View File

@ -4,20 +4,20 @@
#include "playerparams.h"
#include "mainwindow.h"
PlayerSettings::PlayerSettings(CMapHeader & mapHeader, QWidget *parent) :
PlayerSettings::PlayerSettings(MapController & ctrl, QWidget *parent) :
QDialog(parent),
ui(new Ui::PlayerSettings),
header(mapHeader)
controller(ctrl)
{
ui->setupUi(this);
show();
int players = 0;
for(auto & p : header.players)
for(auto & p : controller.map()->players)
{
if(p.canAnyonePlay())
{
paramWidgets.push_back(new PlayerParams(header, players));
paramWidgets.push_back(new PlayerParams(controller, players));
ui->playersLayout->addWidget(paramWidgets.back());
++players;
}
@ -36,23 +36,23 @@ PlayerSettings::~PlayerSettings()
void PlayerSettings::on_playersCount_currentIndexChanged(int index)
{
assert(index + 2 <= header.players.size());
assert(index + 2 <= controller.map()->players.size());
for(int i = 0; i < index + 2; ++i)
{
if(i < paramWidgets.size())
continue;
auto & p = header.players[i];
auto & p = controller.map()->players[i];
p.canComputerPlay = true;
paramWidgets.push_back(new PlayerParams(header, i));
paramWidgets.push_back(new PlayerParams(controller, i));
ui->playersLayout->addWidget(paramWidgets.back());
}
assert(!paramWidgets.empty());
for(int i = paramWidgets.size() - 1; i >= index + 2; --i)
{
auto & p = header.players[i];
auto & p = controller.map()->players[i];
p.canComputerPlay = false;
p.canHumanPlay = false;
ui->playersLayout->removeWidget(paramWidgets[i]);
@ -66,10 +66,10 @@ void PlayerSettings::on_pushButton_clicked()
{
for(auto * w : paramWidgets)
{
header.players[w->playerColor] = w->playerInfo;
controller.map()->players[w->playerColor] = w->playerInfo;
}
static_cast<MainWindow*>(parent())->controller.commitChangeWithoutRedraw();
controller.commitChangeWithoutRedraw();
close();
}

View File

@ -14,7 +14,7 @@ class PlayerSettings : public QDialog
Q_OBJECT
public:
explicit PlayerSettings(CMapHeader & mapHeader, QWidget *parent = nullptr);
explicit PlayerSettings(MapController & controller, QWidget *parent = nullptr);
~PlayerSettings();
private slots:
@ -28,7 +28,7 @@ private:
std::vector<PlayerParams*> paramWidgets;
CMapHeader & header;
MapController & controller;
};
#endif // PLAYERSETTINGS_H