mirror of
https://github.com/huderlem/porymap.git
synced 2026-03-22 01:54:46 -05:00
Merge pull request #713 from GriffinRichards/custom-json-data
Preserve custom JSON data
This commit is contained in:
commit
d350d10cfd
|
|
@ -39,7 +39,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>568</height>
|
||||
<height>589</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
|
|
@ -66,6 +66,16 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_PreserveMatchingOnlyData">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If enabled, Porymap will not discard data like &quot;connections_include_order&quot; or &quot;name_clone&quot;, which serve no purpose other than recreating the original game.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Preserve data only needed to match the original game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -1084,7 +1094,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>788</height>
|
||||
<height>840</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
|
|
|
|||
|
|
@ -323,6 +323,7 @@ public:
|
|||
this->tilesetsHaveCallback = true;
|
||||
this->tilesetsHaveIsCompressed = true;
|
||||
this->setTransparentPixelsBlack = true;
|
||||
this->preserveMatchingOnlyData = false;
|
||||
this->filePaths.clear();
|
||||
this->eventIconPaths.clear();
|
||||
this->pokemonIconPaths.clear();
|
||||
|
|
@ -389,6 +390,7 @@ public:
|
|||
bool tilesetsHaveCallback;
|
||||
bool tilesetsHaveIsCompressed;
|
||||
bool setTransparentPixelsBlack;
|
||||
bool preserveMatchingOnlyData;
|
||||
int metatileAttributesSize;
|
||||
uint32_t metatileBehaviorMask;
|
||||
uint32_t metatileTerrainTypeMask;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <QPointer>
|
||||
|
||||
#include "orderedjson.h"
|
||||
#include "parseutil.h"
|
||||
|
||||
|
||||
class Project;
|
||||
|
|
@ -139,15 +140,14 @@ public:
|
|||
Event::Type getEventType() const { return this->eventType; }
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) = 0;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) = 0;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) = 0;
|
||||
|
||||
virtual void setDefaultValues(Project *project);
|
||||
|
||||
virtual QSet<QString> getExpectedFields() = 0;
|
||||
void readCustomAttributes(const QJsonObject &json);
|
||||
void addCustomAttributesTo(OrderedJson::object *obj) const;
|
||||
const QMap<QString, QJsonValue> getCustomAttributes() const { return this->customAttributes; }
|
||||
void setCustomAttributes(const QMap<QString, QJsonValue> newCustomAttributes) { this->customAttributes = newCustomAttributes; }
|
||||
|
||||
QJsonObject getCustomAttributes() const { return this->customAttributes; }
|
||||
void setCustomAttributes(const QJsonObject &newCustomAttributes) { this->customAttributes = newCustomAttributes; }
|
||||
|
||||
virtual void loadPixmap(Project *project);
|
||||
|
||||
|
|
@ -191,12 +191,16 @@ protected:
|
|||
// When deleting events like this we want to warn the user that the #define may also be deleted.
|
||||
QString idName;
|
||||
|
||||
QMap<QString, QJsonValue> customAttributes;
|
||||
QJsonObject customAttributes;
|
||||
|
||||
QPixmap pixmap;
|
||||
DraggablePixmapItem *pixmapItem = nullptr;
|
||||
|
||||
QPointer<EventFrame> eventFrame;
|
||||
|
||||
static QString readString(QJsonObject *object, const QString &key) { return ParseUtil::jsonToQString(object->take(key)); }
|
||||
static int readInt(QJsonObject *object, const QString &key) { return ParseUtil::jsonToInt(object->take(key)); }
|
||||
static bool readBool(QJsonObject *object, const QString &key) { return ParseUtil::jsonToBool(object->take(key)); }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -219,7 +223,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -286,7 +290,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -324,7 +328,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -361,7 +365,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override = 0;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override = 0;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override = 0;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override = 0;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override = 0;
|
||||
|
||||
|
|
@ -389,7 +393,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -429,7 +433,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -460,7 +464,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override = 0;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override = 0;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override = 0;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override = 0;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override = 0;
|
||||
|
||||
|
|
@ -487,7 +491,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -522,7 +526,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -567,7 +571,7 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &json, Project *project) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
|
|
@ -599,12 +603,15 @@ public:
|
|||
virtual EventFrame *createEventFrame() override;
|
||||
|
||||
virtual OrderedJson::object buildEventJson(Project *project) override;
|
||||
virtual bool loadFromJson(const QJsonObject &, Project *) override;
|
||||
virtual bool loadFromJson(QJsonObject json, Project *project) override;
|
||||
|
||||
virtual void setDefaultValues(Project *project) override;
|
||||
|
||||
virtual QSet<QString> getExpectedFields() override;
|
||||
|
||||
void setHostMapName(QString newHostMapName) { this->hostMapName = newHostMapName; }
|
||||
QString getHostMapName() const;
|
||||
|
||||
void setRespawnMapName(QString newRespawnMapName) { this->respawnMapName = newRespawnMapName; }
|
||||
QString getRespawnMapName() const { return this->respawnMapName; }
|
||||
|
||||
|
|
@ -614,6 +621,7 @@ public:
|
|||
private:
|
||||
QString respawnMapName;
|
||||
QString respawnNPC;
|
||||
QString hostMapName; // Only needed if the host map fails to load.
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ public:
|
|||
bool hasUnsavedChanges() const;
|
||||
void pruneEditHistory();
|
||||
|
||||
void setCustomAttributes(const QMap<QString, QJsonValue> &attributes) { m_customAttributes = attributes; }
|
||||
QMap<QString, QJsonValue> customAttributes() const { return m_customAttributes; }
|
||||
void setCustomAttributes(const QJsonObject &attributes) { m_customAttributes = attributes; }
|
||||
QJsonObject customAttributes() const { return m_customAttributes; }
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
|
|
@ -110,7 +110,7 @@ private:
|
|||
QString m_sharedScriptsMap = "";
|
||||
|
||||
QStringList m_scriptsFileLabels;
|
||||
QMap<QString, QJsonValue> m_customAttributes;
|
||||
QJsonObject m_customAttributes;
|
||||
|
||||
MapHeader *m_header = nullptr;
|
||||
Layout *m_layout = nullptr;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <QString>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
#include <QJsonObject>
|
||||
|
||||
class Project;
|
||||
class Map;
|
||||
|
|
@ -34,6 +35,9 @@ public:
|
|||
int offset() const { return m_offset; }
|
||||
void setOffset(int offset, bool mirror = true);
|
||||
|
||||
QJsonObject customData() const { return m_customData; }
|
||||
void setCustomData(const QJsonObject &customData) { m_customData = customData; }
|
||||
|
||||
MapConnection* findMirror();
|
||||
MapConnection* createMirror();
|
||||
|
||||
|
|
@ -55,6 +59,7 @@ private:
|
|||
QString m_targetMapName;
|
||||
QString m_direction;
|
||||
int m_offset;
|
||||
QJsonObject m_customData;
|
||||
|
||||
void markMapEdited();
|
||||
Map* getMap(const QString& mapName) const;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ public:
|
|||
Tileset *tileset_primary = nullptr;
|
||||
Tileset *tileset_secondary = nullptr;
|
||||
|
||||
QJsonObject customData;
|
||||
|
||||
Blockdata blockdata;
|
||||
|
||||
QImage image;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
QMap<QString, int> readCDefinesByRegex(const QString &filename, const QSet<QString> ®exList, QString *error = nullptr);
|
||||
QMap<QString, int> readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error = nullptr);
|
||||
QStringList readCDefineNames(const QString &filename, const QSet<QString> ®exList, QString *error = nullptr);
|
||||
tsl::ordered_map<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString>& = {});
|
||||
OrderedMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString>& = {});
|
||||
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);
|
||||
QStringList getLabelValues(const QList<QStringList>&, const QString&);
|
||||
bool tryParseJsonFile(QJsonDocument *out, const QString &filepath, QString *error = nullptr);
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ public:
|
|||
bool loadLayout(poryjson::Json);
|
||||
bool loadEntries();
|
||||
|
||||
void setEntries(QMap<QString, MapSectionEntry> *entries) { this->region_map_entries = entries; }
|
||||
void setEntries(const QMap<QString, MapSectionEntry> &entries) { *(this->region_map_entries) = entries; }
|
||||
void setEntries(QHash<QString, MapSectionEntry> *entries) { this->region_map_entries = entries; }
|
||||
void setEntries(const QHash<QString, MapSectionEntry> &entries) { *(this->region_map_entries) = entries; }
|
||||
void clearEntries() { this->region_map_entries->clear(); }
|
||||
MapSectionEntry getEntry(QString section);
|
||||
void setEntry(QString section, MapSectionEntry entry);
|
||||
|
|
@ -151,7 +151,7 @@ signals:
|
|||
void mapNeedsDisplaying();
|
||||
|
||||
private:
|
||||
QMap<QString, MapSectionEntry> *region_map_entries = nullptr;
|
||||
QHash<QString, MapSectionEntry> *region_map_entries = nullptr;
|
||||
|
||||
QString alias = "";
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ private:
|
|||
/// ClearEntries
|
||||
class ClearEntries : public QUndoCommand {
|
||||
public:
|
||||
ClearEntries(RegionMap *map, QMap<QString, MapSectionEntry>, QUndoCommand *parent = nullptr);
|
||||
ClearEntries(RegionMap *map, QHash<QString, MapSectionEntry>, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
|
@ -163,7 +163,7 @@ public:
|
|||
|
||||
private:
|
||||
RegionMap *map;
|
||||
QMap<QString, MapSectionEntry> entries;
|
||||
QHash<QString, MapSectionEntry> entries;
|
||||
};
|
||||
|
||||
#endif // REGIONMAPEDITCOMMANDS_H
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#define GUARD_WILDMONINFO_H
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "orderedmap.h"
|
||||
#include "orderedjson.h"
|
||||
|
||||
class WildPokemon {
|
||||
public:
|
||||
|
|
@ -13,22 +13,26 @@ public:
|
|||
int minLevel;
|
||||
int maxLevel;
|
||||
QString species;
|
||||
OrderedJson::object customData;
|
||||
};
|
||||
|
||||
struct WildMonInfo {
|
||||
bool active = false;
|
||||
int encounterRate = 0;
|
||||
QVector<WildPokemon> wildPokemon;
|
||||
OrderedJson::object customData;
|
||||
};
|
||||
|
||||
struct WildPokemonHeader {
|
||||
tsl::ordered_map<QString, WildMonInfo> wildMons;
|
||||
OrderedMap<QString, WildMonInfo> wildMons;
|
||||
OrderedJson::object customData;
|
||||
};
|
||||
|
||||
struct EncounterField {
|
||||
QString name; // Ex: "fishing_mons"
|
||||
QVector<int> encounterRates;
|
||||
tsl::ordered_map<QString, QVector<int>> groups; // Ex: "good_rod", {2, 3, 4}
|
||||
OrderedMap<QString, QVector<int>> groups; // Ex: "good_rod", {2, 3, 4}
|
||||
OrderedJson::object customData;
|
||||
};
|
||||
|
||||
typedef QVector<EncounterField> EncounterFields;
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public:
|
|||
|
||||
// Array and object typedefs
|
||||
typedef QVector<Json> array;
|
||||
typedef tsl::ordered_map<QString, Json> object;
|
||||
typedef OrderedMap<QString, Json> object;
|
||||
|
||||
// Constructors for the various types of JSON value.
|
||||
Json() noexcept; // NUL
|
||||
|
|
@ -132,7 +132,22 @@ public:
|
|||
int>::type = 0>
|
||||
Json(const V & v) : Json(array(v.begin(), v.end())) {}
|
||||
|
||||
static const Json fromQJsonValue(QJsonValue value);
|
||||
static Json fromQJsonValue(const QJsonValue &value);
|
||||
|
||||
static void append(Json::array *array, const QJsonArray &addendum) {
|
||||
for (const auto &i : addendum) array->push_back(fromQJsonValue(i));
|
||||
}
|
||||
static void append(Json::array *array, const Json::array &addendum) {
|
||||
for (const auto &i : addendum) array->push_back(i);
|
||||
}
|
||||
static void append(Json::object *object, const QJsonObject &addendum) {
|
||||
for (auto it = addendum.constBegin(); it != addendum.constEnd(); it++)
|
||||
(*object)[it.key()] = fromQJsonValue(it.value());
|
||||
}
|
||||
static void append(Json::object *object, const Json::object &addendum) {
|
||||
for (auto it = addendum.cbegin(); it != addendum.cend(); it++)
|
||||
(*object)[it.key()] = it.value();
|
||||
}
|
||||
|
||||
// This prevents Json(some_pointer) from accidentally producing a bool. Use
|
||||
// Json(bool(some_pointer)) if that behavior is desired.
|
||||
|
|
|
|||
|
|
@ -1977,6 +1977,14 @@ public:
|
|||
size_type erase(const K& key, std::size_t precalculated_hash) {
|
||||
return m_ht.erase(key, precalculated_hash);
|
||||
}
|
||||
|
||||
// Naive solution for take, should probably be replaced with one that does a single lookup and no unnecessary insertion.
|
||||
// We want to mirror the behavior of QMap::take, which returns a default-constructed value if the key is not present.
|
||||
T take(const key_type& key) {
|
||||
typename ValueSelect::value_type value = m_ht[key];
|
||||
m_ht.erase(key);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -2404,4 +2412,7 @@ private:
|
|||
|
||||
} // end namespace tsl
|
||||
|
||||
template<class Key, class T>
|
||||
using OrderedMap = tsl::ordered_map<Key, T>;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ public:
|
|||
QStringList mapSectionIdNames;
|
||||
QMap<uint32_t, QString> encounterTypeToName;
|
||||
QMap<uint32_t, QString> terrainTypeToName;
|
||||
QMap<QString, MapSectionEntry> regionMapEntries;
|
||||
QMap<QString, QMap<QString, uint16_t>> metatileLabelsMap;
|
||||
QMap<QString, uint16_t> unusedMetatileLabels;
|
||||
QMap<QString, uint32_t> metatileBehaviorMap;
|
||||
|
|
@ -72,7 +71,6 @@ public:
|
|||
QSet<QString> modifiedFiles;
|
||||
bool usingAsmTilesets;
|
||||
QSet<QString> disabledSettingsNames;
|
||||
QSet<QString> topLevelMapFields;
|
||||
int pokemonMinLevel;
|
||||
int pokemonMaxLevel;
|
||||
int maxEncounterRate;
|
||||
|
|
@ -144,12 +142,11 @@ public:
|
|||
QString getNewHealLocationName(const Map* map) const;
|
||||
|
||||
bool readWildMonData();
|
||||
tsl::ordered_map<QString, tsl::ordered_map<QString, WildPokemonHeader>> wildMonData;
|
||||
OrderedMap<QString, OrderedMap<QString, WildPokemonHeader>> wildMonData;
|
||||
|
||||
QString wildMonTableName;
|
||||
QVector<EncounterField> wildMonFields;
|
||||
QVector<QString> encounterGroupLabels;
|
||||
QVector<poryjson::Json::object> extraEncounterGroups;
|
||||
|
||||
bool readSpeciesIconPaths();
|
||||
QString getDefaultSpeciesIconPath(const QString &species);
|
||||
|
|
@ -157,15 +154,14 @@ public:
|
|||
|
||||
bool addNewMapsec(const QString &idName, const QString &displayName = QString());
|
||||
void removeMapsec(const QString &idName);
|
||||
QString getMapsecDisplayName(const QString &idName) const { return this->mapSectionDisplayNames.value(idName); }
|
||||
QString getMapsecDisplayName(const QString &idName) const { return this->locationData.value(idName).displayName; }
|
||||
void setMapsecDisplayName(const QString &idName, const QString &displayName);
|
||||
|
||||
bool hasUnsavedChanges();
|
||||
bool hasUnsavedDataChanges = false;
|
||||
|
||||
void initTopLevelMapFields();
|
||||
bool readMapJson(const QString &mapName, QJsonDocument * out);
|
||||
bool loadMapEvent(Map *map, const QJsonObject &json, Event::Type defaultType = Event::Type::None);
|
||||
bool loadMapEvent(Map *map, QJsonObject json, Event::Type defaultType = Event::Type::None);
|
||||
bool loadMapData(Map*);
|
||||
bool readMapLayouts();
|
||||
Layout *loadLayout(QString layoutId);
|
||||
|
|
@ -240,6 +236,11 @@ public:
|
|||
static QString getExistingFilepath(QString filepath);
|
||||
void applyParsedLimits();
|
||||
|
||||
void setRegionMapEntries(const QHash<QString, MapSectionEntry> &entries);
|
||||
QHash<QString, MapSectionEntry> getRegionMapEntries() const;
|
||||
|
||||
QSet<QString> getTopLevelMapFields() const;
|
||||
|
||||
static QString getEmptyMapDefineName();
|
||||
static QString getDynamicMapDefineName();
|
||||
static QString getDynamicMapName();
|
||||
|
|
@ -262,12 +263,20 @@ public:
|
|||
static QString getMapGroupPrefix();
|
||||
|
||||
private:
|
||||
QHash<QString, QString> mapSectionDisplayNames;
|
||||
QMap<QString, qint64> modifiedFileTimestamps;
|
||||
QMap<QString, QString> facingDirections;
|
||||
QHash<QString, QString> speciesToIconPath;
|
||||
QHash<QString, Map*> maps;
|
||||
|
||||
// Fields for preserving top-level JSON data that Porymap isn't expecting.
|
||||
QJsonObject customLayoutsData;
|
||||
QJsonObject customMapSectionsData;
|
||||
QJsonObject customMapGroupsData;
|
||||
QJsonObject customHealLocationsData;
|
||||
OrderedJson::object customWildMonData;
|
||||
OrderedJson::object customWildMonGroupData;
|
||||
OrderedJson::array extraEncounterGroups;
|
||||
|
||||
// Maps/layouts represented in these sets have been fully loaded from the project.
|
||||
// If a valid map name / layout id is not in these sets, a Map / Layout object exists
|
||||
// for it in Project::maps / Project::mapLayouts, but it has been minimally populated
|
||||
|
|
@ -291,6 +300,15 @@ private:
|
|||
};
|
||||
QMap<QString, EventGraphics*> eventGraphicsMap;
|
||||
|
||||
// The extra data that can be associated with each MAPSEC name.
|
||||
struct LocationData
|
||||
{
|
||||
MapSectionEntry map;
|
||||
QString displayName;
|
||||
QJsonObject custom;
|
||||
};
|
||||
QHash<QString, LocationData> locationData;
|
||||
|
||||
void updateLayout(Layout *);
|
||||
|
||||
void setNewLayoutBlockdata(Layout *layout);
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ public:
|
|||
explicit CustomAttributesTable(QWidget *parent = nullptr);
|
||||
~CustomAttributesTable() {};
|
||||
|
||||
QMap<QString, QJsonValue> getAttributes() const;
|
||||
void setAttributes(const QMap<QString, QJsonValue> &attributes);
|
||||
QJsonObject getAttributes() const;
|
||||
void setAttributes(const QJsonObject &attributes);
|
||||
|
||||
void addNewAttribute(const QString &key, const QJsonValue &value);
|
||||
bool deleteSelectedAttributes();
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ private:
|
|||
Project *project;
|
||||
|
||||
RegionMap *region_map = nullptr;
|
||||
tsl::ordered_map<QString, RegionMap *> region_maps;
|
||||
OrderedMap<QString, RegionMap *> region_maps;
|
||||
|
||||
QString configFilepath;
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ private:
|
|||
void saveConfig();
|
||||
bool loadRegionMapEntries();
|
||||
bool saveRegionMapEntries();
|
||||
QMap<QString, MapSectionEntry> region_map_entries;
|
||||
QHash<QString, MapSectionEntry> region_map_entries;
|
||||
|
||||
bool buildConfigDialog();
|
||||
poryjson::Json configRegionMapDialog();
|
||||
|
|
|
|||
|
|
@ -809,6 +809,8 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->tilesetsHaveIsCompressed = getConfigBool(key, value);
|
||||
} else if (key == "set_transparent_pixels_black") {
|
||||
this->setTransparentPixelsBlack = getConfigBool(key, value);
|
||||
} else if (key == "preserve_matching_only_data") {
|
||||
this->preserveMatchingOnlyData = getConfigBool(key, value);
|
||||
} else if (key == "event_icon_path_object") {
|
||||
this->eventIconPaths[Event::Group::Object] = value;
|
||||
} else if (key == "event_icon_path_warp") {
|
||||
|
|
@ -899,6 +901,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
map.insert("tilesets_have_callback", QString::number(this->tilesetsHaveCallback));
|
||||
map.insert("tilesets_have_is_compressed", QString::number(this->tilesetsHaveIsCompressed));
|
||||
map.insert("set_transparent_pixels_black", QString::number(this->setTransparentPixelsBlack));
|
||||
map.insert("preserve_matching_only_data", QString::number(this->preserveMatchingOnlyData));
|
||||
map.insert("metatile_attributes_size", QString::number(this->metatileAttributesSize));
|
||||
map.insert("metatile_behavior_mask", Util::toHexString(this->metatileBehaviorMask));
|
||||
map.insert("metatile_terrain_type_mask", Util::toHexString(this->metatileTerrainTypeMask));
|
||||
|
|
|
|||
|
|
@ -51,24 +51,6 @@ void Event::setDefaultValues(Project *) {
|
|||
this->setElevation(projectConfig.defaultElevation);
|
||||
}
|
||||
|
||||
void Event::readCustomAttributes(const QJsonObject &json) {
|
||||
this->customAttributes.clear();
|
||||
const QSet<QString> expectedFields = this->getExpectedFields();
|
||||
for (auto i = json.constBegin(); i != json.constEnd(); i++) {
|
||||
if (!expectedFields.contains(i.key())) {
|
||||
this->customAttributes[i.key()] = i.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Event::addCustomAttributesTo(OrderedJson::object *obj) const {
|
||||
for (auto i = this->customAttributes.constBegin(); i != this->customAttributes.constEnd(); i++) {
|
||||
if (!obj->contains(i.key())) {
|
||||
(*obj)[i.key()] = OrderedJson::fromQJsonValue(i.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Event::modify() {
|
||||
this->map->modify();
|
||||
}
|
||||
|
|
@ -187,27 +169,26 @@ OrderedJson::object ObjectEvent::buildEventJson(Project *) {
|
|||
objectJson["trainer_sight_or_berry_tree_id"] = this->getSightRadiusBerryTreeID();
|
||||
objectJson["script"] = this->getScript();
|
||||
objectJson["flag"] = this->getFlag();
|
||||
this->addCustomAttributesTo(&objectJson);
|
||||
|
||||
OrderedJson::append(&objectJson, this->getCustomAttributes());
|
||||
return objectJson;
|
||||
}
|
||||
|
||||
bool ObjectEvent::loadFromJson(const QJsonObject &json, Project *) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setIdName(ParseUtil::jsonToQString(json["local_id"]));
|
||||
this->setGfx(ParseUtil::jsonToQString(json["graphics_id"]));
|
||||
this->setMovement(ParseUtil::jsonToQString(json["movement_type"]));
|
||||
this->setRadiusX(ParseUtil::jsonToInt(json["movement_range_x"]));
|
||||
this->setRadiusY(ParseUtil::jsonToInt(json["movement_range_y"]));
|
||||
this->setTrainerType(ParseUtil::jsonToQString(json["trainer_type"]));
|
||||
this->setSightRadiusBerryTreeID(ParseUtil::jsonToQString(json["trainer_sight_or_berry_tree_id"]));
|
||||
this->setScript(ParseUtil::jsonToQString(json["script"]));
|
||||
this->setFlag(ParseUtil::jsonToQString(json["flag"]));
|
||||
bool ObjectEvent::loadFromJson(QJsonObject json, Project *) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setIdName(readString(&json, "local_id"));
|
||||
this->setGfx(readString(&json, "graphics_id"));
|
||||
this->setMovement(readString(&json, "movement_type"));
|
||||
this->setRadiusX(readInt(&json, "movement_range_x"));
|
||||
this->setRadiusY(readInt(&json, "movement_range_y"));
|
||||
this->setTrainerType(readString(&json, "trainer_type"));
|
||||
this->setSightRadiusBerryTreeID(readString(&json, "trainer_sight_or_berry_tree_id"));
|
||||
this->setScript(readString(&json, "script"));
|
||||
this->setFlag(readString(&json, "flag"));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -222,26 +203,24 @@ void ObjectEvent::setDefaultValues(Project *project) {
|
|||
this->setSightRadiusBerryTreeID("0");
|
||||
}
|
||||
|
||||
const QSet<QString> expectedObjectFields = {
|
||||
"local_id",
|
||||
"graphics_id",
|
||||
"elevation",
|
||||
"movement_type",
|
||||
"movement_range_x",
|
||||
"movement_range_y",
|
||||
"trainer_type",
|
||||
"trainer_sight_or_berry_tree_id",
|
||||
"script",
|
||||
"flag",
|
||||
};
|
||||
|
||||
QSet<QString> ObjectEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedObjectFields;
|
||||
QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"local_id",
|
||||
"graphics_id",
|
||||
"elevation",
|
||||
"movement_type",
|
||||
"movement_range_x",
|
||||
"movement_range_y",
|
||||
"trainer_type",
|
||||
"trainer_sight_or_berry_tree_id",
|
||||
"script",
|
||||
"flag",
|
||||
};
|
||||
if (projectConfig.eventCloneObjectEnabled) {
|
||||
expectedFields.insert("type");
|
||||
}
|
||||
expectedFields << "x" << "y";
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -292,26 +271,25 @@ OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) {
|
|||
cloneJson["target_local_id"] = this->getTargetID();
|
||||
const QString mapName = this->getTargetMap();
|
||||
cloneJson["target_map"] = project->getMapConstant(mapName, mapName);
|
||||
this->addCustomAttributesTo(&cloneJson);
|
||||
|
||||
OrderedJson::append(&cloneJson, this->getCustomAttributes());
|
||||
return cloneJson;
|
||||
}
|
||||
|
||||
bool CloneObjectEvent::loadFromJson(const QJsonObject &json, Project *project) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setIdName(ParseUtil::jsonToQString(json["local_id"]));
|
||||
this->setGfx(ParseUtil::jsonToQString(json["graphics_id"]));
|
||||
this->setTargetID(ParseUtil::jsonToInt(json["target_local_id"]));
|
||||
bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setIdName(readString(&json, "local_id"));
|
||||
this->setGfx(readString(&json, "graphics_id"));
|
||||
this->setTargetID(readInt(&json, "target_local_id"));
|
||||
|
||||
// Log a warning if "target_map" isn't a known map ID, but don't overwrite user data.
|
||||
const QString mapConstant = ParseUtil::jsonToQString(json["target_map"]);
|
||||
const QString mapConstant = readString(&json, "target_map");
|
||||
if (!project->mapConstantsToMapNames.contains(mapConstant))
|
||||
logWarn(QString("Unknown Target Map constant '%1'.").arg(mapConstant));
|
||||
this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant, mapConstant));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -321,18 +299,16 @@ void CloneObjectEvent::setDefaultValues(Project *project) {
|
|||
if (this->getMap()) this->setTargetMap(this->getMap()->name());
|
||||
}
|
||||
|
||||
const QSet<QString> expectedCloneObjectFields = {
|
||||
"type",
|
||||
"local_id",
|
||||
"graphics_id",
|
||||
"target_local_id",
|
||||
"target_map",
|
||||
};
|
||||
|
||||
QSet<QString> CloneObjectEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedCloneObjectFields;
|
||||
expectedFields << "x" << "y";
|
||||
static const QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"type",
|
||||
"local_id",
|
||||
"graphics_id",
|
||||
"target_local_id",
|
||||
"target_map",
|
||||
};
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -389,25 +365,23 @@ OrderedJson::object WarpEvent::buildEventJson(Project *project) {
|
|||
warpJson["dest_map"] = project->getMapConstant(mapName, mapName);
|
||||
warpJson["dest_warp_id"] = this->getDestinationWarpID();
|
||||
|
||||
this->addCustomAttributesTo(&warpJson);
|
||||
|
||||
OrderedJson::append(&warpJson, this->getCustomAttributes());
|
||||
return warpJson;
|
||||
}
|
||||
|
||||
bool WarpEvent::loadFromJson(const QJsonObject &json, Project *project) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setDestinationWarpID(ParseUtil::jsonToQString(json["dest_warp_id"]));
|
||||
bool WarpEvent::loadFromJson(QJsonObject json, Project *project) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setDestinationWarpID(readString(&json, "dest_warp_id"));
|
||||
|
||||
// Log a warning if "dest_map" isn't a known map ID, but don't overwrite user data.
|
||||
const QString mapConstant = ParseUtil::jsonToQString(json["dest_map"]);
|
||||
const QString mapConstant = readString(&json, "dest_map");
|
||||
if (!project->mapConstantsToMapNames.contains(mapConstant))
|
||||
logWarn(QString("Unknown Destination Map constant '%1'.").arg(mapConstant));
|
||||
this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant, mapConstant));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -417,16 +391,14 @@ void WarpEvent::setDefaultValues(Project *) {
|
|||
this->setElevation(0);
|
||||
}
|
||||
|
||||
const QSet<QString> expectedWarpFields = {
|
||||
"elevation",
|
||||
"dest_map",
|
||||
"dest_warp_id",
|
||||
};
|
||||
|
||||
QSet<QString> WarpEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedWarpFields;
|
||||
expectedFields << "x" << "y";
|
||||
static const QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"elevation",
|
||||
"dest_map",
|
||||
"dest_warp_id",
|
||||
};
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -476,21 +448,19 @@ OrderedJson::object TriggerEvent::buildEventJson(Project *) {
|
|||
triggerJson["var_value"] = this->getScriptVarValue();
|
||||
triggerJson["script"] = this->getScriptLabel();
|
||||
|
||||
this->addCustomAttributesTo(&triggerJson);
|
||||
|
||||
OrderedJson::append(&triggerJson, this->getCustomAttributes());
|
||||
return triggerJson;
|
||||
}
|
||||
|
||||
bool TriggerEvent::loadFromJson(const QJsonObject &json, Project *) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setScriptVar(ParseUtil::jsonToQString(json["var"]));
|
||||
this->setScriptVarValue(ParseUtil::jsonToQString(json["var_value"]));
|
||||
this->setScriptLabel(ParseUtil::jsonToQString(json["script"]));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
bool TriggerEvent::loadFromJson(QJsonObject json, Project *) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setScriptVar(readString(&json, "var"));
|
||||
this->setScriptVarValue(readString(&json, "var_value"));
|
||||
this->setScriptLabel(readString(&json, "script"));
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -501,18 +471,16 @@ void TriggerEvent::setDefaultValues(Project *project) {
|
|||
this->setElevation(0);
|
||||
}
|
||||
|
||||
const QSet<QString> expectedTriggerFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"var",
|
||||
"var_value",
|
||||
"script",
|
||||
};
|
||||
|
||||
QSet<QString> TriggerEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedTriggerFields;
|
||||
expectedFields << "x" << "y";
|
||||
static const QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"type",
|
||||
"elevation",
|
||||
"var",
|
||||
"var_value",
|
||||
"script",
|
||||
};
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -548,19 +516,17 @@ OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) {
|
|||
weatherJson["elevation"] = this->getElevation();
|
||||
weatherJson["weather"] = this->getWeather();
|
||||
|
||||
this->addCustomAttributesTo(&weatherJson);
|
||||
|
||||
OrderedJson::append(&weatherJson, this->getCustomAttributes());
|
||||
return weatherJson;
|
||||
}
|
||||
|
||||
bool WeatherTriggerEvent::loadFromJson(const QJsonObject &json, Project *) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setWeather(ParseUtil::jsonToQString(json["weather"]));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setWeather(readString(&json, "weather"));
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -569,16 +535,14 @@ void WeatherTriggerEvent::setDefaultValues(Project *project) {
|
|||
this->setElevation(0);
|
||||
}
|
||||
|
||||
const QSet<QString> expectedWeatherTriggerFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"weather",
|
||||
};
|
||||
|
||||
QSet<QString> WeatherTriggerEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedWeatherTriggerFields;
|
||||
expectedFields << "x" << "y";
|
||||
static const QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"type",
|
||||
"elevation",
|
||||
"weather",
|
||||
};
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -616,20 +580,18 @@ OrderedJson::object SignEvent::buildEventJson(Project *) {
|
|||
signJson["player_facing_dir"] = this->getFacingDirection();
|
||||
signJson["script"] = this->getScriptLabel();
|
||||
|
||||
this->addCustomAttributesTo(&signJson);
|
||||
|
||||
OrderedJson::append(&signJson, this->getCustomAttributes());
|
||||
return signJson;
|
||||
}
|
||||
|
||||
bool SignEvent::loadFromJson(const QJsonObject &json, Project *) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setFacingDirection(ParseUtil::jsonToQString(json["player_facing_dir"]));
|
||||
this->setScriptLabel(ParseUtil::jsonToQString(json["script"]));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
bool SignEvent::loadFromJson(QJsonObject json, Project *) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setFacingDirection(readString(&json, "player_facing_dir"));
|
||||
this->setScriptLabel(readString(&json, "script"));
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -639,17 +601,15 @@ void SignEvent::setDefaultValues(Project *project) {
|
|||
this->setElevation(0);
|
||||
}
|
||||
|
||||
const QSet<QString> expectedSignFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"player_facing_dir",
|
||||
"script",
|
||||
};
|
||||
|
||||
QSet<QString> SignEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedSignFields;
|
||||
expectedFields << "x" << "y";
|
||||
static const QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"type",
|
||||
"elevation",
|
||||
"player_facing_dir",
|
||||
"script",
|
||||
};
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -695,26 +655,24 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) {
|
|||
hiddenItemJson["underfoot"] = this->getUnderfoot();
|
||||
}
|
||||
|
||||
this->addCustomAttributesTo(&hiddenItemJson);
|
||||
|
||||
OrderedJson::append(&hiddenItemJson, this->getCustomAttributes());
|
||||
return hiddenItemJson;
|
||||
}
|
||||
|
||||
bool HiddenItemEvent::loadFromJson(const QJsonObject &json, Project *) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setItem(ParseUtil::jsonToQString(json["item"]));
|
||||
this->setFlag(ParseUtil::jsonToQString(json["flag"]));
|
||||
bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setItem(readString(&json, "item"));
|
||||
this->setFlag(readString(&json, "flag"));
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
this->setQuantity(ParseUtil::jsonToInt(json["quantity"]));
|
||||
this->setQuantity(readInt(&json, "quantity"));
|
||||
}
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"]));
|
||||
this->setUnderfoot(readBool(&json, "underfoot"));
|
||||
}
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -729,23 +687,21 @@ void HiddenItemEvent::setDefaultValues(Project *project) {
|
|||
}
|
||||
}
|
||||
|
||||
const QSet<QString> expectedHiddenItemFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"item",
|
||||
"flag",
|
||||
};
|
||||
|
||||
QSet<QString> HiddenItemEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedHiddenItemFields;
|
||||
QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"type",
|
||||
"elevation",
|
||||
"item",
|
||||
"flag",
|
||||
};
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
expectedFields << "quantity";
|
||||
}
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
expectedFields << "underfoot";
|
||||
}
|
||||
expectedFields << "x" << "y";
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -781,19 +737,17 @@ OrderedJson::object SecretBaseEvent::buildEventJson(Project *) {
|
|||
secretBaseJson["elevation"] = this->getElevation();
|
||||
secretBaseJson["secret_base_id"] = this->getBaseID();
|
||||
|
||||
this->addCustomAttributesTo(&secretBaseJson);
|
||||
|
||||
OrderedJson::append(&secretBaseJson, this->getCustomAttributes());
|
||||
return secretBaseJson;
|
||||
}
|
||||
|
||||
bool SecretBaseEvent::loadFromJson(const QJsonObject &json, Project *) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setBaseID(ParseUtil::jsonToQString(json["secret_base_id"]));
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setElevation(readInt(&json, "elevation"));
|
||||
this->setBaseID(readString(&json, "secret_base_id"));
|
||||
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -802,16 +756,14 @@ void SecretBaseEvent::setDefaultValues(Project *project) {
|
|||
this->setElevation(0);
|
||||
}
|
||||
|
||||
const QSet<QString> expectedSecretBaseFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"secret_base_id",
|
||||
};
|
||||
|
||||
QSet<QString> SecretBaseEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedSecretBaseFields;
|
||||
expectedFields << "x" << "y";
|
||||
static const QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"type",
|
||||
"elevation",
|
||||
"secret_base_id",
|
||||
};
|
||||
return expectedFields;
|
||||
}
|
||||
|
||||
|
|
@ -839,12 +791,15 @@ EventFrame *HealLocationEvent::createEventFrame() {
|
|||
return this->eventFrame;
|
||||
}
|
||||
|
||||
QString HealLocationEvent::getHostMapName() const {
|
||||
return this->getMap() ? this->getMap()->constantName() : this->hostMapName;
|
||||
}
|
||||
|
||||
OrderedJson::object HealLocationEvent::buildEventJson(Project *project) {
|
||||
OrderedJson::object healLocationJson;
|
||||
|
||||
healLocationJson["id"] = this->getIdName();
|
||||
// This field doesn't need to be stored in the Event itself, so it's output only.
|
||||
healLocationJson["map"] = this->getMap() ? this->getMap()->constantName() : QString();
|
||||
healLocationJson["map"] = this->getHostMapName();
|
||||
healLocationJson["x"] = this->getX();
|
||||
healLocationJson["y"] = this->getY();
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
|
|
@ -853,26 +808,26 @@ OrderedJson::object HealLocationEvent::buildEventJson(Project *project) {
|
|||
healLocationJson["respawn_npc"] = this->getRespawnNPC();
|
||||
}
|
||||
|
||||
this->addCustomAttributesTo(&healLocationJson);
|
||||
|
||||
OrderedJson::append(&healLocationJson, this->getCustomAttributes());
|
||||
return healLocationJson;
|
||||
}
|
||||
|
||||
bool HealLocationEvent::loadFromJson(const QJsonObject &json, Project *project) {
|
||||
this->setX(ParseUtil::jsonToInt(json["x"]));
|
||||
this->setY(ParseUtil::jsonToInt(json["y"]));
|
||||
this->setIdName(ParseUtil::jsonToQString(json["id"]));
|
||||
bool HealLocationEvent::loadFromJson(QJsonObject json, Project *project) {
|
||||
this->setX(readInt(&json, "x"));
|
||||
this->setY(readInt(&json, "y"));
|
||||
this->setIdName(readString(&json, "id"));
|
||||
this->setHostMapName(readString(&json, "map"));
|
||||
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
// Log a warning if "respawn_map" isn't a known map ID, but don't overwrite user data.
|
||||
const QString mapConstant = ParseUtil::jsonToQString(json["respawn_map"]);
|
||||
const QString mapConstant = readString(&json, "respawn_map");
|
||||
if (!project->mapConstantsToMapNames.contains(mapConstant))
|
||||
logWarn(QString("Unknown Respawn Map constant '%1'.").arg(mapConstant));
|
||||
this->setRespawnMapName(project->mapConstantsToMapNames.value(mapConstant, mapConstant));
|
||||
this->setRespawnNPC(ParseUtil::jsonToQString(json["respawn_npc"]));
|
||||
this->setRespawnNPC(readString(&json, "respawn_npc"));
|
||||
}
|
||||
|
||||
this->readCustomAttributes(json);
|
||||
this->setCustomAttributes(json);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -885,16 +840,19 @@ void HealLocationEvent::setDefaultValues(Project *project) {
|
|||
}
|
||||
|
||||
const QSet<QString> expectedHealLocationFields = {
|
||||
"id",
|
||||
"map"
|
||||
|
||||
};
|
||||
|
||||
QSet<QString> HealLocationEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = expectedHealLocationFields;
|
||||
QSet<QString> expectedFields = {
|
||||
"x",
|
||||
"y",
|
||||
"id",
|
||||
"map",
|
||||
};
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
expectedFields.insert("respawn_map");
|
||||
expectedFields.insert("respawn_npc");
|
||||
}
|
||||
expectedFields << "x" << "y";
|
||||
return expectedFields;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ void Layout::copyFrom(const Layout *other) {
|
|||
this->tileset_secondary = other->tileset_secondary;
|
||||
this->blockdata = other->blockdata;
|
||||
this->border = other->border;
|
||||
this->customData = other->customData;
|
||||
}
|
||||
|
||||
QString Layout::layoutConstantFromName(const QString &name) {
|
||||
|
|
|
|||
|
|
@ -610,12 +610,12 @@ bool ParseUtil::gameStringToBool(const QString &gameString, bool * ok) {
|
|||
return gameStringToInt(gameString, ok) != 0;
|
||||
}
|
||||
|
||||
tsl::ordered_map<QString, QHash<QString, QString>> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash<int, QString> &memberMap) {
|
||||
OrderedMap<QString, QHash<QString, QString>> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash<int, QString> &memberMap) {
|
||||
QString filePath = pathWithRoot(filename);
|
||||
auto cParser = fex::Parser();
|
||||
auto tokens = fex::Lexer().LexFile(filePath);
|
||||
auto topLevelObjects = cParser.ParseTopLevelObjects(tokens);
|
||||
tsl::ordered_map<QString, QHash<QString, QString>> structs;
|
||||
OrderedMap<QString, QHash<QString, QString>> structs;
|
||||
for (auto it = topLevelObjects.begin(); it != topLevelObjects.end(); it++) {
|
||||
QString structLabel = QString::fromStdString(it->first);
|
||||
if (structLabel.isEmpty()) continue;
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ void ResizeTilemap::undo() {
|
|||
|
||||
///
|
||||
|
||||
ClearEntries::ClearEntries(RegionMap *map, QMap<QString, MapSectionEntry> entries, QUndoCommand *parent)
|
||||
ClearEntries::ClearEntries(RegionMap *map, QHash<QString, MapSectionEntry> entries, QUndoCommand *parent)
|
||||
: QUndoCommand(parent) {
|
||||
setText("Clear Entries");
|
||||
|
||||
|
|
|
|||
|
|
@ -596,7 +596,7 @@ void Editor::configureEncounterJSON(QWidget *window) {
|
|||
if (newNameDialog.exec() == QDialog::Accepted) {
|
||||
QString newFieldName = newNameEdit->text();
|
||||
QVector<int> newFieldRates(1, 100);
|
||||
tempFields.append({newFieldName, newFieldRates, {}});
|
||||
tempFields.append({newFieldName, newFieldRates, {}, {}});
|
||||
fieldChoices->addItem(newFieldName);
|
||||
fieldChoices->setCurrentIndex(fieldChoices->count() - 1);
|
||||
}
|
||||
|
|
@ -675,7 +675,7 @@ void Editor::saveEncounterTabData() {
|
|||
|
||||
if (!stack->count()) return;
|
||||
|
||||
tsl::ordered_map<QString, WildPokemonHeader> &encounterMap = project->wildMonData[map->constantName()];
|
||||
OrderedMap<QString, WildPokemonHeader> &encounterMap = project->wildMonData[map->constantName()];
|
||||
|
||||
for (int groupIndex = 0; groupIndex < stack->count(); groupIndex++) {
|
||||
MonTabWidget *tabWidget = static_cast<MonTabWidget *>(stack->widget(groupIndex));
|
||||
|
|
|
|||
|
|
@ -311,33 +311,26 @@ const Json & JsonArray::operator[] (int i) const {
|
|||
else return m_value[i];
|
||||
}
|
||||
|
||||
const Json Json::fromQJsonValue(QJsonValue value) {
|
||||
Json Json::fromQJsonValue(const QJsonValue &value) {
|
||||
switch (value.type())
|
||||
{
|
||||
case QJsonValue::String: return value.toString();
|
||||
case QJsonValue::Double: return value.toInt();
|
||||
case QJsonValue::Bool: return value.toBool();
|
||||
case QJsonValue::Array:
|
||||
{
|
||||
QJsonArray qArr = value.toArray();
|
||||
Json::array arr;
|
||||
for (const auto &i: qArr)
|
||||
arr.push_back(Json::fromQJsonValue(i));
|
||||
return arr;
|
||||
case QJsonValue::Array: {
|
||||
Json::array array;
|
||||
Json::append(&array, value.toArray());
|
||||
return array;
|
||||
}
|
||||
case QJsonValue::Object:
|
||||
{
|
||||
QJsonObject qObj = value.toObject();
|
||||
Json::object obj;
|
||||
for (auto it = qObj.constBegin(); it != qObj.constEnd(); it++)
|
||||
obj[it.key()] = Json::fromQJsonValue(it.value());
|
||||
return obj;
|
||||
case QJsonValue::Object: {
|
||||
Json::object object;
|
||||
Json::append(&object, value.toObject());
|
||||
return object;
|
||||
}
|
||||
default: return static_null();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Comparison
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1200,7 +1200,7 @@ bool MainWindow::setProjectUI() {
|
|||
ui->layoutList->setModel(layoutListProxyModel);
|
||||
ui->layoutList->sortByColumn(0, Qt::SortOrder::AscendingOrder);
|
||||
|
||||
ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->topLevelMapFields);
|
||||
ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->getTopLevelMapFields());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
293
src/project.cpp
293
src/project.cpp
|
|
@ -177,8 +177,8 @@ Map* Project::loadMap(const QString &mapName) {
|
|||
return map;
|
||||
}
|
||||
|
||||
void Project::initTopLevelMapFields() {
|
||||
static const QSet<QString> defaultTopLevelMapFields = {
|
||||
QSet<QString> Project::getTopLevelMapFields() const {
|
||||
QSet<QString> fields = {
|
||||
"id",
|
||||
"name",
|
||||
"layout",
|
||||
|
|
@ -197,15 +197,15 @@ void Project::initTopLevelMapFields() {
|
|||
"shared_events_map",
|
||||
"shared_scripts_map",
|
||||
};
|
||||
this->topLevelMapFields = defaultTopLevelMapFields;
|
||||
if (projectConfig.mapAllowFlagsEnabled) {
|
||||
this->topLevelMapFields.insert("allow_cycling");
|
||||
this->topLevelMapFields.insert("allow_escaping");
|
||||
this->topLevelMapFields.insert("allow_running");
|
||||
fields.insert("allow_cycling");
|
||||
fields.insert("allow_escaping");
|
||||
fields.insert("allow_running");
|
||||
}
|
||||
if (projectConfig.floorNumberEnabled) {
|
||||
this->topLevelMapFields.insert("floor_number");
|
||||
fields.insert("floor_number");
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
bool Project::readMapJson(const QString &mapName, QJsonDocument * out) {
|
||||
|
|
@ -218,8 +218,8 @@ bool Project::readMapJson(const QString &mapName, QJsonDocument * out) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Project::loadMapEvent(Map *map, const QJsonObject &json, Event::Type defaultType) {
|
||||
QString typeString = ParseUtil::jsonToQString(json["type"]);
|
||||
bool Project::loadMapEvent(Map *map, QJsonObject json, Event::Type defaultType) {
|
||||
QString typeString = ParseUtil::jsonToQString(json.take("type"));
|
||||
Event::Type type = typeString.isEmpty() ? defaultType : Event::typeFromJsonKey(typeString);
|
||||
Event* event = Event::create(type);
|
||||
if (!event) {
|
||||
|
|
@ -245,10 +245,10 @@ bool Project::loadMapData(Map* map) {
|
|||
QJsonObject mapObj = mapDoc.object();
|
||||
|
||||
// We should already know the map constant ID from the initial project launch, but we'll ensure it's correct here anyway.
|
||||
map->setConstantName(ParseUtil::jsonToQString(mapObj["id"]));
|
||||
map->setConstantName(ParseUtil::jsonToQString(mapObj.take("id")));
|
||||
this->mapConstantsToMapNames.insert(map->constantName(), map->name());
|
||||
|
||||
const QString layoutId = ParseUtil::jsonToQString(mapObj["layout"]);
|
||||
const QString layoutId = ParseUtil::jsonToQString(mapObj.take("layout"));
|
||||
Layout* layout = this->mapLayouts.value(layoutId);
|
||||
if (!layout) {
|
||||
// We've already verified layout IDs on project launch and ignored maps with invalid IDs, so this shouldn't happen.
|
||||
|
|
@ -257,24 +257,24 @@ bool Project::loadMapData(Map* map) {
|
|||
}
|
||||
map->setLayout(layout);
|
||||
|
||||
map->header()->setSong(ParseUtil::jsonToQString(mapObj["music"]));
|
||||
map->header()->setLocation(ParseUtil::jsonToQString(mapObj["region_map_section"]));
|
||||
map->header()->setRequiresFlash(ParseUtil::jsonToBool(mapObj["requires_flash"]));
|
||||
map->header()->setWeather(ParseUtil::jsonToQString(mapObj["weather"]));
|
||||
map->header()->setType(ParseUtil::jsonToQString(mapObj["map_type"]));
|
||||
map->header()->setShowsLocationName(ParseUtil::jsonToBool(mapObj["show_map_name"]));
|
||||
map->header()->setBattleScene(ParseUtil::jsonToQString(mapObj["battle_scene"]));
|
||||
map->header()->setSong(ParseUtil::jsonToQString(mapObj.take("music")));
|
||||
map->header()->setLocation(ParseUtil::jsonToQString(mapObj.take("region_map_section")));
|
||||
map->header()->setRequiresFlash(ParseUtil::jsonToBool(mapObj.take("requires_flash")));
|
||||
map->header()->setWeather(ParseUtil::jsonToQString(mapObj.take("weather")));
|
||||
map->header()->setType(ParseUtil::jsonToQString(mapObj.take("map_type")));
|
||||
map->header()->setShowsLocationName(ParseUtil::jsonToBool(mapObj.take("show_map_name")));
|
||||
map->header()->setBattleScene(ParseUtil::jsonToQString(mapObj.take("battle_scene")));
|
||||
|
||||
if (projectConfig.mapAllowFlagsEnabled) {
|
||||
map->header()->setAllowsBiking(ParseUtil::jsonToBool(mapObj["allow_cycling"]));
|
||||
map->header()->setAllowsEscaping(ParseUtil::jsonToBool(mapObj["allow_escaping"]));
|
||||
map->header()->setAllowsRunning(ParseUtil::jsonToBool(mapObj["allow_running"]));
|
||||
map->header()->setAllowsBiking(ParseUtil::jsonToBool(mapObj.take("allow_cycling")));
|
||||
map->header()->setAllowsEscaping(ParseUtil::jsonToBool(mapObj.take("allow_escaping")));
|
||||
map->header()->setAllowsRunning(ParseUtil::jsonToBool(mapObj.take("allow_running")));
|
||||
}
|
||||
if (projectConfig.floorNumberEnabled) {
|
||||
map->header()->setFloorNumber(ParseUtil::jsonToInt(mapObj["floor_number"]));
|
||||
map->header()->setFloorNumber(ParseUtil::jsonToInt(mapObj.take("floor_number")));
|
||||
}
|
||||
map->setSharedEventsMap(ParseUtil::jsonToQString(mapObj["shared_events_map"]));
|
||||
map->setSharedScriptsMap(ParseUtil::jsonToQString(mapObj["shared_scripts_map"]));
|
||||
map->setSharedEventsMap(ParseUtil::jsonToQString(mapObj.take("shared_events_map")));
|
||||
map->setSharedScriptsMap(ParseUtil::jsonToQString(mapObj.take("shared_scripts_map")));
|
||||
|
||||
// Events
|
||||
map->resetEvents();
|
||||
|
|
@ -289,7 +289,7 @@ bool Project::loadMapData(Map* map) {
|
|||
for (auto i = defaultEventTypes.constBegin(); i != defaultEventTypes.constEnd(); i++) {
|
||||
QString eventGroupKey = i.key();
|
||||
Event::Type defaultType = i.value();
|
||||
const QJsonArray eventsJsonArr = mapObj[eventGroupKey].toArray();
|
||||
const QJsonArray eventsJsonArr = mapObj.take(eventGroupKey).toArray();
|
||||
for (int i = 0; i < eventsJsonArr.size(); i++) {
|
||||
if (!loadMapEvent(map, eventsJsonArr.at(i).toObject(), defaultType)) {
|
||||
logError(QString("Failed to load event for %1, in %2 at index %3.").arg(map->name()).arg(eventGroupKey).arg(i));
|
||||
|
|
@ -304,24 +304,19 @@ bool Project::loadMapData(Map* map) {
|
|||
}
|
||||
|
||||
map->deleteConnections();
|
||||
QJsonArray connectionsArr = mapObj["connections"].toArray();
|
||||
QJsonArray connectionsArr = mapObj.take("connections").toArray();
|
||||
if (!connectionsArr.isEmpty()) {
|
||||
for (int i = 0; i < connectionsArr.size(); i++) {
|
||||
QJsonObject connectionObj = connectionsArr[i].toObject();
|
||||
const QString direction = ParseUtil::jsonToQString(connectionObj["direction"]);
|
||||
const int offset = ParseUtil::jsonToInt(connectionObj["offset"]);
|
||||
const QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]);
|
||||
map->loadConnection(new MapConnection(this->mapConstantsToMapNames.value(mapConstant, mapConstant), direction, offset));
|
||||
const QString direction = ParseUtil::jsonToQString(connectionObj.take("direction"));
|
||||
const int offset = ParseUtil::jsonToInt(connectionObj.take("offset"));
|
||||
const QString mapConstant = ParseUtil::jsonToQString(connectionObj.take("map"));
|
||||
auto connection = new MapConnection(this->mapConstantsToMapNames.value(mapConstant, mapConstant), direction, offset);
|
||||
connection->setCustomData(connectionObj);
|
||||
map->loadConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, QJsonValue> customAttributes;
|
||||
for (auto i = mapObj.constBegin(); i != mapObj.constEnd(); i++) {
|
||||
if (!this->topLevelMapFields.contains(i.key())) {
|
||||
customAttributes.insert(i.key(), i.value());
|
||||
}
|
||||
}
|
||||
map->setCustomAttributes(customAttributes);
|
||||
map->setCustomAttributes(mapObj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -473,6 +468,7 @@ void Project::clearMapLayouts() {
|
|||
this->layoutIds.clear();
|
||||
this->layoutIdsMaster.clear();
|
||||
this->loadedLayoutIds.clear();
|
||||
this->customLayoutsData = QJsonObject();
|
||||
}
|
||||
|
||||
bool Project::readMapLayouts() {
|
||||
|
|
@ -489,7 +485,7 @@ bool Project::readMapLayouts() {
|
|||
|
||||
QJsonObject layoutsObj = layoutsDoc.object();
|
||||
|
||||
this->layoutsLabel = ParseUtil::jsonToQString(layoutsObj["layouts_table_label"]);
|
||||
this->layoutsLabel = ParseUtil::jsonToQString(layoutsObj.take("layouts_table_label"));
|
||||
if (this->layoutsLabel.isEmpty()) {
|
||||
this->layoutsLabel = "gMapLayouts";
|
||||
logWarn(QString("'layouts_table_label' value is missing from %1. Defaulting to %2")
|
||||
|
|
@ -497,13 +493,13 @@ bool Project::readMapLayouts() {
|
|||
.arg(layoutsLabel));
|
||||
}
|
||||
|
||||
QJsonArray layouts = layoutsObj["layouts"].toArray();
|
||||
QJsonArray layouts = layoutsObj.take("layouts").toArray();
|
||||
for (int i = 0; i < layouts.size(); i++) {
|
||||
QJsonObject layoutObj = layouts[i].toObject();
|
||||
if (layoutObj.isEmpty())
|
||||
continue;
|
||||
Layout *layout = new Layout();
|
||||
layout->id = ParseUtil::jsonToQString(layoutObj["id"]);
|
||||
layout->id = ParseUtil::jsonToQString(layoutObj.take("id"));
|
||||
if (layout->id.isEmpty()) {
|
||||
logError(QString("Missing 'id' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
|
|
@ -514,20 +510,20 @@ bool Project::readMapLayouts() {
|
|||
delete layout;
|
||||
continue;
|
||||
}
|
||||
layout->name = ParseUtil::jsonToQString(layoutObj["name"]);
|
||||
layout->name = ParseUtil::jsonToQString(layoutObj.take("name"));
|
||||
if (layout->name.isEmpty()) {
|
||||
logError(QString("Missing 'name' value for %1 in %2").arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
return false;
|
||||
}
|
||||
int lwidth = ParseUtil::jsonToInt(layoutObj["width"]);
|
||||
int lwidth = ParseUtil::jsonToInt(layoutObj.take("width"));
|
||||
if (lwidth <= 0) {
|
||||
logError(QString("Invalid 'width' value '%1' for %2 in %3. Must be greater than 0.").arg(lwidth).arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
return false;
|
||||
}
|
||||
layout->width = lwidth;
|
||||
int lheight = ParseUtil::jsonToInt(layoutObj["height"]);
|
||||
int lheight = ParseUtil::jsonToInt(layoutObj.take("height"));
|
||||
if (lheight <= 0) {
|
||||
logError(QString("Invalid 'height' value '%1' for %2 in %3. Must be greater than 0.").arg(lheight).arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
|
|
@ -535,12 +531,12 @@ bool Project::readMapLayouts() {
|
|||
}
|
||||
layout->height = lheight;
|
||||
if (projectConfig.useCustomBorderSize) {
|
||||
int bwidth = ParseUtil::jsonToInt(layoutObj["border_width"]);
|
||||
int bwidth = ParseUtil::jsonToInt(layoutObj.take("border_width"));
|
||||
if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG
|
||||
bwidth = DEFAULT_BORDER_WIDTH;
|
||||
}
|
||||
layout->border_width = bwidth;
|
||||
int bheight = ParseUtil::jsonToInt(layoutObj["border_height"]);
|
||||
int bheight = ParseUtil::jsonToInt(layoutObj.take("border_height"));
|
||||
if (bheight <= 0) {
|
||||
bheight = DEFAULT_BORDER_HEIGHT;
|
||||
}
|
||||
|
|
@ -549,30 +545,31 @@ bool Project::readMapLayouts() {
|
|||
layout->border_width = DEFAULT_BORDER_WIDTH;
|
||||
layout->border_height = DEFAULT_BORDER_HEIGHT;
|
||||
}
|
||||
layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj["primary_tileset"]);
|
||||
layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj.take("primary_tileset"));
|
||||
if (layout->tileset_primary_label.isEmpty()) {
|
||||
logError(QString("Missing 'primary_tileset' value for %1 in %2").arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
return false;
|
||||
}
|
||||
layout->tileset_secondary_label = ParseUtil::jsonToQString(layoutObj["secondary_tileset"]);
|
||||
layout->tileset_secondary_label = ParseUtil::jsonToQString(layoutObj.take("secondary_tileset"));
|
||||
if (layout->tileset_secondary_label.isEmpty()) {
|
||||
logError(QString("Missing 'secondary_tileset' value for %1 in %2").arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
return false;
|
||||
}
|
||||
layout->border_path = ParseUtil::jsonToQString(layoutObj["border_filepath"]);
|
||||
layout->border_path = ParseUtil::jsonToQString(layoutObj.take("border_filepath"));
|
||||
if (layout->border_path.isEmpty()) {
|
||||
logError(QString("Missing 'border_filepath' value for %1 in %2").arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
return false;
|
||||
}
|
||||
layout->blockdata_path = ParseUtil::jsonToQString(layoutObj["blockdata_filepath"]);
|
||||
layout->blockdata_path = ParseUtil::jsonToQString(layoutObj.take("blockdata_filepath"));
|
||||
if (layout->blockdata_path.isEmpty()) {
|
||||
logError(QString("Missing 'blockdata_filepath' value for %1 in %2").arg(layout->id).arg(layoutsFilepath));
|
||||
delete layout;
|
||||
return false;
|
||||
}
|
||||
layout->customData = layoutObj;
|
||||
|
||||
this->mapLayouts.insert(layout->id, layout);
|
||||
this->mapLayoutsMaster.insert(layout->id, layout->copy());
|
||||
|
|
@ -585,6 +582,8 @@ bool Project::readMapLayouts() {
|
|||
return false;
|
||||
}
|
||||
|
||||
this->customLayoutsData = layoutsObj;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -615,12 +614,14 @@ void Project::saveMapLayouts() {
|
|||
layoutObj["secondary_tileset"] = layout->tileset_secondary_label;
|
||||
layoutObj["border_filepath"] = layout->border_path;
|
||||
layoutObj["blockdata_filepath"] = layout->blockdata_path;
|
||||
OrderedJson::append(&layoutObj, layout->customData);
|
||||
layoutsArr.push_back(layoutObj);
|
||||
}
|
||||
layoutsObj["layouts"] = layoutsArr;
|
||||
OrderedJson::append(&layoutsObj, this->customLayoutsData);
|
||||
|
||||
ignoreWatchedFileTemporarily(layoutsFilepath);
|
||||
|
||||
layoutsObj["layouts"] = layoutsArr;
|
||||
OrderedJson layoutJson(layoutsObj);
|
||||
OrderedJsonDoc jsonDoc(&layoutJson);
|
||||
jsonDoc.dump(&layoutsFile);
|
||||
|
|
@ -677,6 +678,7 @@ void Project::saveMapGroups() {
|
|||
}
|
||||
mapGroupsObj[groupName] = groupArr;
|
||||
}
|
||||
OrderedJson::append(&mapGroupsObj, this->customMapGroupsData);
|
||||
|
||||
ignoreWatchedFileTemporarily(mapGroupsFilepath);
|
||||
|
||||
|
|
@ -696,26 +698,29 @@ void Project::saveRegionMapSections() {
|
|||
|
||||
OrderedJson::array mapSectionArray;
|
||||
for (const auto &idName : this->mapSectionIdNamesSaveOrder) {
|
||||
const LocationData location = this->locationData.value(idName);
|
||||
|
||||
OrderedJson::object mapSectionObj;
|
||||
mapSectionObj["id"] = idName;
|
||||
|
||||
if (this->mapSectionDisplayNames.contains(idName)) {
|
||||
mapSectionObj["name"] = this->mapSectionDisplayNames.value(idName);
|
||||
if (!location.displayName.isEmpty()) {
|
||||
mapSectionObj["name"] = location.displayName;
|
||||
}
|
||||
|
||||
if (this->regionMapEntries.contains(idName)) {
|
||||
MapSectionEntry entry = this->regionMapEntries.value(idName);
|
||||
mapSectionObj["x"] = entry.x;
|
||||
mapSectionObj["y"] = entry.y;
|
||||
mapSectionObj["width"] = entry.width;
|
||||
mapSectionObj["height"] = entry.height;
|
||||
if (location.map.valid) {
|
||||
mapSectionObj["x"] = location.map.x;
|
||||
mapSectionObj["y"] = location.map.y;
|
||||
mapSectionObj["width"] = location.map.width;
|
||||
mapSectionObj["height"] = location.map.height;
|
||||
}
|
||||
OrderedJson::append(&mapSectionObj, location.custom);
|
||||
|
||||
mapSectionArray.append(mapSectionObj);
|
||||
}
|
||||
|
||||
OrderedJson::object object;
|
||||
object["map_sections"] = mapSectionArray;
|
||||
OrderedJson::append(&object, this->customMapSectionsData);
|
||||
|
||||
ignoreWatchedFileTemporarily(filepath);
|
||||
OrderedJson json(object);
|
||||
|
|
@ -742,7 +747,7 @@ void Project::saveWildMonData() {
|
|||
monHeadersObject["for_maps"] = true;
|
||||
|
||||
OrderedJson::array fieldsInfoArray;
|
||||
for (EncounterField fieldInfo : wildMonFields) {
|
||||
for (EncounterField fieldInfo : this->wildMonFields) {
|
||||
OrderedJson::object fieldObject;
|
||||
OrderedJson::array rateArray;
|
||||
|
||||
|
|
@ -765,48 +770,52 @@ void Project::saveWildMonData() {
|
|||
}
|
||||
if (!groupsObject.empty()) fieldObject["groups"] = groupsObject;
|
||||
|
||||
OrderedJson::append(&fieldObject, fieldInfo.customData);
|
||||
fieldsInfoArray.append(fieldObject);
|
||||
}
|
||||
monHeadersObject["fields"] = fieldsInfoArray;
|
||||
|
||||
OrderedJson::array encountersArray;
|
||||
for (auto keyPair : wildMonData) {
|
||||
for (auto keyPair : this->wildMonData) {
|
||||
QString key = keyPair.first;
|
||||
for (auto grouplLabelPair : wildMonData[key]) {
|
||||
for (auto grouplLabelPair : this->wildMonData[key]) {
|
||||
QString groupLabel = grouplLabelPair.first;
|
||||
OrderedJson::object encounterObject;
|
||||
encounterObject["map"] = key;
|
||||
encounterObject["base_label"] = groupLabel;
|
||||
|
||||
WildPokemonHeader encounterHeader = wildMonData[key][groupLabel];
|
||||
WildPokemonHeader encounterHeader = this->wildMonData[key][groupLabel];
|
||||
for (auto fieldNamePair : encounterHeader.wildMons) {
|
||||
QString fieldName = fieldNamePair.first;
|
||||
OrderedJson::object fieldObject;
|
||||
OrderedJson::object monInfoObject;
|
||||
WildMonInfo monInfo = encounterHeader.wildMons[fieldName];
|
||||
fieldObject["encounter_rate"] = monInfo.encounterRate;
|
||||
monInfoObject["encounter_rate"] = monInfo.encounterRate;
|
||||
OrderedJson::array monArray;
|
||||
for (WildPokemon wildMon : monInfo.wildPokemon) {
|
||||
OrderedJson::object monEntry;
|
||||
monEntry["min_level"] = wildMon.minLevel;
|
||||
monEntry["max_level"] = wildMon.maxLevel;
|
||||
monEntry["species"] = wildMon.species;
|
||||
OrderedJson::append(&monEntry, wildMon.customData);
|
||||
monArray.push_back(monEntry);
|
||||
}
|
||||
fieldObject["mons"] = monArray;
|
||||
encounterObject[fieldName] = fieldObject;
|
||||
monInfoObject["mons"] = monArray;
|
||||
OrderedJson::append(&monInfoObject, monInfo.customData);
|
||||
|
||||
encounterObject[fieldName] = monInfoObject;
|
||||
OrderedJson::append(&encounterObject, encounterHeader.customData);
|
||||
}
|
||||
encountersArray.push_back(encounterObject);
|
||||
}
|
||||
}
|
||||
monHeadersObject["encounters"] = encountersArray;
|
||||
wildEncounterGroups.push_back(monHeadersObject);
|
||||
OrderedJson::append(&monHeadersObject, this->customWildMonGroupData);
|
||||
|
||||
// add extra Json objects that are not associated with maps to the file
|
||||
for (auto extraObject : extraEncounterGroups) {
|
||||
wildEncounterGroups.push_back(extraObject);
|
||||
}
|
||||
wildEncounterGroups.push_back(monHeadersObject);
|
||||
OrderedJson::append(&wildEncounterGroups, this->extraEncounterGroups);
|
||||
|
||||
wildEncountersObject["wild_encounter_groups"] = wildEncounterGroups;
|
||||
OrderedJson::append(&wildEncountersObject, this->customWildMonData);
|
||||
|
||||
ignoreWatchedFileTemporarily(wildEncountersJsonFilepath);
|
||||
OrderedJson encounterJson(wildEncountersObject);
|
||||
|
|
@ -870,6 +879,7 @@ void Project::saveHealLocations() {
|
|||
|
||||
OrderedJson::object object;
|
||||
object["heal_locations"] = eventJsonArr;
|
||||
OrderedJson::append(&object, this->customHealLocationsData);
|
||||
|
||||
ignoreWatchedFileTemporarily(filepath);
|
||||
OrderedJson json(object);
|
||||
|
|
@ -1203,6 +1213,7 @@ void Project::saveMap(Map *map, bool skipLayout) {
|
|||
connectionObj["map"] = getMapConstant(connection->targetMapName(), connection->targetMapName());
|
||||
connectionObj["offset"] = connection->offset();
|
||||
connectionObj["direction"] = connection->direction();
|
||||
OrderedJson::append(&connectionObj, connection->customData());
|
||||
connectionsArr.append(connectionObj);
|
||||
}
|
||||
mapObj["connections"] = connectionsArr;
|
||||
|
|
@ -1258,10 +1269,7 @@ void Project::saveMap(Map *map, bool skipLayout) {
|
|||
this->healLocations[map->constantName()] = hlEvents;
|
||||
|
||||
// Custom header fields.
|
||||
const auto customAttributes = map->customAttributes();
|
||||
for (auto i = customAttributes.constBegin(); i != customAttributes.constEnd(); i++) {
|
||||
mapObj[i.key()] = OrderedJson::fromQJsonValue(i.value());
|
||||
}
|
||||
OrderedJson::append(&mapObj, map->customAttributes());
|
||||
|
||||
OrderedJson mapJson(mapObj);
|
||||
OrderedJsonDoc jsonDoc(&mapJson);
|
||||
|
|
@ -1603,6 +1611,8 @@ bool Project::readWildMonData() {
|
|||
this->pokemonMaxLevel = 100;
|
||||
this->maxEncounterRate = 2880/16;
|
||||
this->wildEncountersLoaded = false;
|
||||
this->customWildMonData = OrderedJson::object();
|
||||
this->customWildMonGroupData = OrderedJson::object();
|
||||
if (!userConfig.useEncounterJson) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1648,7 +1658,8 @@ bool Project::readWildMonData() {
|
|||
QMap<QString, QMap<int, int>> encounterRateFrequencyMaps;
|
||||
|
||||
// Parse "wild_encounter_groups". This is the main object array containing all the data in this file.
|
||||
for (OrderedJson mainArrayJson : wildMonObj["wild_encounter_groups"].array_items()) {
|
||||
OrderedJson::array mainArray = wildMonObj.take("wild_encounter_groups").array_items();
|
||||
for (const OrderedJson &mainArrayJson : mainArray) {
|
||||
OrderedJson::object mainArrayObject = mainArrayJson.object_items();
|
||||
|
||||
// We're only interested in wild encounter data that's associated with maps ("for_maps" == true).
|
||||
|
|
@ -1657,10 +1668,14 @@ bool Project::readWildMonData() {
|
|||
if (!mainArrayObject["for_maps"].bool_value()) {
|
||||
this->extraEncounterGroups.push_back(mainArrayObject);
|
||||
continue;
|
||||
} else {
|
||||
// Note: We don't call 'take' above, we don't want to strip data from extraEncounterGroups.
|
||||
// We do want to strip it from the main group, because it shouldn't be treated as custom data.
|
||||
mainArrayObject.erase("for_maps");
|
||||
}
|
||||
|
||||
// If multiple "for_maps" data sets are found they will be collapsed into a single set.
|
||||
QString label = mainArrayObject["label"].string_value();
|
||||
QString label = mainArrayObject.take("label").string_value();
|
||||
if (this->wildMonTableName.isEmpty()) {
|
||||
this->wildMonTableName = label;
|
||||
} else {
|
||||
|
|
@ -1673,24 +1688,25 @@ bool Project::readWildMonData() {
|
|||
// Each element describes a type of wild encounter Porymap can expect to find, and we represent this data with an EncounterField.
|
||||
// They should contain a name ("type"), the number of encounter slots and the ratio at which they occur ("encounter_rates"),
|
||||
// and whether the encounters are divided into groups (like fishing rods).
|
||||
for (const OrderedJson &fieldJson : mainArrayObject["fields"].array_items()) {
|
||||
for (const OrderedJson &fieldJson : mainArrayObject.take("fields").array_items()) {
|
||||
OrderedJson::object fieldObject = fieldJson.object_items();
|
||||
|
||||
EncounterField encounterField;
|
||||
encounterField.name = fieldObject["type"].string_value();
|
||||
encounterField.name = fieldObject.take("type").string_value();
|
||||
|
||||
for (auto val : fieldObject["encounter_rates"].array_items()) {
|
||||
for (auto val : fieldObject.take("encounter_rates").array_items()) {
|
||||
encounterField.encounterRates.append(val.int_value());
|
||||
}
|
||||
|
||||
// Each element of the "groups" array is an object with the group name as the key (e.g. "old_rod")
|
||||
// and an array of slot numbers indicating which encounter slots in this encounter type belong to that group.
|
||||
for (auto groupPair : fieldObject["groups"].object_items()) {
|
||||
for (auto groupPair : fieldObject.take("groups").object_items()) {
|
||||
const QString groupName = groupPair.first;
|
||||
for (auto slotNum : groupPair.second.array_items()) {
|
||||
encounterField.groups[groupName].append(slotNum.int_value());
|
||||
}
|
||||
}
|
||||
encounterField.customData = fieldObject;
|
||||
|
||||
encounterRateFrequencyMaps.insert(encounterField.name, QMap<int, int>());
|
||||
this->wildMonFields.append(encounterField);
|
||||
|
|
@ -1700,7 +1716,7 @@ bool Project::readWildMonData() {
|
|||
// Each element is an object that will tell us which map it's associated with,
|
||||
// its symbol name (which we will display in the Groups dropdown) and a list of
|
||||
// pokémon associated with any of the encounter types described by the data we parsed above.
|
||||
for (const auto &encounterJson : mainArrayObject["encounters"].array_items()) {
|
||||
for (const auto &encounterJson : mainArrayObject.take("encounters").array_items()) {
|
||||
OrderedJson::object encounterObj = encounterJson.object_items();
|
||||
|
||||
WildPokemonHeader header;
|
||||
|
|
@ -1708,29 +1724,31 @@ bool Project::readWildMonData() {
|
|||
// Check for each possible encounter type.
|
||||
for (const EncounterField &monField : this->wildMonFields) {
|
||||
const QString field = monField.name;
|
||||
if (encounterObj[field].is_null()) {
|
||||
if (!encounterObj.contains(field)) {
|
||||
// Encounter type isn't present
|
||||
continue;
|
||||
}
|
||||
OrderedJson::object encounterFieldObj = encounterObj[field].object_items();
|
||||
OrderedJson::object encounterFieldObj = encounterObj.take(field).object_items();
|
||||
|
||||
WildMonInfo monInfo;
|
||||
monInfo.active = true;
|
||||
|
||||
// Read encounter rate
|
||||
monInfo.encounterRate = encounterFieldObj["encounter_rate"].int_value();
|
||||
monInfo.encounterRate = encounterFieldObj.take("encounter_rate").int_value();
|
||||
encounterRateFrequencyMaps[field][monInfo.encounterRate]++;
|
||||
|
||||
// Read wild pokémon list
|
||||
for (auto monJson : encounterFieldObj["mons"].array_items()) {
|
||||
for (const auto &monJson : encounterFieldObj.take("mons").array_items()) {
|
||||
OrderedJson::object monObj = monJson.object_items();
|
||||
|
||||
WildPokemon newMon;
|
||||
newMon.minLevel = monObj["min_level"].int_value();
|
||||
newMon.maxLevel = monObj["max_level"].int_value();
|
||||
newMon.species = monObj["species"].string_value();
|
||||
newMon.minLevel = monObj.take("min_level").int_value();
|
||||
newMon.maxLevel = monObj.take("max_level").int_value();
|
||||
newMon.species = monObj.take("species").string_value();
|
||||
newMon.customData = monObj;
|
||||
monInfo.wildPokemon.append(newMon);
|
||||
}
|
||||
monInfo.customData = encounterFieldObj;
|
||||
|
||||
// If the user supplied too few pokémon for this group then we fill in the rest with default values.
|
||||
for (int i = monInfo.wildPokemon.length(); i < monField.encounterRates.length(); i++) {
|
||||
|
|
@ -1738,13 +1756,15 @@ bool Project::readWildMonData() {
|
|||
}
|
||||
header.wildMons[field] = monInfo;
|
||||
}
|
||||
|
||||
const QString mapConstant = encounterObj["map"].string_value();
|
||||
const QString baseLabel = encounterObj["base_label"].string_value();
|
||||
const QString mapConstant = encounterObj.take("map").string_value();
|
||||
const QString baseLabel = encounterObj.take("base_label").string_value();
|
||||
header.customData = encounterObj;
|
||||
this->wildMonData[mapConstant].insert({baseLabel, header});
|
||||
this->encounterGroupLabels.append(baseLabel);
|
||||
}
|
||||
this->customWildMonGroupData = mainArrayObject;
|
||||
}
|
||||
this->customWildMonData = wildMonObj;
|
||||
|
||||
// For each encounter type, set default encounter rate to most common value.
|
||||
// Iterate over map of encounter type names to frequency maps...
|
||||
|
|
@ -1772,8 +1792,7 @@ bool Project::readMapGroups() {
|
|||
this->mapNames.clear();
|
||||
this->groupNames.clear();
|
||||
this->groupNameToMapNames.clear();
|
||||
|
||||
this->initTopLevelMapFields();
|
||||
this->customMapGroupsData = QJsonObject();
|
||||
|
||||
const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_map_groups);
|
||||
fileWatcher.addPath(root + "/" + filepath);
|
||||
|
|
@ -1785,7 +1804,7 @@ bool Project::readMapGroups() {
|
|||
}
|
||||
|
||||
QJsonObject mapGroupsObj = mapGroupsDoc.object();
|
||||
QJsonArray mapGroupOrder = mapGroupsObj["group_order"].toArray();
|
||||
QJsonArray mapGroupOrder = mapGroupsObj.take("group_order").toArray();
|
||||
|
||||
const QString dynamicMapName = getDynamicMapName();
|
||||
const QString dynamicMapConstant = getDynamicMapDefineName();
|
||||
|
|
@ -1794,7 +1813,12 @@ bool Project::readMapGroups() {
|
|||
QStringList failedMapNames;
|
||||
for (int groupIndex = 0; groupIndex < mapGroupOrder.size(); groupIndex++) {
|
||||
const QString groupName = ParseUtil::jsonToQString(mapGroupOrder.at(groupIndex));
|
||||
const QJsonArray mapNamesJson = mapGroupsObj.value(groupName).toArray();
|
||||
if (this->groupNames.contains(groupName)) {
|
||||
logWarn(QString("Ignoring repeated map group name '%1'.").arg(groupName));
|
||||
continue;
|
||||
}
|
||||
|
||||
const QJsonArray mapNamesJson = mapGroupsObj.take(groupName).toArray();
|
||||
this->groupNames.append(groupName);
|
||||
|
||||
// Process the names in this map group
|
||||
|
|
@ -1888,6 +1912,14 @@ bool Project::readMapGroups() {
|
|||
this->mapConstantsToMapNames.insert(dynamicMapConstant, dynamicMapName);
|
||||
this->mapNames.append(dynamicMapName);
|
||||
|
||||
// Chuck the "connections_include_order" field, this is only for matching.
|
||||
if (!projectConfig.preserveMatchingOnlyData) {
|
||||
mapGroupsObj.remove("connections_include_order");
|
||||
}
|
||||
|
||||
// Preserve any remaining fields for when we save.
|
||||
this->customMapGroupsData = mapGroupsObj;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2317,10 +2349,11 @@ bool Project::readFieldmapMasks() {
|
|||
}
|
||||
|
||||
bool Project::readRegionMapSections() {
|
||||
this->locationData.clear();
|
||||
this->mapSectionIdNames.clear();
|
||||
this->mapSectionIdNamesSaveOrder.clear();
|
||||
this->mapSectionDisplayNames.clear();
|
||||
this->regionMapEntries.clear();
|
||||
this->customMapSectionsData = QJsonObject();
|
||||
|
||||
const QString defaultName = getEmptyMapsecName();
|
||||
const QString requiredPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix);
|
||||
|
||||
|
|
@ -2333,7 +2366,8 @@ bool Project::readRegionMapSections() {
|
|||
}
|
||||
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath));
|
||||
|
||||
QJsonArray mapSections = doc.object()["map_sections"].toArray();
|
||||
QJsonObject mapSectionsGlobalObj = doc.object();
|
||||
QJsonArray mapSections = mapSectionsGlobalObj.take("map_sections").toArray();
|
||||
for (int i = 0; i < mapSections.size(); i++) {
|
||||
QJsonObject mapSectionObj = mapSections.at(i).toObject();
|
||||
|
||||
|
|
@ -2351,7 +2385,7 @@ bool Project::readRegionMapSections() {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
const QString idName = ParseUtil::jsonToQString(mapSectionObj[idField]);
|
||||
const QString idName = ParseUtil::jsonToQString(mapSectionObj.take(idField));
|
||||
if (!idName.startsWith(requiredPrefix)) {
|
||||
logWarn(QString("Ignoring data for map section '%1' in '%2'. IDs must start with the prefix '%3'").arg(idName).arg(filepath).arg(requiredPrefix));
|
||||
continue;
|
||||
|
|
@ -2360,8 +2394,10 @@ bool Project::readRegionMapSections() {
|
|||
this->mapSectionIdNames.append(idName);
|
||||
this->mapSectionIdNamesSaveOrder.append(idName);
|
||||
|
||||
if (mapSectionObj.contains("name"))
|
||||
this->mapSectionDisplayNames.insert(idName, ParseUtil::jsonToQString(mapSectionObj["name"]));
|
||||
LocationData location;
|
||||
if (mapSectionObj.contains("name")) {
|
||||
location.displayName = ParseUtil::jsonToQString(mapSectionObj.take("name"));
|
||||
}
|
||||
|
||||
// Map sections may have additional data indicating their position on the region map.
|
||||
// If they have this data, we can add them to the region map entry list.
|
||||
|
|
@ -2373,17 +2409,25 @@ bool Project::readRegionMapSections() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!hasRegionMapData)
|
||||
continue;
|
||||
if (hasRegionMapData) {
|
||||
location.map.x = ParseUtil::jsonToInt(mapSectionObj.take("x"));
|
||||
location.map.y = ParseUtil::jsonToInt(mapSectionObj.take("y"));
|
||||
location.map.width = ParseUtil::jsonToInt(mapSectionObj.take("width"));
|
||||
location.map.height = ParseUtil::jsonToInt(mapSectionObj.take("height"));
|
||||
location.map.valid = true;
|
||||
}
|
||||
|
||||
MapSectionEntry entry;
|
||||
entry.x = ParseUtil::jsonToInt(mapSectionObj["x"]);
|
||||
entry.y = ParseUtil::jsonToInt(mapSectionObj["y"]);
|
||||
entry.width = ParseUtil::jsonToInt(mapSectionObj["width"]);
|
||||
entry.height = ParseUtil::jsonToInt(mapSectionObj["height"]);
|
||||
entry.valid = true;
|
||||
this->regionMapEntries[idName] = entry;
|
||||
// Chuck the "name_clone" field, this is only for matching.
|
||||
if (!projectConfig.preserveMatchingOnlyData) {
|
||||
mapSectionObj.remove("name_clone");
|
||||
}
|
||||
|
||||
// Preserve any remaining fields for when we save.
|
||||
location.custom = mapSectionObj;
|
||||
|
||||
this->locationData.insert(idName, location);
|
||||
}
|
||||
this->customMapSectionsData = mapSectionsGlobalObj;
|
||||
|
||||
// Make sure the default name is present in the list.
|
||||
if (!this->mapSectionIdNames.contains(defaultName)) {
|
||||
|
|
@ -2394,6 +2438,20 @@ bool Project::readRegionMapSections() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Project::setRegionMapEntries(const QHash<QString, MapSectionEntry> &entries) {
|
||||
for (auto it = entries.constBegin(); it != entries.constEnd(); it++) {
|
||||
this->locationData[it.key()].map = it.value();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<QString, MapSectionEntry> Project::getRegionMapEntries() const {
|
||||
QHash<QString, MapSectionEntry> entries;
|
||||
for (auto it = this->locationData.constBegin(); it != this->locationData.constEnd(); it++) {
|
||||
entries[it.key()] = it.value().map;
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
QString Project::getEmptyMapsecName() {
|
||||
return projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_empty);
|
||||
}
|
||||
|
|
@ -2444,9 +2502,9 @@ void Project::removeMapsec(const QString &idName) {
|
|||
}
|
||||
|
||||
void Project::setMapsecDisplayName(const QString &idName, const QString &displayName) {
|
||||
if (this->mapSectionDisplayNames.value(idName) == displayName)
|
||||
if (getMapsecDisplayName(idName) == displayName)
|
||||
return;
|
||||
this->mapSectionDisplayNames[idName] = displayName;
|
||||
this->locationData[idName].displayName = displayName;
|
||||
this->hasUnsavedDataChanges = true;
|
||||
emit mapSectionDisplayNameChanged(idName, displayName);
|
||||
}
|
||||
|
|
@ -2457,6 +2515,7 @@ void Project::clearHealLocations() {
|
|||
}
|
||||
this->healLocations.clear();
|
||||
this->healLocationSaveOrder.clear();
|
||||
this->customHealLocationsData = QJsonObject();
|
||||
}
|
||||
|
||||
bool Project::readHealLocations() {
|
||||
|
|
@ -2471,7 +2530,8 @@ bool Project::readHealLocations() {
|
|||
}
|
||||
fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath));
|
||||
|
||||
QJsonArray healLocations = doc.object()["heal_locations"].toArray();
|
||||
QJsonObject healLocationsObj = doc.object();
|
||||
QJsonArray healLocations = healLocationsObj.take("heal_locations").toArray();
|
||||
for (int i = 0; i < healLocations.size(); i++) {
|
||||
QJsonObject healLocationObj = healLocations.at(i).toObject();
|
||||
static const QString mapField = QStringLiteral("map");
|
||||
|
|
@ -2482,9 +2542,10 @@ bool Project::readHealLocations() {
|
|||
|
||||
auto event = new HealLocationEvent();
|
||||
event->loadFromJson(healLocationObj, this);
|
||||
this->healLocations[ParseUtil::jsonToQString(healLocationObj["map"])].append(event);
|
||||
this->healLocations[event->getHostMapName()].append(event);
|
||||
this->healLocationSaveOrder.append(event->getIdName());
|
||||
}
|
||||
this->customHealLocationsData = healLocationsObj;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ CustomAttributesTable::CustomAttributesTable(QWidget *parent) :
|
|||
});
|
||||
}
|
||||
|
||||
QMap<QString, QJsonValue> CustomAttributesTable::getAttributes() const {
|
||||
QMap<QString, QJsonValue> fields;
|
||||
QJsonObject CustomAttributesTable::getAttributes() const {
|
||||
QJsonObject fields;
|
||||
for (int row = 0; row < this->rowCount(); row++) {
|
||||
auto keyValuePair = this->getAttribute(row);
|
||||
if (!keyValuePair.first.isEmpty())
|
||||
|
|
@ -145,10 +145,10 @@ void CustomAttributesTable::addNewAttribute(const QString &key, const QJsonValue
|
|||
}
|
||||
|
||||
// For programmatically populating the table
|
||||
void CustomAttributesTable::setAttributes(const QMap<QString, QJsonValue> &attributes) {
|
||||
void CustomAttributesTable::setAttributes(const QJsonObject &attributes) {
|
||||
m_keys.clear();
|
||||
this->setRowCount(0); // Clear old values
|
||||
for (auto it = attributes.cbegin(); it != attributes.cend(); it++)
|
||||
for (auto it = attributes.constBegin(); it != attributes.constEnd(); it++)
|
||||
this->addAttribute(it.key(), it.value());
|
||||
this->resizeVertically();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -444,6 +444,7 @@ void ProjectSettingsEditor::refresh() {
|
|||
ui->checkBox_OutputCallback->setChecked(projectConfig.tilesetsHaveCallback);
|
||||
ui->checkBox_OutputIsCompressed->setChecked(projectConfig.tilesetsHaveIsCompressed);
|
||||
ui->checkBox_DisableWarning->setChecked(porymapConfig.warpBehaviorWarningDisabled);
|
||||
ui->checkBox_PreserveMatchingOnlyData->setChecked(projectConfig.preserveMatchingOnlyData);
|
||||
|
||||
// Radio buttons
|
||||
if (projectConfig.setTransparentPixelsBlack)
|
||||
|
|
@ -525,6 +526,7 @@ void ProjectSettingsEditor::save() {
|
|||
projectConfig.tilesetsHaveIsCompressed = ui->checkBox_OutputIsCompressed->isChecked();
|
||||
porymapConfig.warpBehaviorWarningDisabled = ui->checkBox_DisableWarning->isChecked();
|
||||
projectConfig.setTransparentPixelsBlack = ui->radioButton_RenderBlack->isChecked();
|
||||
projectConfig.preserveMatchingOnlyData = ui->checkBox_PreserveMatchingOnlyData->isChecked();
|
||||
|
||||
// Save spin box settings
|
||||
projectConfig.defaultElevation = ui->spinBox_Elevation->value();
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ void RegionMapEditor::applyUserShortcuts() {
|
|||
}
|
||||
|
||||
bool RegionMapEditor::loadRegionMapEntries() {
|
||||
this->region_map_entries = this->project->regionMapEntries;
|
||||
this->region_map_entries = this->project->getRegionMapEntries();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegionMapEditor::saveRegionMapEntries() {
|
||||
this->project->regionMapEntries = this->region_map_entries;
|
||||
this->project->setRegionMapEntries(this->region_map_entries);
|
||||
this->project->saveRegionMapSections();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user