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

bigfixing & new file: launcher/jsonutils.cpp

- launcher uses json parser from vcmi lib instead of one from Qt #1469
- fixed abilities overrides for some creatures #1476
- fixed hero portraits in seer huts #1402
- ttf fonts will render text in utf-8 mode. Not really useful at this point
- new settings entry, available in launcher: encoding. Unused for now.
This commit is contained in:
Ivan Savenko 2013-09-21 18:29:26 +00:00
parent d06b02638b
commit 208df34fc2
25 changed files with 423 additions and 257 deletions

View File

@ -632,7 +632,7 @@ namespace vstd
template <typename Container> template <typename Container>
typename Container::const_reference atOrDefault(const Container &r, size_t index, const typename Container::const_reference &defaultValue) typename Container::const_reference atOrDefault(const Container &r, size_t index, const typename Container::const_reference &defaultValue)
{ {
if(isValidIndex(r, index)) if(index < r.size())
return r[index]; return r[index];
return defaultValue; return defaultValue;

View File

@ -174,7 +174,7 @@
"faction": "fortress", "faction": "fortress",
"abilities" : "abilities" :
{ {
"SHOOTER" : null "SHOOTING_ARMY" : null
}, },
"graphics" : "graphics" :
{ {

View File

@ -943,7 +943,7 @@ size_t CComponent::getIndex()
case morale: return val+3; case morale: return val+3;
case luck: return val+3; case luck: return val+3;
case building: return val; case building: return val;
case hero: return CGI->heroh->heroes[subtype]->imageIndex; case hero: return subtype;
case flag: return subtype; case flag: return subtype;
} }
assert(0); assert(0);
@ -965,7 +965,7 @@ std::string CComponent::getDescription()
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)]; case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)]; case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description(); case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description();
case hero: return CGI->heroh->heroes[subtype]->name; case hero: return "";
case flag: return ""; case flag: return "";
} }
assert(0); assert(0);
@ -1007,7 +1007,7 @@ std::string CComponent::getSubtitleInternal()
case morale: return ""; case morale: return "";
case luck: return ""; case luck: return "";
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name(); case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name();
case hero: return CGI->heroh->heroes[subtype]->name; case hero: return "";
case flag: return CGI->generaltexth->capColors[subtype]; case flag: return CGI->generaltexth->capColors[subtype];
} }
assert(0); assert(0);

View File

@ -270,9 +270,9 @@ void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data,
{ {
SDL_Surface * rendered; SDL_Surface * rendered;
if (blended) if (blended)
rendered = TTF_RenderText_Blended(font.get(), data.c_str(), color); rendered = TTF_RenderUTF8_Blended(font.get(), data.c_str(), color);
else else
rendered = TTF_RenderText_Solid(font.get(), data.c_str(), color); rendered = TTF_RenderUTF8_Solid(font.get(), data.c_str(), color);
assert(rendered); assert(rendered);

View File

@ -117,7 +117,7 @@
{ {
"type" : "DRAGON_NATURE" "type" : "DRAGON_NATURE"
}, },
"FLYING" : null "FLYING_ARMY" : null
}, },
"graphics" : "graphics" :
{ {

View File

@ -17,7 +17,7 @@
"type" : "object", "type" : "object",
"default": {}, "default": {},
"additionalProperties" : false, "additionalProperties" : false,
"required" : [ "classicCreatureWindow", "playerName", "showfps", "music", "sound" ], "required" : [ "classicCreatureWindow", "playerName", "showfps", "music", "sound", "encoding" ],
"properties" : { "properties" : {
"classicCreatureWindow" : { "classicCreatureWindow" : {
"type" : "boolean", "type" : "boolean",
@ -38,6 +38,10 @@
"sound" : { "sound" : {
"type" : "number", "type" : "number",
"default" : 88 "default" : 88
},
"encoding" : {
"type" : "string",
"default" : "native"
} }
} }
}, },

View File

@ -22,6 +22,7 @@ set(launcher_SRCS
main.cpp main.cpp
mainwindow_moc.cpp mainwindow_moc.cpp
launcherdirs.cpp launcherdirs.cpp
jsonutils.cpp
) )
set(launcher_FORMS set(launcher_FORMS

96
launcher/jsonutils.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "StdInc.h"
#include "jsonutils.h"
static QVariantMap JsonToMap(const JsonMap & json)
{
QVariantMap map;
for (auto & entry : json)
{
map.insert(QString::fromUtf8(entry.first.c_str()), JsonUtils::toVariant(entry.second));
}
return map;
}
static QVariantList JsonToList(const JsonVector & json)
{
QVariantList list;
for (auto & entry : json)
{
list.push_back(JsonUtils::toVariant(entry));
}
return list;
}
static JsonVector VariantToList(QVariantList variant)
{
JsonVector vector;
for (auto & entry : variant)
{
vector.push_back(JsonUtils::toJson(entry));
}
return vector;
}
static JsonMap VariantToMap(QVariantMap variant)
{
JsonMap map;
for (auto & entry : variant.toStdMap())
{
map[entry.first.toUtf8().data()] = JsonUtils::toJson(entry.second);
}
return map;
}
namespace JsonUtils
{
QVariant toVariant(const JsonNode & node)
{
switch (node.getType())
{
break; case JsonNode::DATA_NULL: return QVariant();
break; case JsonNode::DATA_BOOL: return QVariant(node.Bool());
break; case JsonNode::DATA_FLOAT: return QVariant(node.Float());
break; case JsonNode::DATA_STRING: return QVariant(QString::fromUtf8(node.String().c_str()));
break; case JsonNode::DATA_VECTOR: return JsonToList(node.Vector());
break; case JsonNode::DATA_STRUCT: return JsonToMap(node.Struct());
}
return QVariant();
}
QVariant JsonFromFile(QString filename)
{
QFile file(filename);
file.open(QFile::ReadOnly);
auto data = file.readAll();
JsonNode node(data.data(), data.size());
return toVariant(node);
}
JsonNode toJson(QVariant object)
{
JsonNode ret;
if (object.canConvert<QVariantMap>())
ret.Struct() = VariantToMap(object.toMap());
if (object.canConvert<QVariantList>())
ret.Vector() = VariantToList(object.toList());
if (object.canConvert<QString>())
ret.String() = object.toString().toUtf8().data();
if (object.canConvert<double>())
ret.Bool() = object.toFloat();
if (object.canConvert<bool>())
ret.Bool() = object.toBool();
return ret;
}
void JsonToFile(QString filename, QVariant object)
{
std::ofstream file(filename.toUtf8().data(), std::ofstream::binary);
file << toJson(object);
}
}

13
launcher/jsonutils.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <QVariant>
#include "../lib/JsonNode.h"
namespace JsonUtils
{
QVariant toVariant(const JsonNode & node);
QVariant JsonFromFile(QString filename);
JsonNode toJson(QVariant object);
void JsonToFile(QString filename, QVariant object);
}

View File

@ -1,6 +1,9 @@
#include "StdInc.h" #include "StdInc.h"
#include "cmodlist.h" #include "cmodlist.h"
#include "../../lib/JsonNode.h"
#include "../../lib/filesystem/CFileInputStream.h"
bool CModEntry::compareVersions(QString lesser, QString greater) bool CModEntry::compareVersions(QString lesser, QString greater)
{ {
static const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch static const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch
@ -25,7 +28,7 @@ bool CModEntry::compareVersions(QString lesser, QString greater)
return false; return false;
} }
CModEntry::CModEntry(QJsonObject repository, QJsonObject localData, QJsonValue modSettings, QString modname): CModEntry::CModEntry(QVariantMap repository, QVariantMap localData, QVariant modSettings, QString modname):
repository(repository), repository(repository),
localData(localData), localData(localData),
modSettings(modSettings), modSettings(modSettings),
@ -38,7 +41,7 @@ bool CModEntry::isEnabled() const
if (!isInstalled()) if (!isInstalled())
return false; return false;
return modSettings.toBool(false); return modSettings.toBool();
} }
bool CModEntry::isDisabled() const bool CModEntry::isDisabled() const
@ -89,24 +92,24 @@ QString CModEntry::getName() const
QVariant CModEntry::getValue(QString value) const QVariant CModEntry::getValue(QString value) const
{ {
if (repository.contains(value)) if (repository.contains(value))
return repository[value].toVariant(); return repository[value];
if (localData.contains(value)) if (localData.contains(value))
return localData[value].toVariant(); return localData[value];
return QVariant(); return QVariant();
} }
QJsonObject CModList::copyField(QJsonObject data, QString from, QString to) QVariantMap CModList::copyField(QVariantMap data, QString from, QString to)
{ {
QJsonObject renamed; QVariantMap renamed;
for (auto it = data.begin(); it != data.end(); it++) for (auto it = data.begin(); it != data.end(); it++)
{ {
QJsonObject object = it.value().toObject(); QVariant object = it.value();
object.insert(to, object.value(from)); object.toMap().insert(to, object.toMap().value(from));
renamed.insert(it.key(), QJsonValue(object)); renamed.insert(it.key(), object.toMap());
} }
return renamed; return renamed;
} }
@ -116,40 +119,40 @@ void CModList::resetRepositories()
repositories.clear(); repositories.clear();
} }
void CModList::addRepository(QJsonObject data) void CModList::addRepository(QVariantMap data)
{ {
repositories.push_back(copyField(data, "version", "latestVersion")); repositories.push_back(copyField(data, "version", "latestVersion"));
} }
void CModList::setLocalModList(QJsonObject data) void CModList::setLocalModList(QVariantMap data)
{ {
localModList = copyField(data, "version", "installedVersion"); localModList = copyField(data, "version", "installedVersion");
} }
void CModList::setModSettings(QJsonObject data) void CModList::setModSettings(QVariant data)
{ {
modSettings = data; modSettings = data.toMap();
} }
CModEntry CModList::getMod(QString modname) const CModEntry CModList::getMod(QString modname) const
{ {
assert(hasMod(modname)); assert(hasMod(modname));
QJsonObject repo; QVariantMap repo;
QJsonObject local = localModList[modname].toObject(); QVariantMap local = localModList[modname].toMap();
QJsonValue settings = modSettings[modname]; QVariant settings = modSettings[modname];
for (auto entry : repositories) for (auto entry : repositories)
{ {
if (entry.contains(modname)) if (entry.contains(modname))
{ {
if (repo.empty()) if (repo.empty())
repo = entry[modname].toObject(); repo = entry[modname].toMap();
else else
{ {
if (CModEntry::compareVersions(repo["version"].toString(), if (CModEntry::compareVersions(repo["version"].toString(),
entry[modname].toObject()["version"].toString())) entry[modname].toMap()["version"].toString()))
repo = entry[modname].toObject(); repo = entry[modname].toMap();
} }
} }
} }

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <QJsonDocument> #include <QVariantMap>
#include <QJsonObject>
#include <QVariant> #include <QVariant>
class JsonNode;
namespace ModStatus namespace ModStatus
{ {
enum EModStatus enum EModStatus
@ -19,13 +20,13 @@ namespace ModStatus
class CModEntry class CModEntry
{ {
// repository contains newest version only (if multiple are available) // repository contains newest version only (if multiple are available)
QJsonObject repository; QVariantMap repository;
QJsonObject localData; QVariantMap localData;
QJsonValue modSettings; QVariant modSettings;
QString modname; QString modname;
public: public:
CModEntry(QJsonObject repository, QJsonObject localData, QJsonValue modSettings, QString modname); CModEntry(QVariantMap repository, QVariantMap localData, QVariant modSettings, QString modname);
// installed and enabled // installed and enabled
bool isEnabled() const; bool isEnabled() const;
@ -52,16 +53,16 @@ public:
class CModList class CModList
{ {
QVector<QJsonObject> repositories; QVector<QVariantMap> repositories;
QJsonObject localModList; QVariantMap localModList;
QJsonObject modSettings; QVariantMap modSettings;
QJsonObject copyField(QJsonObject data, QString from, QString to); QVariantMap copyField(QVariantMap data, QString from, QString to);
public: public:
virtual void resetRepositories(); virtual void resetRepositories();
virtual void addRepository(QJsonObject data); virtual void addRepository(QVariantMap data);
virtual void setLocalModList(QJsonObject data); virtual void setLocalModList(QVariantMap data);
virtual void setModSettings(QJsonObject data); virtual void setModSettings(QVariant data);
// returns mod by name. Note: mod MUST exist // returns mod by name. Note: mod MUST exist
CModEntry getMod(QString modname) const; CModEntry getMod(QString modname) const;

View File

@ -117,21 +117,21 @@ void CModListModel::resetRepositories()
endResetModel(); endResetModel();
} }
void CModListModel::addRepository(QJsonObject data) void CModListModel::addRepository(QVariantMap data)
{ {
beginResetModel(); beginResetModel();
CModList::addRepository(data); CModList::addRepository(data);
endResetModel(); endResetModel();
} }
void CModListModel::setLocalModList(QJsonObject data) void CModListModel::setLocalModList(QVariantMap data)
{ {
beginResetModel(); beginResetModel();
CModList::setLocalModList(data); CModList::setLocalModList(data);
endResetModel(); endResetModel();
} }
void CModListModel::setModSettings(QJsonObject data) void CModListModel::setModSettings(QVariant data)
{ {
beginResetModel(); beginResetModel();
CModList::setModSettings(data); CModList::setModSettings(data);

View File

@ -30,9 +30,9 @@ class CModListModel : public QAbstractTableModel, public CModList
public: public:
/// CModListContainer overrides /// CModListContainer overrides
void resetRepositories(); void resetRepositories();
void addRepository(QJsonObject data); void addRepository(QVariantMap data);
void setLocalModList(QJsonObject data); void setLocalModList(QVariantMap data);
void setModSettings(QJsonObject data); void setModSettings(QVariant data);
QString modIndexToName(int index) const; QString modIndexToName(int index) const;

View File

@ -5,23 +5,9 @@
#include "../../lib/filesystem/Filesystem.h" #include "../../lib/filesystem/Filesystem.h"
#include "../../lib/filesystem/CZipLoader.h" #include "../../lib/filesystem/CZipLoader.h"
#include "../jsonutils.h"
#include "../launcherdirs.h" #include "../launcherdirs.h"
static QJsonObject JsonFromFile(QString filename)
{
QFile file(filename);
file.open(QFile::ReadOnly);
return QJsonDocument::fromJson(file.readAll()).object();
}
static void JsonToFile(QString filename, QJsonObject object)
{
QFile file(filename);
file.open(QFile::WriteOnly);
file.write(QJsonDocument(object).toJson());
}
static QString detectModArchive(QString path, QString modName) static QString detectModArchive(QString path, QString modName)
{ {
auto files = ZipArchive::listFiles(path.toUtf8().data()); auto files = ZipArchive::listFiles(path.toUtf8().data());
@ -57,8 +43,8 @@ QString CModManager::settingsPath()
void CModManager::loadModSettings() void CModManager::loadModSettings()
{ {
modSettings = JsonFromFile(settingsPath()); modSettings = JsonUtils::JsonFromFile(settingsPath()).toMap();
modList->setModSettings(modSettings["activeMods"].toObject()); modList->setModSettings(modSettings["activeMods"]);
} }
void CModManager::resetRepositories() void CModManager::resetRepositories()
@ -68,7 +54,7 @@ void CModManager::resetRepositories()
void CModManager::loadRepository(QString file) void CModManager::loadRepository(QString file)
{ {
modList->addRepository(JsonFromFile(file)); modList->addRepository(JsonUtils::JsonFromFile(file).toMap());
} }
void CModManager::loadMods() void CModManager::loadMods()
@ -78,17 +64,9 @@ void CModManager::loadMods()
for (auto modname : installedMods) for (auto modname : installedMods)
{ {
ResourceID resID("Mods/" + modname + "/mod.json"); ResourceID resID("Mods/" + modname + "/mod.json");
std::string name = *CResourceHandler::get()->getResourceName(resID);
if (CResourceHandler::get()->existsResource(resID)) auto mod = JsonUtils::JsonFromFile(QString::fromUtf8(name.c_str()));
{ localMods.insert(QString::fromUtf8(modname.c_str()).toLower(), mod);
auto data = CResourceHandler::get()->load(resID)->readAll();
auto array = QByteArray(reinterpret_cast<char *>(data.first.get()), data.second);
auto mod = QJsonDocument::fromJson(array);
assert (mod.isObject()); // TODO: use JsonNode from vcmi code here - QJsonNode parser is just too pedantic
localMods.insert(QString::fromUtf8(modname.c_str()).toLower(), QJsonValue(mod.object()));
}
} }
modList->setLocalModList(localMods); modList->setLocalModList(localMods);
} }
@ -209,15 +187,15 @@ bool CModManager::canDisableMod(QString modname)
bool CModManager::doEnableMod(QString mod, bool on) bool CModManager::doEnableMod(QString mod, bool on)
{ {
QJsonValue value(on); QVariant value(on);
QJsonObject list = modSettings["activeMods"].toObject(); QVariantMap list = modSettings["activeMods"].toMap();
list.insert(mod, value); list.insert(mod, value);
modSettings.insert("activeMods", list); modSettings.insert("activeMods", list);
modList->setModSettings(modSettings["activeMods"].toObject()); modList->setModSettings(modSettings["activeMods"]);
JsonToFile(settingsPath(), modSettings); JsonUtils::JsonToFile(settingsPath(), modSettings);
return true; return true;
} }
@ -245,7 +223,7 @@ bool CModManager::doInstallMod(QString modname, QString archivePath)
return addError(modname, "Failed to extract mod data"); return addError(modname, "Failed to extract mod data");
} }
QJsonObject json = JsonFromFile(destDir + modDirName + "/mod.json"); QVariantMap json = JsonUtils::JsonFromFile(destDir + modDirName + "/mod.json").toMap();
localMods.insert(modname, json); localMods.insert(modname, json);
modList->setLocalModList(localMods); modList->setLocalModList(localMods);

View File

@ -13,8 +13,8 @@ class CModManager
bool doInstallMod(QString mod, QString archivePath); bool doInstallMod(QString mod, QString archivePath);
bool doUninstallMod(QString mod); bool doUninstallMod(QString mod);
QJsonObject modSettings; QVariantMap modSettings;
QJsonObject localMods; QVariantMap localMods;
QStringList recentErrors; QStringList recentErrors;
bool addError(QString modname, QString message); bool addError(QString modname, QString message);

View File

@ -108,5 +108,17 @@ void CSettingsView::on_plainTextEditRepos_textChanged()
node->Vector().push_back(entry); node->Vector().push_back(entry);
} }
} }
}
void CSettingsView::on_comboBoxEncoding_currentIndexChanged(int index)
{
std::string encodings[] =
{
"native", // right now indicates disabled unicode, may be removed in future
"CP1250", "CP1251", "CP1252", // european Windows-125X encoding
"GBK", "gb2312" // chinese, aka CP936. Same encoding rules but different font files.
};
Settings node = settings.write["general"]["encoding"];
node->String() = encodings[index];
} }

View File

@ -29,6 +29,8 @@ private slots:
void on_plainTextEditRepos_textChanged(); void on_plainTextEditRepos_textChanged();
void on_comboBoxEncoding_currentIndexChanged(int index);
private: private:
Ui::CSettingsView *ui; Ui::CSettingsView *ui;
}; };

View File

@ -7,13 +7,82 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>700</width> <width>700</width>
<height>303</height> <height>308</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxFullScreen">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Off</string>
</property>
</item>
<item>
<property name="text">
<string>On</string>
</property>
</item>
</widget>
</item>
<item row="11" column="0" colspan="5">
<widget class="QPlainTextEdit" name="plainTextEditRepos">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="plainText">
<string>http://downloads.vcmi.eu/Mods/repository.json</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLineEdit" name="lineEditUserDataDir">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>/home/user/.vcmi</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelPlayerAI">
<property name="text">
<string>Player AI</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="spacerColumns">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>8</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="4"> <item row="1" column="4">
<widget class="QLineEdit" name="lineEditGameDir"> <widget class="QLineEdit" name="lineEditGameDir">
<property name="enabled"> <property name="enabled">
@ -33,7 +102,54 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="7" column="3">
<widget class="QLabel" name="labelEnableMods">
<property name="text">
<string>Enable mods on install</string>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QSpinBox" name="spinBoxNetworkPort">
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>3030</number>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="labelUserDataDir">
<property name="text">
<string>User data directory</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="labelGameDir">
<property name="text">
<string>Game directory</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="labelAISettings">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>AI Settings</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="spacerRepos"> <spacer name="spacerRepos">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -56,39 +172,55 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="0" column="0" colspan="2">
<spacer name="spacerSections"> <widget class="QLabel" name="labelVideo">
<property name="orientation"> <property name="font">
<enum>Qt::Vertical</enum> <font>
<weight>75</weight>
<bold>true</bold>
</font>
</property> </property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>56</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelFullScreen">
<property name="text"> <property name="text">
<string>Fullscreen</string> <string>Video</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="4"> <item row="0" column="3" colspan="2">
<widget class="QSpinBox" name="spinBoxNetworkPort"> <widget class="QLabel" name="labelDataDirs">
<property name="minimum"> <property name="font">
<number>1024</number> <font>
<weight>75</weight>
<bold>true</bold>
</font>
</property> </property>
<property name="maximum"> <property name="text">
<number>65535</number> <string>Data Directories (unchangeable)</string>
</property> </property>
<property name="value"> </widget>
<number>3030</number> </item>
<item row="9" column="0" colspan="2">
<widget class="QLabel" name="labelRepositories">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Repositories</string>
</property>
</widget>
</item>
<item row="4" column="3" colspan="2">
<widget class="QLabel" name="labelGeneral">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>General</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -167,14 +299,7 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="2" column="3"> <item row="7" column="4">
<widget class="QLabel" name="labelUserDataDir">
<property name="text">
<string>User data directory</string>
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QComboBox" name="comboBoxEnableMods"> <widget class="QComboBox" name="comboBoxEnableMods">
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>1</number>
@ -191,100 +316,61 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="8" column="0" colspan="2"> <item row="3" column="0">
<widget class="QLabel" name="labelRepositories"> <spacer name="spacerSections">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Repositories</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="5">
<widget class="QPlainTextEdit" name="plainTextEditRepos">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="plainText">
<string>http://downloads.vcmi.eu/Mods/repository.json</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelPlayerAI">
<property name="text">
<string>Player AI</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="spacerColumns">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType"> <property name="sizeType">
<enum>QSizePolicy::Fixed</enum> <enum>QSizePolicy::Fixed</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>8</width> <width>56</width>
<height>20</height> <height>8</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="2" column="1"> <item row="2" column="0">
<widget class="QComboBox" name="comboBoxFullScreen"> <widget class="QLabel" name="labelFullScreen">
<property name="currentIndex"> <property name="text">
<number>0</number> <string>Fullscreen</string>
</property> </property>
</widget>
</item>
<item row="6" column="4">
<widget class="QComboBox" name="comboBoxEncoding">
<item> <item>
<property name="text"> <property name="text">
<string>Off</string> <string>Native (unicode disabled)</string>
</property> </property>
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>On</string> <string>Central European (Windows 1250)</string>
</property>
</item>
<item>
<property name="text">
<string>Cyrillic script (Windows 1251)</string>
</property>
</item>
<item>
<property name="text">
<string>Western European (Windows 1252)</string>
</property>
</item>
<item>
<property name="text">
<string>Simplified Chinese (GBK)</string>
</property>
</item>
<item>
<property name="text">
<string>Simplified Chinese (GB2312)</string>
</property> </property>
</item> </item>
</widget>
</item>
<item row="6" column="3">
<widget class="QLabel" name="labelEnableMods">
<property name="text">
<string>Enable mods on install</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLineEdit" name="lineEditUserDataDir">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>/home/user/.vcmi</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="labelNeutralAI">
<property name="text">
<string>Neutral AI</string>
</property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="6" column="1">
@ -301,62 +387,17 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="1" column="3"> <item row="6" column="0">
<widget class="QLabel" name="labelGameDir"> <widget class="QLabel" name="labelNeutralAI">
<property name="text"> <property name="text">
<string>Game directory</string> <string>Neutral AI</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="2"> <item row="6" column="3">
<widget class="QLabel" name="labelAISettings"> <widget class="QLabel" name="labelEncoding">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text"> <property name="text">
<string>AI Settings</string> <string>Heroes III character set</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="labelVideo">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Video</string>
</property>
</widget>
</item>
<item row="0" column="3" colspan="2">
<widget class="QLabel" name="labelDataDirs">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Data Directories (unchangeable)</string>
</property>
</widget>
</item>
<item row="4" column="3" colspan="2">
<widget class="QLabel" name="labelGeneral">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>General</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -472,7 +472,7 @@ void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNod
{ {
auto object = loadFromJson(data); auto object = loadFromJson(data);
object->ID = HeroTypeID(heroes.size()); object->ID = HeroTypeID(heroes.size());
object->imageIndex = heroes.size() + 10; // 2 special frames + some extra portraits object->imageIndex = heroes.size() + 30; // 2 special frames + some extra portraits
heroes.push_back(object); heroes.push_back(object);

View File

@ -95,7 +95,7 @@ set(lib_HEADERS
add_library(vcmi SHARED ${lib_SRCS} ${lib_HEADERS}) add_library(vcmi SHARED ${lib_SRCS} ${lib_HEADERS})
set_target_properties(vcmi PROPERTIES XCODE_ATTRIBUTE_LD_DYLIB_INSTALL_NAME "@executable_path/libvcmi.dylib") set_target_properties(vcmi PROPERTIES XCODE_ATTRIBUTE_LD_DYLIB_INSTALL_NAME "@executable_path/libvcmi.dylib")
target_link_libraries(vcmi minizip ${Boost_LIBRARIES} ${SDL_LIBRARY} ${ZLIB_LIBRARIES}) target_link_libraries(vcmi minizip ${Boost_LIBRARIES} ${SDL_LIBRARY} ${ZLIB_LIBRARIES} ${RT_LIB} ${DL_LIB})
if (NOT APPLE) # Already inside vcmiclient bundle if (NOT APPLE) # Already inside vcmiclient bundle
install(TARGETS vcmi DESTINATION ${LIB_DIR}) install(TARGETS vcmi DESTINATION ${LIB_DIR})

View File

@ -141,17 +141,29 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
auto entries = registeredObjects.equal_range(fullID); auto entries = registeredObjects.equal_range(fullID);
if (entries.first != entries.second) if (entries.first != entries.second)
{ {
size_t matchesFound = 0;
for (auto it = entries.first; it != entries.second; it++) for (auto it = entries.first; it != entries.second; it++)
{ {
if (vstd::contains(allowedScopes, it->second.scope)) if (vstd::contains(allowedScopes, it->second.scope))
{ {
request.callback(it->second.id); if (matchesFound == 0) // trigger only once
return true; request.callback(it->second.id);
matchesFound++;
} }
} }
if (matchesFound == 1)
return true; // success, only one matching ID
// error found. Try to generate some debug info // error found. Try to generate some debug info
logGlobal->errorStream() << "Unknown identifier " << request.type << "." << request.name << " from mod " << request.localScope; if (matchesFound == 0)
logGlobal->errorStream() << "Unknown identifier!";
else
logGlobal->errorStream() << "Ambiguous identifier request!";
logGlobal->errorStream() << "Request for " << request.type << "." << request.name << " from mod " << request.localScope;
for (auto it = entries.first; it != entries.second; it++) for (auto it = entries.first; it != entries.second; it++)
{ {
logGlobal->errorStream() << "\tID is available in mod " << it->second.scope; logGlobal->errorStream() << "\tID is available in mod " << it->second.scope;

View File

@ -4494,12 +4494,13 @@ void CQuest::getVisitText (MetaString &iwText, std::vector<Component> &component
} }
break; break;
case MISSION_KILL_HERO: case MISSION_KILL_HERO:
components.push_back(Component(Component::HERO, heroPortrait, 0, 0)); components.push_back(Component(Component::HERO_PORTRAIT, heroPortrait, 0, 0));
if (!isCustom) if (!isCustom)
addReplacements(iwText, text); addReplacements(iwText, text);
break; break;
case MISSION_HERO: case MISSION_HERO:
components.push_back(Component (Component::HERO, m13489val, 0, 0)); //FIXME: portrait may not match hero, if custom portrait was set in map editor
components.push_back(Component (Component::HERO_PORTRAIT, VLC->heroh->heroes[m13489val]->imageIndex, 0, 0));
if (!isCustom) if (!isCustom)
iwText.addReplacement(VLC->heroh->heroes[m13489val]->name); iwText.addReplacement(VLC->heroh->heroes[m13489val]->name);
break; break;

View File

@ -1138,7 +1138,7 @@ struct NewTurn : public CPackForClient //101
struct Component : public CPack //2002 helper for object scrips informations struct Component : public CPack //2002 helper for object scrips informations
{ {
enum EComponentType {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE, LUCK, BUILDING, HERO, FLAG}; enum EComponentType {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE, LUCK, BUILDING, HERO_PORTRAIT, FLAG};
ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels) ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels)
si32 val; // + give; - take si32 val; // + give; - take
si16 when; // 0 - now; +x - within x days; -x - per x days si16 when; // 0 - now; +x - within x days; -x - per x days

View File

@ -1011,15 +1011,15 @@ DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
CGHeroInstance* h = gs->getHero(hero->id); CGHeroInstance* h = gs->getHero(hero->id);
h->level = level; h->level = level;
//deterministic secondary skills //deterministic secondary skills
h->skillsInfo.magicSchoolCounter = (++h->skillsInfo.magicSchoolCounter) % h->maxlevelsToMagicSchool(); h->skillsInfo.magicSchoolCounter = (h->skillsInfo.magicSchoolCounter + 1) % h->maxlevelsToMagicSchool();
h->skillsInfo.wisdomCounter = (++h->skillsInfo.wisdomCounter) % h->maxlevelsToWisdom(); h->skillsInfo.wisdomCounter = (h->skillsInfo.wisdomCounter + 1) % h->maxlevelsToWisdom();
if (vstd::contains(skills, SecondarySkill::WISDOM)) if (vstd::contains(skills, SecondarySkill::WISDOM))
h->skillsInfo.resetWisdomCounter(); h->skillsInfo.resetWisdomCounter();
SecondarySkill spellSchools[] = { SecondarySkill spellSchools[] = {
SecondarySkill::FIRE_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC, SecondarySkill::EARTH_MAGIC}; SecondarySkill::FIRE_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC, SecondarySkill::EARTH_MAGIC};
for (auto skill : spellSchools) for (auto skill : spellSchools)
{ {
if (vstd::contains(skills, SecondarySkill::WISDOM)) if (vstd::contains(skills, skill))
{ {
h->skillsInfo.resetMagicSchoolCounter(); h->skillsInfo.resetMagicSchoolCounter();
break; break;

View File

@ -300,7 +300,9 @@ std::vector<std::string> CResourceHandler::getAvailableMods()
continue; continue;
} }
} }
foundMods.push_back(name);
if (!name.empty())
foundMods.push_back(name);
} }
return foundMods; return foundMods;
} }