Merge pull request #479 from GriffinRichards/fix-json

Better type conversion for JSON data
This commit is contained in:
Marcus Huderle 2022-10-22 12:57:17 -05:00 committed by GitHub
commit 7b66537d01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 576 additions and 428 deletions

View file

@ -26,6 +26,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
### Changed ### Changed
- Overhauled the region map editor, adding support for tilemaps, and significant customization. Also now supports pokefirered. - Overhauled the region map editor, adding support for tilemaps, and significant customization. Also now supports pokefirered.
- The Custom Attributes table for map headers and events now supports types other than strings.
- If an object event is inanimate, it will always render using its first frame. - If an object event is inanimate, it will always render using its first frame.
- Unused metatile attribute bits are preserved instead of being cleared. - Unused metatile attribute bits are preserved instead of being cleared.
- The wild encounter editor is automatically disabled if the encounter JSON data cannot be read - The wild encounter editor is automatically disabled if the encounter JSON data cannot be read
@ -42,6 +43,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
- The number and order of entries in the heal location data tables can now be changed arbitrarily, and independently of each other. - The number and order of entries in the heal location data tables can now be changed arbitrarily, and independently of each other.
- The metatile behavior is now displayed in the bottom bar mouseover text. - The metatile behavior is now displayed in the bottom bar mouseover text.
- Removed some unnecessary error logs from the scripting API and added new useful ones. - Removed some unnecessary error logs from the scripting API and added new useful ones.
- If any JSON data is the incorrect type Porymap will now attempt to convert it.
### Fixed ### Fixed
- Fix events losing their assigned script when the script autocomplete is used. - Fix events losing their assigned script when the script autocomplete is used.

View file

@ -2276,14 +2276,14 @@
</widget> </widget>
</item> </item>
<item row="10" column="0"> <item row="10" column="0">
<widget class="QLabel" name="label_AllowEscapeRope"> <widget class="QLabel" name="label_AllowEscaping">
<property name="text"> <property name="text">
<string>Allow Dig &amp; Escape Rope</string> <string>Allow Dig &amp; Escape Rope</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="10" column="1">
<widget class="QCheckBox" name="checkBox_AllowEscapeRope"> <widget class="QCheckBox" name="checkBox_AllowEscaping">
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allows the player to use Dig or Escape Rope&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allows the player to use Dig or Escape Rope&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
@ -2388,7 +2388,7 @@
<string>Custom fields will be added to the map.json file for the current map.</string> <string>Custom fields will be added to the map.json file for the current map.</string>
</property> </property>
<attribute name="horizontalHeaderVisible"> <attribute name="horizontalHeaderVisible">
<bool>false</bool> <bool>true</bool>
</attribute> </attribute>
<attribute name="horizontalHeaderCascadingSectionResizes"> <attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool> <bool>false</bool>
@ -2405,6 +2405,11 @@
<attribute name="verticalHeaderVisible"> <attribute name="verticalHeaderVisible">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column> <column>
<property name="text"> <property name="text">
<string>Key</string> <string>Key</string>

View file

@ -151,8 +151,8 @@ public:
virtual QSet<QString> getExpectedFields() = 0; virtual QSet<QString> getExpectedFields() = 0;
void readCustomValues(QJsonObject values); void readCustomValues(QJsonObject values);
void addCustomValuesTo(OrderedJson::object *obj); void addCustomValuesTo(OrderedJson::object *obj);
QMap<QString, QString> getCustomValues() { return this->customValues; } const QMap<QString, QJsonValue> getCustomValues() { return this->customValues; }
void setCustomValues(QMap<QString, QString> newCustomValues) { this->customValues = newCustomValues; } void setCustomValues(const QMap<QString, QJsonValue> newCustomValues) { this->customValues = newCustomValues; }
virtual void loadPixmap(Project *project) = 0; virtual void loadPixmap(Project *project) = 0;
@ -173,6 +173,7 @@ public:
int getEventIndex(); int getEventIndex();
static QString eventGroupToString(Event::Group group);
static QString eventTypeToString(Event::Type type); static QString eventTypeToString(Event::Type type);
static Event::Type eventTypeFromString(QString type); static Event::Type eventTypeFromString(QString type);
@ -192,7 +193,7 @@ protected:
int spriteHeight = 16; int spriteHeight = 16;
bool usingSprite = false; bool usingSprite = false;
QMap<QString, QString> customValues; QMap<QString, QJsonValue> customValues;
QPixmap pixmap; QPixmap pixmap;
DraggablePixmapItem *pixmapItem = nullptr; DraggablePixmapItem *pixmapItem = nullptr;
@ -340,12 +341,12 @@ public:
void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; } void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; }
QString getDestinationMap() { return this->destinationMap; } QString getDestinationMap() { return this->destinationMap; }
void setDestinationWarpID(int newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; } void setDestinationWarpID(QString newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; }
int getDestinationWarpID() { return this->destinationWarpID; } QString getDestinationWarpID() { return this->destinationWarpID; }
private: private:
QString destinationMap; QString destinationMap;
int destinationWarpID = 0; QString destinationWarpID;
}; };

View file

@ -42,23 +42,23 @@ public:
QString song; QString song;
QString layoutId; QString layoutId;
QString location; QString location;
QString requiresFlash; bool requiresFlash;
QString isFlyable;
QString weather; QString weather;
QString type; QString type;
QString show_location; bool show_location;
QString allowRunning; bool allowRunning;
QString allowBiking; bool allowBiking;
QString allowEscapeRope; bool allowEscaping;
int floorNumber = 0; int floorNumber = 0;
QString battle_scene; QString battle_scene;
QString sharedEventsMap = ""; QString sharedEventsMap = "";
QString sharedScriptsMap = ""; QString sharedScriptsMap = "";
QMap<QString, QString> customHeaders; QMap<QString, QJsonValue> customHeaders;
MapLayout *layout; MapLayout *layout;
bool isPersistedToFile = true; bool isPersistedToFile = true;
bool hasUnsavedDataChanges = false; bool hasUnsavedDataChanges = false;
bool needsLayoutDir = true; bool needsLayoutDir = true;
bool needsHealLocation = false;
QImage collision_image; QImage collision_image;
QPixmap collision_pixmap; QPixmap collision_pixmap;
QImage image; QImage image;

View file

@ -8,7 +8,7 @@
class MapConnection { class MapConnection {
public: public:
QString direction; QString direction;
QString offset; int offset;
QString map_name; QString map_name;
}; };

View file

@ -14,10 +14,10 @@ public:
static QString layoutConstantFromName(QString mapName); static QString layoutConstantFromName(QString mapName);
QString id; QString id;
QString name; QString name;
QString width; int width;
QString height; int height;
QString border_width; int border_width;
QString border_height; int border_height;
QString border_path; QString border_path;
QString blockdata_path; QString blockdata_path;
QString tileset_primary_label; QString tileset_primary_label;

View file

@ -72,7 +72,11 @@ public:
static QString removeLineComments(QString text, const QStringList &commentSymbols); static QString removeLineComments(QString text, const QStringList &commentSymbols);
static QStringList splitShellCommand(QStringView command); static QStringList splitShellCommand(QStringView command);
static int gameStringToInt(QString gameString, bool * ok = nullptr);
static bool gameStringToBool(QString gameString, bool * ok = nullptr); static bool gameStringToBool(QString gameString, bool * ok = nullptr);
static QString jsonToQString(QJsonValue value, bool * ok = nullptr);
static int jsonToInt(QJsonValue value, bool * ok = nullptr);
static bool jsonToBool(QJsonValue value, bool * ok = nullptr);
private: private:
QString root; QString root;

View file

@ -60,6 +60,9 @@
#include <QPair> #include <QPair>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <QJsonValue>
#include <QJsonArray>
#include <QJsonObject>
#include <memory> #include <memory>
#include <initializer_list> #include <initializer_list>
@ -129,6 +132,8 @@ public:
int>::type = 0> int>::type = 0>
Json(const V & v) : Json(array(v.begin(), v.end())) {} Json(const V & v) : Json(array(v.begin(), v.end())) {}
static const Json fromQJsonValue(QJsonValue value);
// This prevents Json(some_pointer) from accidentally producing a bool. Use // This prevents Json(some_pointer) from accidentally producing a bool. Use
// Json(bool(some_pointer)) if that behavior is desired. // Json(bool(some_pointer)) if that behavior is desired.
Json(void *) = delete; Json(void *) = delete;

View file

@ -196,7 +196,7 @@ private slots:
void on_checkBox_ShowLocation_stateChanged(int selected); void on_checkBox_ShowLocation_stateChanged(int selected);
void on_checkBox_AllowRunning_stateChanged(int selected); void on_checkBox_AllowRunning_stateChanged(int selected);
void on_checkBox_AllowBiking_stateChanged(int selected); void on_checkBox_AllowBiking_stateChanged(int selected);
void on_checkBox_AllowEscapeRope_stateChanged(int selected); void on_checkBox_AllowEscaping_stateChanged(int selected);
void on_spinBox_FloorNumber_valueChanged(int offset); void on_spinBox_FloorNumber_valueChanged(int offset);
void on_actionUse_Encounter_Json_triggered(bool checked); void on_actionUse_Encounter_Json_triggered(bool checked);
void on_actionMonitor_Project_Files_triggered(bool checked); void on_actionMonitor_Project_Files_triggered(bool checked);
@ -219,6 +219,7 @@ private slots:
void on_toolButton_deleteObject_clicked(); void on_toolButton_deleteObject_clicked();
void addNewEvent(Event::Type type); void addNewEvent(Event::Type type);
void tryAddEventTab(QWidget * tab, Event::Group group);
void displayEventTabs(); void displayEventTabs();
void updateSelectedObjects(); void updateSelectedObjects();
void updateObjects(); void updateObjects();
@ -387,6 +388,7 @@ private:
void redrawMetatileSelection(); void redrawMetatileSelection();
QObjectList shortcutableObjects() const; QObjectList shortcutableObjects() const;
void addCustomHeaderValue(QString key, QJsonValue value, bool isNew = false);
}; };
enum MapListUserRoles { enum MapListUserRoles {

View file

@ -26,8 +26,9 @@ struct EventGraphics
bool inanimate; bool inanimate;
}; };
static QString NONE_MAP_CONSTANT = "MAP_NONE"; // The constant and displayed name of the special map value used by warps with multiple potential destinations
static QString NONE_MAP_NAME = "None"; static QString DYNAMIC_MAP_CONSTANT = "MAP_DYNAMIC";
static QString DYNAMIC_MAP_NAME = "Dynamic";
class Project : public QObject class Project : public QObject
{ {
@ -136,7 +137,7 @@ public:
bool readSpeciesIconPaths(); bool readSpeciesIconPaths();
QMap<QString, QString> speciesToIconPath; QMap<QString, QString> speciesToIconPath;
QMap<QString, bool> getTopLevelMapFields(); QSet<QString> getTopLevelMapFields();
bool loadMapData(Map*); bool loadMapData(Map*);
bool readMapLayouts(); bool readMapLayouts();
bool loadLayout(MapLayout *); bool loadLayout(MapLayout *);

View file

@ -15,7 +15,7 @@ public:
setFlag(ItemSendsGeometryChanges); setFlag(ItemSendsGeometryChanges);
this->initialX = x; this->initialX = x;
this->initialY = y; this->initialY = y;
this->initialOffset = connection->offset.toInt(); this->initialOffset = connection->offset;
this->baseMapWidth = baseMapWidth; this->baseMapWidth = baseMapWidth;
this->baseMapHeight = baseMapHeight; this->baseMapHeight = baseMapHeight;
} }

View file

@ -12,11 +12,15 @@ public:
explicit CustomAttributesTable(Event *event, QWidget *parent = nullptr); explicit CustomAttributesTable(Event *event, QWidget *parent = nullptr);
~CustomAttributesTable(); ~CustomAttributesTable();
static const QMap<QString, QJsonValue> getAttributes(QTableWidget * table);
static QJsonValue pickType(QWidget * parent, bool * ok = nullptr);
static void addAttribute(QTableWidget * table, QString key, QJsonValue value, bool isNew = false);
static bool deleteSelectedAttributes(QTableWidget * table);
private: private:
Event *event; Event *event;
QTableWidget *table; QTableWidget *table;
void resizeVertically(); void resizeVertically();
QMap<QString, QString> getTableFields();
}; };
#endif // CUSTOMATTRIBUTESTABLE_H #endif // CUSTOMATTRIBUTESTABLE_H

View file

@ -133,7 +133,7 @@ public:
public: public:
NoScrollComboBox *combo_dest_map; NoScrollComboBox *combo_dest_map;
NoScrollSpinBox *spinner_dest_warp; NoScrollComboBox *combo_dest_warp;
private: private:
WarpEvent *warp; WarpEvent *warp;

View file

@ -43,7 +43,7 @@ void Event::readCustomValues(QJsonObject values) {
QSet<QString> expectedFields = this->getExpectedFields(); QSet<QString> expectedFields = this->getExpectedFields();
for (QString key : values.keys()) { for (QString key : values.keys()) {
if (!expectedFields.contains(key)) { if (!expectedFields.contains(key)) {
this->customValues[key] = values[key].toString(); this->customValues[key] = values[key];
} }
} }
} }
@ -51,7 +51,7 @@ void Event::readCustomValues(QJsonObject values) {
void Event::addCustomValuesTo(OrderedJson::object *obj) { void Event::addCustomValuesTo(OrderedJson::object *obj) {
for (QString key : this->customValues.keys()) { for (QString key : this->customValues.keys()) {
if (!obj->contains(key)) { if (!obj->contains(key)) {
(*obj)[key] = this->customValues[key]; (*obj)[key] = OrderedJson::fromQJsonValue(this->customValues[key]);
} }
} }
} }
@ -60,6 +60,23 @@ void Event::modify() {
this->map->modify(); this->map->modify();
} }
QString Event::eventGroupToString(Event::Group group) {
switch (group) {
case Event::Group::Object:
return "Object";
case Event::Group::Warp:
return "Warp";
case Event::Group::Coord:
return "Trigger";
case Event::Group::Bg:
return "BG";
case Event::Group::Heal:
return "Healspot";
default:
return "";
}
}
QString Event::eventTypeToString(Event::Type type) { QString Event::eventTypeToString(Event::Type type) {
switch (type) { switch (type) {
case Event::Type::Object: case Event::Type::Object:
@ -163,17 +180,17 @@ OrderedJson::object ObjectEvent::buildEventJson(Project *) {
} }
bool ObjectEvent::loadFromJson(QJsonObject json, Project *) { bool ObjectEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setGfx(json["graphics_id"].toString()); this->setGfx(ParseUtil::jsonToQString(json["graphics_id"]));
this->setMovement(json["movement_type"].toString()); this->setMovement(ParseUtil::jsonToQString(json["movement_type"]));
this->setRadiusX(json["movement_range_x"].toInt()); this->setRadiusX(ParseUtil::jsonToInt(json["movement_range_x"]));
this->setRadiusY(json["movement_range_y"].toInt()); this->setRadiusY(ParseUtil::jsonToInt(json["movement_range_y"]));
this->setTrainerType(json["trainer_type"].toString()); this->setTrainerType(ParseUtil::jsonToQString(json["trainer_type"]));
this->setSightRadiusBerryTreeID(json["trainer_sight_or_berry_tree_id"].toString()); this->setSightRadiusBerryTreeID(ParseUtil::jsonToQString(json["trainer_sight_or_berry_tree_id"]));
this->setScript(json["script"].toString()); this->setScript(ParseUtil::jsonToQString(json["script"]));
this->setFlag(json["flag"].toString()); this->setFlag(ParseUtil::jsonToQString(json["flag"]));
this->readCustomValues(json); this->readCustomValues(json);
@ -220,7 +237,7 @@ void ObjectEvent::loadPixmap(Project *project) {
// Invalid gfx constant. // Invalid gfx constant.
// If this is a number, try to use that instead. // If this is a number, try to use that instead.
bool ok; bool ok;
int altGfx = this->gfx.toInt(&ok); int altGfx = ParseUtil::gameStringToInt(this->gfx, &ok);
if (ok && (altGfx < project->gfxDefines.count())) { if (ok && (altGfx < project->gfxDefines.count())) {
eventGfx = project->eventGraphicsMap.value(project->gfxDefines.key(altGfx, "NULL"), nullptr); eventGfx = project->eventGraphicsMap.value(project->gfxDefines.key(altGfx, "NULL"), nullptr);
} }
@ -311,20 +328,20 @@ OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) {
} }
bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setGfx(json["graphics_id"].toString()); this->setGfx(ParseUtil::jsonToQString(json["graphics_id"]));
this->setTargetID(json["target_local_id"].toInt()); this->setTargetID(ParseUtil::jsonToInt(json["target_local_id"]));
// Ensure the target map constant is valid before adding it to the events. // Ensure the target map constant is valid before adding it to the events.
QString mapConstant = json["target_map"].toString(); QString mapConstant = ParseUtil::jsonToQString(json["target_map"]);
if (project->mapConstantsToMapNames.contains(mapConstant)) { if (project->mapConstantsToMapNames.contains(mapConstant)) {
this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant)); this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant));
} else if (mapConstant == NONE_MAP_CONSTANT) { } else if (mapConstant == DYNAMIC_MAP_CONSTANT) {
this->setTargetMap(NONE_MAP_NAME); this->setTargetMap(DYNAMIC_MAP_NAME);
} else { } else {
logError(QString("Destination map constant '%1' is invalid").arg(mapConstant)); logWarn(QString("Target Map constant '%1' is invalid. Using default '%2'.").arg(mapConstant).arg(DYNAMIC_MAP_CONSTANT));
return false; this->setTargetMap(DYNAMIC_MAP_NAME);
} }
this->readCustomValues(json); this->readCustomValues(json);
@ -421,20 +438,20 @@ OrderedJson::object WarpEvent::buildEventJson(Project *project) {
} }
bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { bool WarpEvent::loadFromJson(QJsonObject json, Project *project) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setDestinationWarpID(json["dest_warp_id"].toInt()); this->setDestinationWarpID(ParseUtil::jsonToQString(json["dest_warp_id"]));
// Ensure the warp destination map constant is valid before adding it to the warps. // Ensure the warp destination map constant is valid before adding it to the warps.
QString mapConstant = json["dest_map"].toString(); QString mapConstant = ParseUtil::jsonToQString(json["dest_map"]);
if (project->mapConstantsToMapNames.contains(mapConstant)) { if (project->mapConstantsToMapNames.contains(mapConstant)) {
this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant)); this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant));
} else if (mapConstant == NONE_MAP_CONSTANT) { } else if (mapConstant == DYNAMIC_MAP_CONSTANT) {
this->setDestinationMap(NONE_MAP_NAME); this->setDestinationMap(DYNAMIC_MAP_NAME);
} else { } else {
logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant)); logWarn(QString("Destination Map constant '%1' is invalid. Using default '%2'.").arg(mapConstant).arg(DYNAMIC_MAP_CONSTANT));
return false; this->setDestinationMap(DYNAMIC_MAP_NAME);
} }
this->readCustomValues(json); this->readCustomValues(json);
@ -444,7 +461,7 @@ bool WarpEvent::loadFromJson(QJsonObject json, Project *project) {
void WarpEvent::setDefaultValues(Project *) { void WarpEvent::setDefaultValues(Project *) {
if (this->getMap()) this->setDestinationMap(this->getMap()->name); if (this->getMap()) this->setDestinationMap(this->getMap()->name);
this->setDestinationWarpID(0); this->setDestinationWarpID("0");
this->setElevation(0); this->setElevation(0);
} }
@ -515,12 +532,12 @@ OrderedJson::object TriggerEvent::buildEventJson(Project *) {
} }
bool TriggerEvent::loadFromJson(QJsonObject json, Project *) { bool TriggerEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setScriptVar(json["var"].toString()); this->setScriptVar(ParseUtil::jsonToQString(json["var"]));
this->setScriptVarValue(json["var_value"].toString()); this->setScriptVarValue(ParseUtil::jsonToQString(json["var_value"]));
this->setScriptLabel(json["script"].toString()); this->setScriptLabel(ParseUtil::jsonToQString(json["script"]));
this->readCustomValues(json); this->readCustomValues(json);
@ -589,10 +606,10 @@ OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) {
} }
bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) { bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setWeather(json["weather"].toString()); this->setWeather(ParseUtil::jsonToQString(json["weather"]));
this->readCustomValues(json); this->readCustomValues(json);
@ -665,11 +682,11 @@ OrderedJson::object SignEvent::buildEventJson(Project *) {
} }
bool SignEvent::loadFromJson(QJsonObject json, Project *) { bool SignEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setFacingDirection(json["player_facing_dir"].toString()); this->setFacingDirection(ParseUtil::jsonToQString(json["player_facing_dir"]));
this->setScriptLabel(json["script"].toString()); this->setScriptLabel(ParseUtil::jsonToQString(json["script"]));
this->readCustomValues(json); this->readCustomValues(json);
@ -746,16 +763,16 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) {
} }
bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setItem(json["item"].toString()); this->setItem(ParseUtil::jsonToQString(json["item"]));
this->setFlag(json["flag"].toString()); this->setFlag(ParseUtil::jsonToQString(json["flag"]));
if (projectConfig.getHiddenItemQuantityEnabled()) { if (projectConfig.getHiddenItemQuantityEnabled()) {
this->setQuantity(json["quantity"].toInt()); this->setQuantity(ParseUtil::jsonToInt(json["quantity"]));
} }
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
this->setUnderfoot(json["underfoot"].toBool()); this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"]));
} }
this->readCustomValues(json); this->readCustomValues(json);
@ -834,10 +851,10 @@ OrderedJson::object SecretBaseEvent::buildEventJson(Project *) {
} }
bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) { bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt()); this->setX(ParseUtil::jsonToInt(json["x"]));
this->setY(json["y"].toInt()); this->setY(ParseUtil::jsonToInt(json["y"]));
this->setElevation(json["elevation"].toInt()); this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
this->setBaseID(json["secret_base_id"].toString()); this->setBaseID(ParseUtil::jsonToQString(json["secret_base_id"]));
this->readCustomValues(json); this->readCustomValues(json);

View file

@ -310,10 +310,10 @@ void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata, bool
setNewDimensionsBlockdata(newWidth, newHeight); setNewDimensionsBlockdata(newWidth, newHeight);
} }
int oldWidth = layout->width.toInt(); int oldWidth = layout->width;
int oldHeight = layout->height.toInt(); int oldHeight = layout->height;
layout->width = QString::number(newWidth); layout->width = newWidth;
layout->height = QString::number(newHeight); layout->height = newHeight;
if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) { if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) {
Scripting::cb_MapResized(oldWidth, oldHeight, newWidth, newHeight); Scripting::cb_MapResized(oldWidth, oldHeight, newWidth, newHeight);
@ -328,10 +328,10 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata,
setNewBorderDimensionsBlockdata(newWidth, newHeight); setNewBorderDimensionsBlockdata(newWidth, newHeight);
} }
int oldWidth = layout->border_width.toInt(); int oldWidth = layout->border_width;
int oldHeight = layout->border_height.toInt(); int oldHeight = layout->border_height;
layout->border_width = QString::number(newWidth); layout->border_width = newWidth;
layout->border_height = QString::number(newHeight); layout->border_height = newHeight;
if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) { if (enableScriptCallback && (oldWidth != newWidth || oldHeight != newHeight)) {
Scripting::cb_BorderResized(oldWidth, oldHeight, newWidth, newHeight); Scripting::cb_BorderResized(oldWidth, oldHeight, newWidth, newHeight);

View file

@ -16,17 +16,17 @@ QString MapLayout::layoutConstantFromName(QString mapName) {
} }
int MapLayout::getWidth() { int MapLayout::getWidth() {
return width.toInt(nullptr, 0); return width;
} }
int MapLayout::getHeight() { int MapLayout::getHeight() {
return height.toInt(nullptr, 0); return height;
} }
int MapLayout::getBorderWidth() { int MapLayout::getBorderWidth() {
return border_width.toInt(nullptr, 0); return border_width;
} }
int MapLayout::getBorderHeight() { int MapLayout::getBorderHeight() {
return border_height.toInt(nullptr, 0); return border_height;
} }

View file

@ -70,10 +70,10 @@ MapLayout *MapParser::parse(QString filepath, bool *error, Project *project)
} }
MapLayout *mapLayout = new MapLayout(); MapLayout *mapLayout = new MapLayout();
mapLayout->width = QString::number(mapWidth); mapLayout->width = mapWidth;
mapLayout->height = QString::number(mapHeight); mapLayout->height = mapHeight;
mapLayout->border_width = (borderWidth == 0) ? QString::number(2) : QString::number(borderWidth); mapLayout->border_width = (borderWidth == 0) ? DEFAULT_BORDER_WIDTH : borderWidth;
mapLayout->border_height = (borderHeight == 0) ? QString::number(2) : QString::number(borderHeight); mapLayout->border_height = (borderHeight == 0) ? DEFAULT_BORDER_HEIGHT : borderHeight;
QList<QString> tilesets = project->tilesetLabelsOrdered; QList<QString> tilesets = project->tilesetLabelsOrdered;

View file

@ -404,13 +404,17 @@ QMap<QString, QString> ParseUtil::readNamedIndexCArray(const QString &filename,
return map; return map;
} }
bool ParseUtil::gameStringToBool(QString gameString, bool * ok) { int ParseUtil::gameStringToInt(QString gameString, bool * ok) {
if (ok) *ok = true; if (ok) *ok = true;
if (QString::compare(gameString, "TRUE", Qt::CaseInsensitive) == 0) if (QString::compare(gameString, "TRUE", Qt::CaseInsensitive) == 0)
return true; return 1;
if (QString::compare(gameString, "FALSE", Qt::CaseInsensitive) == 0) if (QString::compare(gameString, "FALSE", Qt::CaseInsensitive) == 0)
return false; return 0;
return gameString.toInt(ok) != 0; return gameString.toInt(ok);
}
bool ParseUtil::gameStringToBool(QString gameString, bool * ok) {
return gameStringToInt(gameString, ok) != 0;
} }
QMap<QString, QHash<QString, QString>> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash<int, QString> memberMap) { QMap<QString, QHash<QString, QString>> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash<int, QString> memberMap) {
@ -522,6 +526,48 @@ bool ParseUtil::ensureFieldsExist(const QJsonObject &obj, const QList<QString> &
return true; return true;
} }
// QJsonValues are strictly typed, and so will not attempt any implicit conversions.
// The below functions are for attempting to convert a JSON value read from the user's
// project to a QString, int, or bool (whichever Porymap expects).
QString ParseUtil::jsonToQString(QJsonValue value, bool * ok) {
if (ok) *ok = true;
switch (value.type())
{
case QJsonValue::String: return value.toString();
case QJsonValue::Double: return QString::number(value.toInt());
case QJsonValue::Bool: return QString::number(value.toBool());
default: break;
}
if (ok) *ok = false;
return QString();
}
int ParseUtil::jsonToInt(QJsonValue value, bool * ok) {
if (ok) *ok = true;
switch (value.type())
{
case QJsonValue::String: return ParseUtil::gameStringToInt(value.toString(), ok);
case QJsonValue::Double: return value.toInt();
case QJsonValue::Bool: return value.toBool();
default: break;
}
if (ok) *ok = false;
return 0;
}
bool ParseUtil::jsonToBool(QJsonValue value, bool * ok) {
if (ok) *ok = true;
switch (value.type())
{
case QJsonValue::String: return ParseUtil::gameStringToBool(value.toString(), ok);
case QJsonValue::Double: return value.toInt() != 0;
case QJsonValue::Bool: return value.toBool();
default: break;
}
if (ok) *ok = false;
return false;
}
int ParseUtil::getScriptLineNumber(const QString &filePath, const QString &scriptLabel) { int ParseUtil::getScriptLineNumber(const QString &filePath, const QString &scriptLabel) {
if (scriptLabel.isEmpty()) if (scriptLabel.isEmpty())
return 0; return 0;

View file

@ -10,6 +10,7 @@
#include "editcommands.h" #include "editcommands.h"
#include "config.h" #include "config.h"
#include "scripting.h" #include "scripting.h"
#include "customattributestable.h"
#include <QCheckBox> #include <QCheckBox>
#include <QPainter> #include <QPainter>
#include <QMouseEvent> #include <QMouseEvent>
@ -176,7 +177,7 @@ void Editor::setEditingConnections() {
bool controlsEnabled = selected_connection_item != nullptr; bool controlsEnabled = selected_connection_item != nullptr;
setConnectionEditControlsEnabled(controlsEnabled); setConnectionEditControlsEnabled(controlsEnabled);
if (selected_connection_item) { if (selected_connection_item) {
onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); onConnectionOffsetChanged(selected_connection_item->connection->offset);
setConnectionMap(selected_connection_item->connection->map_name); setConnectionMap(selected_connection_item->connection->map_name);
setCurrentConnectionDirection(selected_connection_item->connection->direction); setCurrentConnectionDirection(selected_connection_item->connection->direction);
} }
@ -774,7 +775,7 @@ void Editor::setCurrentConnectionDirection(QString curDirection) {
selected_connection_item->connection->direction = curDirection; selected_connection_item->connection->direction = curDirection;
QPixmap pixmap = connected_map->renderConnection(*selected_connection_item->connection, map->layout); QPixmap pixmap = connected_map->renderConnection(*selected_connection_item->connection, map->layout);
int offset = selected_connection_item->connection->offset.toInt(nullptr, 0); int offset = selected_connection_item->connection->offset;
selected_connection_item->initialOffset = offset; selected_connection_item->initialOffset = offset;
int x = 0, y = 0; int x = 0, y = 0;
if (selected_connection_item->connection->direction == "up") { if (selected_connection_item->connection->direction == "up") {
@ -820,7 +821,7 @@ void Editor::updateCurrentConnectionDirection(QString curDirection) {
void Editor::onConnectionMoved(MapConnection* connection) { void Editor::onConnectionMoved(MapConnection* connection) {
updateMirroredConnectionOffset(connection); updateMirroredConnectionOffset(connection);
onConnectionOffsetChanged(connection->offset.toInt()); onConnectionOffsetChanged(connection->offset);
maskNonVisibleConnectionTiles(); maskNonVisibleConnectionTiles();
} }
@ -834,7 +835,7 @@ void Editor::onConnectionOffsetChanged(int newOffset) {
void Editor::setConnectionEditControlValues(MapConnection* connection) { void Editor::setConnectionEditControlValues(MapConnection* connection) {
QString mapName = connection ? connection->map_name : ""; QString mapName = connection ? connection->map_name : "";
QString direction = connection ? connection->direction : ""; QString direction = connection ? connection->direction : "";
int offset = connection ? connection->offset.toInt() : 0; int offset = connection ? connection->offset : 0;
ui->comboBox_ConnectedMap->blockSignals(true); ui->comboBox_ConnectedMap->blockSignals(true);
ui->comboBox_ConnectionDirection->blockSignals(true); ui->comboBox_ConnectionDirection->blockSignals(true);
@ -883,7 +884,7 @@ void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) {
setConnectionEditControlValues(selected_connection_item->connection); setConnectionEditControlValues(selected_connection_item->connection);
ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset()); ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset());
ui->spinBox_ConnectionOffset->setMinimum(selected_connection_item->getMinOffset()); ui->spinBox_ConnectionOffset->setMinimum(selected_connection_item->getMinOffset());
onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt()); onConnectionOffsetChanged(selected_connection_item->connection->offset);
} }
void Editor::setSelectedConnectionFromMap(QString mapName) { void Editor::setSelectedConnectionFromMap(QString mapName) {
@ -1565,7 +1566,7 @@ void Editor::createConnectionItem(MapConnection* connection, bool hide) {
} }
QPixmap pixmap = connected_map->renderConnection(*connection, map->layout); QPixmap pixmap = connected_map->renderConnection(*connection, map->layout);
int offset = connection->offset.toInt(nullptr, 0); int offset = connection->offset;
int x = 0, y = 0; int x = 0, y = 0;
if (connection->direction == "up") { if (connection->direction == "up") {
x = offset * 16; x = offset * 16;
@ -1728,7 +1729,7 @@ void Editor::updateConnectionOffset(int offset) {
selected_connection_item->blockSignals(true); selected_connection_item->blockSignals(true);
offset = qMin(offset, selected_connection_item->getMaxOffset()); offset = qMin(offset, selected_connection_item->getMaxOffset());
offset = qMax(offset, selected_connection_item->getMinOffset()); offset = qMax(offset, selected_connection_item->getMinOffset());
selected_connection_item->connection->offset = QString::number(offset); selected_connection_item->connection->offset = offset;
if (selected_connection_item->connection->direction == "up" || selected_connection_item->connection->direction == "down") { if (selected_connection_item->connection->direction == "up" || selected_connection_item->connection->direction == "down") {
selected_connection_item->setX(selected_connection_item->initialX + (offset - selected_connection_item->initialOffset) * 16); selected_connection_item->setX(selected_connection_item->initialX + (offset - selected_connection_item->initialOffset) * 16);
} else if (selected_connection_item->connection->direction == "left" || selected_connection_item->connection->direction == "right") { } else if (selected_connection_item->connection->direction == "left" || selected_connection_item->connection->direction == "right") {
@ -1747,7 +1748,7 @@ void Editor::setConnectionMap(QString mapName) {
if (!selected_connection_item) if (!selected_connection_item)
return; return;
if (mapName.isEmpty() || mapName == NONE_MAP_NAME) { if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) {
removeCurrentConnection(); removeCurrentConnection();
return; return;
} }
@ -1783,7 +1784,7 @@ void Editor::addNewConnection() {
MapConnection* newConnection = new MapConnection; MapConnection* newConnection = new MapConnection;
newConnection->direction = minDirection; newConnection->direction = minDirection;
newConnection->offset = "0"; newConnection->offset = 0;
newConnection->map_name = defaultMapName; newConnection->map_name = defaultMapName;
map->connections.append(newConnection); map->connections.append(newConnection);
createConnectionItem(newConnection, true); createConnectionItem(newConnection, true);
@ -1851,7 +1852,7 @@ void Editor::updateMirroredConnection(MapConnection* connection, QString origina
otherMap->connections.append(mirrorConnection); otherMap->connections.append(mirrorConnection);
} }
mirrorConnection->offset = QString::number(-connection->offset.toInt()); mirrorConnection->offset = -connection->offset;
} }
void Editor::removeCurrentConnection() { void Editor::removeCurrentConnection() {
@ -1899,7 +1900,7 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
} }
} }
if (mapName.isEmpty() || mapName == NONE_MAP_NAME) { if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) {
// Remove dive/emerge connection // Remove dive/emerge connection
if (connection) { if (connection) {
map->connections.removeOne(connection); map->connections.removeOne(connection);
@ -1909,7 +1910,7 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
if (!connection) { if (!connection) {
connection = new MapConnection; connection = new MapConnection;
connection->direction = direction; connection->direction = direction;
connection->offset = "0"; connection->offset = 0;
connection->map_name = mapName; connection->map_name = mapName;
map->connections.append(connection); map->connections.append(connection);
updateMirroredConnection(connection, connection->direction, connection->map_name); updateMirroredConnection(connection, connection->direction, connection->map_name);
@ -1952,17 +1953,7 @@ void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback)
void Editor::updateCustomMapHeaderValues(QTableWidget *table) void Editor::updateCustomMapHeaderValues(QTableWidget *table)
{ {
QMap<QString, QString> fields; map->customHeaders = CustomAttributesTable::getAttributes(table);
for (int row = 0; row < table->rowCount(); row++) {
QString keyStr = "";
QString valueStr = "";
QTableWidgetItem *key = table->item(row, 0);
QTableWidgetItem *value = table->item(row, 1);
if (key) keyStr = key->text();
if (value) valueStr = value->text();
fields[keyStr] = valueStr;
}
map->customHeaders = fields;
emit editedMapData(); emit editedMapData();
} }

View file

@ -308,6 +308,33 @@ const Json & JsonArray::operator[] (int i) const {
else return m_value[i]; else return m_value[i];
} }
const Json Json::fromQJsonValue(QJsonValue value) {
switch (value.type())
{
default:
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::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;
}
}
}
/* * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * *
* Comparison * Comparison
*/ */

View file

@ -381,28 +381,28 @@ void MainWindow::setProjectSpecificUIVisibility()
case BaseGameVersion::pokeruby: case BaseGameVersion::pokeruby:
ui->checkBox_AllowRunning->setVisible(false); ui->checkBox_AllowRunning->setVisible(false);
ui->checkBox_AllowBiking->setVisible(false); ui->checkBox_AllowBiking->setVisible(false);
ui->checkBox_AllowEscapeRope->setVisible(false); ui->checkBox_AllowEscaping->setVisible(false);
ui->label_AllowRunning->setVisible(false); ui->label_AllowRunning->setVisible(false);
ui->label_AllowBiking->setVisible(false); ui->label_AllowBiking->setVisible(false);
ui->label_AllowEscapeRope->setVisible(false); ui->label_AllowEscaping->setVisible(false);
ui->actionRegion_Map_Editor->setVisible(true); ui->actionRegion_Map_Editor->setVisible(true);
break; break;
case BaseGameVersion::pokeemerald: case BaseGameVersion::pokeemerald:
ui->checkBox_AllowRunning->setVisible(true); ui->checkBox_AllowRunning->setVisible(true);
ui->checkBox_AllowBiking->setVisible(true); ui->checkBox_AllowBiking->setVisible(true);
ui->checkBox_AllowEscapeRope->setVisible(true); ui->checkBox_AllowEscaping->setVisible(true);
ui->label_AllowRunning->setVisible(true); ui->label_AllowRunning->setVisible(true);
ui->label_AllowBiking->setVisible(true); ui->label_AllowBiking->setVisible(true);
ui->label_AllowEscapeRope->setVisible(true); ui->label_AllowEscaping->setVisible(true);
ui->actionRegion_Map_Editor->setVisible(true); ui->actionRegion_Map_Editor->setVisible(true);
break; break;
case BaseGameVersion::pokefirered: case BaseGameVersion::pokefirered:
ui->checkBox_AllowRunning->setVisible(true); ui->checkBox_AllowRunning->setVisible(true);
ui->checkBox_AllowBiking->setVisible(true); ui->checkBox_AllowBiking->setVisible(true);
ui->checkBox_AllowEscapeRope->setVisible(true); ui->checkBox_AllowEscaping->setVisible(true);
ui->label_AllowRunning->setVisible(true); ui->label_AllowRunning->setVisible(true);
ui->label_AllowBiking->setVisible(true); ui->label_AllowBiking->setVisible(true);
ui->label_AllowEscapeRope->setVisible(true); ui->label_AllowEscaping->setVisible(true);
ui->actionRegion_Map_Editor->setVisible(true); ui->actionRegion_Map_Editor->setVisible(true);
break; break;
} }
@ -719,6 +719,10 @@ void MainWindow::refreshMapScene()
} }
void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_group) { void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_group) {
// Can't warp to dynamic maps
if (map_name == DYNAMIC_MAP_NAME)
return;
// Ensure valid destination map name. // Ensure valid destination map name.
if (!editor->project->mapNames.contains(map_name)) { if (!editor->project->mapNames.contains(map_name)) {
logError(QString("Invalid map name '%1'").arg(map_name)); logError(QString("Invalid map name '%1'").arg(map_name));
@ -737,10 +741,10 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_
} }
// Select the target event. // Select the target event.
event_id -= Event::getIndexOffset(event_group); int index = event_id - Event::getIndexOffset(event_group);
QList<Event*> events = editor->map->events[event_group]; QList<Event*> events = editor->map->events[event_group];
if (event_id < events.length() && event_id >= 0) { if (index < events.length() && index >= 0) {
Event *event = events.at(event_id); Event *event = events.at(index);
for (DraggablePixmapItem *item : editor->getObjects()) { for (DraggablePixmapItem *item : editor->getObjects()) {
if (item->event == event) { if (item->event == event) {
editor->selected_events->clear(); editor->selected_events->clear();
@ -748,6 +752,9 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_
editor->updateSelectedEvents(); editor->updateSelectedEvents();
} }
} }
} else {
// Can still warp to this map, but can't select the specified event
logWarn(QString("%1 %2 doesn't exist on map '%3'").arg(Event::eventGroupToString(event_group)).arg(event_id).arg(map_name));
} }
} }
@ -769,13 +776,13 @@ void MainWindow::displayMapProperties() {
const QSignalBlocker blockerA(ui->checkBox_AllowRunning); const QSignalBlocker blockerA(ui->checkBox_AllowRunning);
const QSignalBlocker blockerB(ui->checkBox_AllowBiking); const QSignalBlocker blockerB(ui->checkBox_AllowBiking);
const QSignalBlocker blockerC(ui->spinBox_FloorNumber); const QSignalBlocker blockerC(ui->spinBox_FloorNumber);
const QSignalBlocker blockerD(ui->checkBox_AllowEscapeRope); const QSignalBlocker blockerD(ui->checkBox_AllowEscaping);
ui->checkBox_Visibility->setChecked(false); ui->checkBox_Visibility->setChecked(false);
ui->checkBox_ShowLocation->setChecked(false); ui->checkBox_ShowLocation->setChecked(false);
ui->checkBox_AllowRunning->setChecked(false); ui->checkBox_AllowRunning->setChecked(false);
ui->checkBox_AllowBiking->setChecked(false); ui->checkBox_AllowBiking->setChecked(false);
ui->checkBox_AllowEscapeRope->setChecked(false); ui->checkBox_AllowEscaping->setChecked(false);
if (!editor || !editor->map || !editor->project) { if (!editor || !editor->map || !editor->project) {
ui->frame_3->setEnabled(false); ui->frame_3->setEnabled(false);
return; return;
@ -793,27 +800,24 @@ void MainWindow::displayMapProperties() {
ui->comboBox_Song->setCurrentText(map->song); ui->comboBox_Song->setCurrentText(map->song);
ui->comboBox_Location->setCurrentText(map->location); ui->comboBox_Location->setCurrentText(map->location);
ui->checkBox_Visibility->setChecked(ParseUtil::gameStringToBool(map->requiresFlash)); ui->checkBox_Visibility->setChecked(map->requiresFlash);
ui->comboBox_Weather->setCurrentText(map->weather); ui->comboBox_Weather->setCurrentText(map->weather);
ui->comboBox_Type->setCurrentText(map->type); ui->comboBox_Type->setCurrentText(map->type);
ui->comboBox_BattleScene->setCurrentText(map->battle_scene); ui->comboBox_BattleScene->setCurrentText(map->battle_scene);
ui->checkBox_ShowLocation->setChecked(ParseUtil::gameStringToBool(map->show_location)); ui->checkBox_ShowLocation->setChecked(map->show_location);
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
ui->checkBox_AllowRunning->setChecked(ParseUtil::gameStringToBool(map->allowRunning)); ui->checkBox_AllowRunning->setChecked(map->allowRunning);
ui->checkBox_AllowBiking->setChecked(ParseUtil::gameStringToBool(map->allowBiking)); ui->checkBox_AllowBiking->setChecked(map->allowBiking);
ui->checkBox_AllowEscapeRope->setChecked(ParseUtil::gameStringToBool(map->allowEscapeRope)); ui->checkBox_AllowEscaping->setChecked(map->allowEscaping);
} }
ui->spinBox_FloorNumber->setValue(map->floorNumber); ui->spinBox_FloorNumber->setValue(map->floorNumber);
// Custom fields table. // Custom fields table.
ui->tableWidget_CustomHeaderFields->blockSignals(true); ui->tableWidget_CustomHeaderFields->blockSignals(true);
ui->tableWidget_CustomHeaderFields->setRowCount(0); ui->tableWidget_CustomHeaderFields->setRowCount(0);
for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) { for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++)
int rowIndex = ui->tableWidget_CustomHeaderFields->rowCount(); CustomAttributesTable::addAttribute(ui->tableWidget_CustomHeaderFields, it.key(), it.value());
ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, new QTableWidgetItem(it.key()));
ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, new QTableWidgetItem(it.value()));
}
ui->tableWidget_CustomHeaderFields->blockSignals(false); ui->tableWidget_CustomHeaderFields->blockSignals(false);
} }
@ -860,12 +864,7 @@ void MainWindow::on_comboBox_BattleScene_currentTextChanged(const QString &battl
void MainWindow::on_checkBox_Visibility_stateChanged(int selected) void MainWindow::on_checkBox_Visibility_stateChanged(int selected)
{ {
if (editor && editor->map) { if (editor && editor->map) {
bool checked = selected == Qt::Checked; editor->map->requiresFlash = (selected == Qt::Checked);
if (checked) {
editor->map->requiresFlash = "TRUE";
} else {
editor->map->requiresFlash = "FALSE";
}
markMapEdited(); markMapEdited();
} }
} }
@ -873,12 +872,7 @@ void MainWindow::on_checkBox_Visibility_stateChanged(int selected)
void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected) void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected)
{ {
if (editor && editor->map) { if (editor && editor->map) {
bool checked = selected == Qt::Checked; editor->map->show_location = (selected == Qt::Checked);
if (checked) {
editor->map->show_location = "TRUE";
} else {
editor->map->show_location = "FALSE";
}
markMapEdited(); markMapEdited();
} }
} }
@ -886,12 +880,7 @@ void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected)
void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected) void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected)
{ {
if (editor && editor->map) { if (editor && editor->map) {
bool checked = selected == Qt::Checked; editor->map->allowRunning = (selected == Qt::Checked);
if (checked) {
editor->map->allowRunning = "1";
} else {
editor->map->allowRunning = "0";
}
markMapEdited(); markMapEdited();
} }
} }
@ -899,25 +888,15 @@ void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected)
void MainWindow::on_checkBox_AllowBiking_stateChanged(int selected) void MainWindow::on_checkBox_AllowBiking_stateChanged(int selected)
{ {
if (editor && editor->map) { if (editor && editor->map) {
bool checked = selected == Qt::Checked; editor->map->allowBiking = (selected == Qt::Checked);
if (checked) {
editor->map->allowBiking = "1";
} else {
editor->map->allowBiking = "0";
}
markMapEdited(); markMapEdited();
} }
} }
void MainWindow::on_checkBox_AllowEscapeRope_stateChanged(int selected) void MainWindow::on_checkBox_AllowEscaping_stateChanged(int selected)
{ {
if (editor && editor->map) { if (editor && editor->map) {
bool checked = selected == Qt::Checked; editor->map->allowEscaping = (selected == Qt::Checked);
if (checked) {
editor->map->allowEscapeRope = "1";
} else {
editor->map->allowEscapeRope = "0";
}
markMapEdited(); markMapEdited();
} }
} }
@ -1202,7 +1181,7 @@ void MainWindow::onNewMapCreated() {
sortMapList(); sortMapList();
setMap(newMapName, true); setMap(newMapName, true);
if (ParseUtil::gameStringToBool(newMap->isFlyable)) { if (newMap->needsHealLocation) {
addNewEvent(Event::Type::HealLocation); addNewEvent(Event::Type::HealLocation);
editor->project->saveHealLocations(newMap); editor->project->saveHealLocations(newMap);
editor->save(); editor->save();
@ -1605,8 +1584,8 @@ void MainWindow::paste() {
} }
QJsonArray metatilesArray = pasteObject["metatile_selection"].toArray(); QJsonArray metatilesArray = pasteObject["metatile_selection"].toArray();
QJsonArray collisionsArray = pasteObject["collision_selection"].toArray(); QJsonArray collisionsArray = pasteObject["collision_selection"].toArray();
int width = pasteObject["width"].toInt(); int width = ParseUtil::jsonToInt(pasteObject["width"]);
int height = pasteObject["height"].toInt(); int height = ParseUtil::jsonToInt(pasteObject["height"]);
QList<uint16_t> metatiles; QList<uint16_t> metatiles;
QList<QPair<uint16_t, uint16_t>> collisions; QList<QPair<uint16_t, uint16_t>> collisions;
for (auto tile : metatilesArray) { for (auto tile : metatilesArray) {
@ -1912,25 +1891,20 @@ void MainWindow::addNewEvent(Event::Type type) {
} }
} }
void MainWindow::tryAddEventTab(QWidget * tab, Event::Group group) {
if (editor->map->events.value(group).length())
ui->tabWidget_EventType->addTab(tab, QString("%1s").arg(Event::eventGroupToString(group)));
}
void MainWindow::displayEventTabs() { void MainWindow::displayEventTabs() {
const QSignalBlocker blocker(ui->tabWidget_EventType); const QSignalBlocker blocker(ui->tabWidget_EventType);
ui->tabWidget_EventType->clear(); ui->tabWidget_EventType->clear();
tryAddEventTab(eventTabObjectWidget, Event::Group::Object);
if (editor->map->events.value(Event::Group::Object).length()) tryAddEventTab(eventTabWarpWidget, Event::Group::Warp);
ui->tabWidget_EventType->addTab(eventTabObjectWidget, "Objects"); tryAddEventTab(eventTabTriggerWidget, Event::Group::Coord);
tryAddEventTab(eventTabBGWidget, Event::Group::Bg);
if (editor->map->events.value(Event::Group::Warp).length()) tryAddEventTab(eventTabHealspotWidget, Event::Group::Heal);
ui->tabWidget_EventType->addTab(eventTabWarpWidget, "Warps");
if (editor->map->events.value(Event::Group::Coord).length())
ui->tabWidget_EventType->addTab(eventTabTriggerWidget, "Triggers");
if (editor->map->events.value(Event::Group::Bg).length())
ui->tabWidget_EventType->addTab(eventTabBGWidget, "BGs");
if (editor->map->events.value(Event::Group::Heal).length())
ui->tabWidget_EventType->addTab(eventTabHealspotWidget, "Healspots");
} }
void MainWindow::updateObjects() { void MainWindow::updateObjects() {
@ -2785,33 +2759,18 @@ void MainWindow::togglePreferenceSpecificUi() {
void MainWindow::on_pushButton_AddCustomHeaderField_clicked() void MainWindow::on_pushButton_AddCustomHeaderField_clicked()
{ {
int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount(); bool ok;
this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex); QJsonValue value = CustomAttributesTable::pickType(this, &ok);
this->ui->tableWidget_CustomHeaderFields->selectRow(rowIndex); if (ok){
this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); CustomAttributesTable::addAttribute(this->ui->tableWidget_CustomHeaderFields, "", value, true);
this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
}
} }
void MainWindow::on_pushButton_DeleteCustomHeaderField_clicked() void MainWindow::on_pushButton_DeleteCustomHeaderField_clicked()
{ {
int rowCount = this->ui->tableWidget_CustomHeaderFields->rowCount(); if (CustomAttributesTable::deleteSelectedAttributes(this->ui->tableWidget_CustomHeaderFields))
if (rowCount > 0) {
QModelIndexList indexList = ui->tableWidget_CustomHeaderFields->selectionModel()->selectedIndexes();
QList<QPersistentModelIndex> persistentIndexes;
for (QModelIndex index : indexList) {
QPersistentModelIndex persistentIndex(index);
persistentIndexes.append(persistentIndex);
}
for (QPersistentModelIndex index : persistentIndexes) {
this->ui->tableWidget_CustomHeaderFields->removeRow(index.row());
}
if (this->ui->tableWidget_CustomHeaderFields->rowCount() > 0) {
this->ui->tableWidget_CustomHeaderFields->selectRow(0);
}
this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields); this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
}
} }
void MainWindow::on_tableWidget_CustomHeaderFields_cellChanged(int, int) void MainWindow::on_tableWidget_CustomHeaderFields_cellChanged(int, int)

View file

@ -142,36 +142,36 @@ void Project::setNewMapConnections(Map *map) {
map->connections.clear(); map->connections.clear();
} }
static QMap<QString, bool> defaultTopLevelMapFields { const QSet<QString> defaultTopLevelMapFields = {
{"id", true}, "id",
{"name", true}, "name",
{"layout", true}, "layout",
{"music", true}, "music",
{"region_map_section", true}, "region_map_section",
{"requires_flash", true}, "requires_flash",
{"weather", true}, "weather",
{"map_type", true}, "map_type",
{"show_map_name", true}, "show_map_name",
{"battle_scene", true}, "battle_scene",
{"connections", true}, "connections",
{"object_events", true}, "object_events",
{"warp_events", true}, "warp_events",
{"coord_events", true}, "coord_events",
{"bg_events", true}, "bg_events",
{"shared_events_map", true}, "shared_events_map",
{"shared_scripts_map", true}, "shared_scripts_map",
}; };
QMap<QString, bool> Project::getTopLevelMapFields() { QSet<QString> Project::getTopLevelMapFields() {
QMap<QString, bool> topLevelMapFields = defaultTopLevelMapFields; QSet<QString> topLevelMapFields = defaultTopLevelMapFields;
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
topLevelMapFields.insert("allow_cycling", true); topLevelMapFields.insert("allow_cycling");
topLevelMapFields.insert("allow_escaping", true); topLevelMapFields.insert("allow_escaping");
topLevelMapFields.insert("allow_running", true); topLevelMapFields.insert("allow_running");
} }
if (projectConfig.getFloorNumberEnabled()) { if (projectConfig.getFloorNumberEnabled()) {
topLevelMapFields.insert("floor_number", true); topLevelMapFields.insert("floor_number");
} }
return topLevelMapFields; return topLevelMapFields;
} }
@ -190,25 +190,25 @@ bool Project::loadMapData(Map* map) {
QJsonObject mapObj = mapDoc.object(); QJsonObject mapObj = mapDoc.object();
map->song = mapObj["music"].toString(); map->song = ParseUtil::jsonToQString(mapObj["music"]);
map->layoutId = mapObj["layout"].toString(); map->layoutId = ParseUtil::jsonToQString(mapObj["layout"]);
map->location = mapObj["region_map_section"].toString(); map->location = ParseUtil::jsonToQString(mapObj["region_map_section"]);
map->requiresFlash = QString::number(mapObj["requires_flash"].toBool()); map->requiresFlash = ParseUtil::jsonToBool(mapObj["requires_flash"]);
map->weather = mapObj["weather"].toString(); map->weather = ParseUtil::jsonToQString(mapObj["weather"]);
map->type = mapObj["map_type"].toString(); map->type = ParseUtil::jsonToQString(mapObj["map_type"]);
map->requiresFlash = QString::number(mapObj["requires_flash"].toBool()); map->show_location = ParseUtil::jsonToBool(mapObj["show_map_name"]);
map->show_location = QString::number(mapObj["show_map_name"].toBool()); map->battle_scene = ParseUtil::jsonToQString(mapObj["battle_scene"]);
map->battle_scene = mapObj["battle_scene"].toString();
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
map->allowBiking = QString::number(mapObj["allow_cycling"].toBool()); map->allowBiking = ParseUtil::jsonToBool(mapObj["allow_cycling"]);
map->allowEscapeRope = QString::number(mapObj["allow_escaping"].toBool()); map->allowEscaping = ParseUtil::jsonToBool(mapObj["allow_escaping"]);
map->allowRunning = QString::number(mapObj["allow_running"].toBool()); map->allowRunning = ParseUtil::jsonToBool(mapObj["allow_running"]);
} }
if (projectConfig.getFloorNumberEnabled()) { if (projectConfig.getFloorNumberEnabled()) {
map->floorNumber = mapObj["floor_number"].toInt(); map->floorNumber = ParseUtil::jsonToInt(mapObj["floor_number"]);
} }
map->sharedEventsMap = mapObj["shared_events_map"].toString(); map->sharedEventsMap = ParseUtil::jsonToQString(mapObj["shared_events_map"]);
map->sharedScriptsMap = mapObj["shared_scripts_map"].toString(); map->sharedScriptsMap = ParseUtil::jsonToQString(mapObj["shared_scripts_map"]);
// Events // Events
map->events[Event::Group::Object].clear(); map->events[Event::Group::Object].clear();
@ -217,7 +217,7 @@ bool Project::loadMapData(Map* map) {
for (int i = 0; i < objectEventsArr.size(); i++) { for (int i = 0; i < objectEventsArr.size(); i++) {
QJsonObject event = objectEventsArr[i].toObject(); QJsonObject event = objectEventsArr[i].toObject();
// If clone objects are not enabled then no type field is present // If clone objects are not enabled then no type field is present
QString type = hasCloneObjects ? event["type"].toString() : "object"; QString type = hasCloneObjects ? ParseUtil::jsonToQString(event["type"]) : "object";
if (type.isEmpty() || type == "object") { if (type.isEmpty() || type == "object") {
ObjectEvent *object = new ObjectEvent(); ObjectEvent *object = new ObjectEvent();
object->loadFromJson(event, this); object->loadFromJson(event, this);
@ -252,7 +252,7 @@ bool Project::loadMapData(Map* map) {
QJsonArray coordEventsArr = mapObj["coord_events"].toArray(); QJsonArray coordEventsArr = mapObj["coord_events"].toArray();
for (int i = 0; i < coordEventsArr.size(); i++) { for (int i = 0; i < coordEventsArr.size(); i++) {
QJsonObject event = coordEventsArr[i].toObject(); QJsonObject event = coordEventsArr[i].toObject();
QString type = event["type"].toString(); QString type = ParseUtil::jsonToQString(event["type"]);
if (type == "trigger") { if (type == "trigger") {
TriggerEvent *coord = new TriggerEvent(); TriggerEvent *coord = new TriggerEvent();
coord->loadFromJson(event, this); coord->loadFromJson(event, this);
@ -270,7 +270,7 @@ bool Project::loadMapData(Map* map) {
QJsonArray bgEventsArr = mapObj["bg_events"].toArray(); QJsonArray bgEventsArr = mapObj["bg_events"].toArray();
for (int i = 0; i < bgEventsArr.size(); i++) { for (int i = 0; i < bgEventsArr.size(); i++) {
QJsonObject event = bgEventsArr[i].toObject(); QJsonObject event = bgEventsArr[i].toObject();
QString type = event["type"].toString(); QString type = ParseUtil::jsonToQString(event["type"]);
if (type == "sign") { if (type == "sign") {
SignEvent *bg = new SignEvent(); SignEvent *bg = new SignEvent();
bg->loadFromJson(event, this); bg->loadFromJson(event, this);
@ -319,9 +319,9 @@ bool Project::loadMapData(Map* map) {
for (int i = 0; i < connectionsArr.size(); i++) { for (int i = 0; i < connectionsArr.size(); i++) {
QJsonObject connectionObj = connectionsArr[i].toObject(); QJsonObject connectionObj = connectionsArr[i].toObject();
MapConnection *connection = new MapConnection; MapConnection *connection = new MapConnection;
connection->direction = connectionObj["direction"].toString(); connection->direction = ParseUtil::jsonToQString(connectionObj["direction"]);
connection->offset = QString::number(connectionObj["offset"].toInt()); connection->offset = ParseUtil::jsonToInt(connectionObj["offset"]);
QString mapConstant = connectionObj["map"].toString(); QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]);
if (mapConstantsToMapNames.contains(mapConstant)) { if (mapConstantsToMapNames.contains(mapConstant)) {
connection->map_name = mapConstantsToMapNames.value(mapConstant); connection->map_name = mapConstantsToMapNames.value(mapConstant);
map->connections.append(connection); map->connections.append(connection);
@ -332,10 +332,10 @@ bool Project::loadMapData(Map* map) {
} }
// Check for custom fields // Check for custom fields
QMap<QString, bool> baseFields = this->getTopLevelMapFields(); QSet<QString> baseFields = this->getTopLevelMapFields();
for (QString key : mapObj.keys()) { for (QString key : mapObj.keys()) {
if (!baseFields.contains(key)) { if (!baseFields.contains(key)) {
map->customHeaders.insert(key, mapObj[key].toString()); map->customHeaders.insert(key, mapObj[key]);
} }
} }
@ -355,7 +355,7 @@ QString Project::readMapLayoutId(QString map_name) {
} }
QJsonObject mapObj = mapDoc.object(); QJsonObject mapObj = mapDoc.object();
return mapObj["layout"].toString(); return ParseUtil::jsonToQString(mapObj["layout"]);
} }
QString Project::readMapLocation(QString map_name) { QString Project::readMapLocation(QString map_name) {
@ -371,23 +371,21 @@ QString Project::readMapLocation(QString map_name) {
} }
QJsonObject mapObj = mapDoc.object(); QJsonObject mapObj = mapDoc.object();
return mapObj["region_map_section"].toString(); return ParseUtil::jsonToQString(mapObj["region_map_section"]);
} }
void Project::setNewMapHeader(Map* map, int mapIndex) { void Project::setNewMapHeader(Map* map, int mapIndex) {
map->layoutId = QString("%1").arg(mapIndex); map->layoutId = QString("%1").arg(mapIndex);
map->location = mapSectionValueToName.value(0); map->location = mapSectionValueToName.value(0);
map->requiresFlash = "FALSE"; map->requiresFlash = false;
map->weather = weatherNames.value(0, "WEATHER_NONE"); map->weather = weatherNames.value(0, "WEATHER_NONE");
map->type = mapTypes.value(0, "MAP_TYPE_NONE"); map->type = mapTypes.value(0, "MAP_TYPE_NONE");
map->song = defaultSong; map->song = defaultSong;
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { map->show_location = true;
map->show_location = "TRUE"; if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
} else { map->allowBiking = true;
map->allowBiking = "1"; map->allowEscaping = false;
map->allowEscapeRope = "0"; map->allowRunning = true;
map->allowRunning = "1";
map->show_location = "1";
} }
if (projectConfig.getFloorNumberEnabled()) { if (projectConfig.getFloorNumberEnabled()) {
map->floorNumber = 0; map->floorNumber = 0;
@ -445,7 +443,7 @@ bool Project::readMapLayouts() {
return false; return false;
} }
layoutsLabel = layoutsObj["layouts_table_label"].toString(); layoutsLabel = ParseUtil::jsonToQString(layoutsObj["layouts_table_label"]);
if (layoutsLabel.isNull()) { if (layoutsLabel.isNull()) {
layoutsLabel = "gMapLayouts"; layoutsLabel = "gMapLayouts";
logWarn(QString("'layouts_table_label' value is missing from %1. Defaulting to %2") logWarn(QString("'layouts_table_label' value is missing from %1. Defaulting to %2")
@ -477,61 +475,61 @@ bool Project::readMapLayouts() {
return false; return false;
} }
MapLayout *layout = new MapLayout(); MapLayout *layout = new MapLayout();
layout->id = layoutObj["id"].toString(); layout->id = ParseUtil::jsonToQString(layoutObj["id"]);
if (layout->id.isEmpty()) { if (layout->id.isEmpty()) {
logError(QString("Missing 'id' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); logError(QString("Missing 'id' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
return false; return false;
} }
layout->name = layoutObj["name"].toString(); layout->name = ParseUtil::jsonToQString(layoutObj["name"]);
if (layout->name.isEmpty()) { if (layout->name.isEmpty()) {
logError(QString("Missing 'name' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); logError(QString("Missing 'name' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
return false; return false;
} }
int lwidth = layoutObj["width"].toInt(); int lwidth = ParseUtil::jsonToInt(layoutObj["width"]);
if (lwidth <= 0) { if (lwidth <= 0) {
logError(QString("Invalid layout 'width' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lwidth).arg(i).arg(layoutsFilepath)); logError(QString("Invalid layout 'width' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lwidth).arg(i).arg(layoutsFilepath));
return false; return false;
} }
layout->width = QString::number(lwidth); layout->width = lwidth;
int lheight = layoutObj["height"].toInt(); int lheight = ParseUtil::jsonToInt(layoutObj["height"]);
if (lheight <= 0) { if (lheight <= 0) {
logError(QString("Invalid layout 'height' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lheight).arg(i).arg(layoutsFilepath)); logError(QString("Invalid layout 'height' value '%1' on layout %2 in %3. Must be greater than 0.").arg(lheight).arg(i).arg(layoutsFilepath));
return false; return false;
} }
layout->height = QString::number(lheight); layout->height = lheight;
if (useCustomBorderSize) { if (useCustomBorderSize) {
int bwidth = layoutObj["border_width"].toInt(); int bwidth = ParseUtil::jsonToInt(layoutObj["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 if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG
logWarn(QString("Invalid layout 'border_width' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bwidth).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_WIDTH)); logWarn(QString("Invalid layout 'border_width' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bwidth).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_WIDTH));
bwidth = DEFAULT_BORDER_WIDTH; bwidth = DEFAULT_BORDER_WIDTH;
} }
layout->border_width = QString::number(bwidth); layout->border_width = bwidth;
int bheight = layoutObj["border_height"].toInt(); int bheight = ParseUtil::jsonToInt(layoutObj["border_height"]);
if (bheight <= 0) { if (bheight <= 0) {
logWarn(QString("Invalid layout 'border_height' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT)); logWarn(QString("Invalid layout 'border_height' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT));
bheight = DEFAULT_BORDER_HEIGHT; bheight = DEFAULT_BORDER_HEIGHT;
} }
layout->border_height = QString::number(bheight); layout->border_height = bheight;
} else { } else {
layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); layout->border_width = DEFAULT_BORDER_WIDTH;
layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); layout->border_height = DEFAULT_BORDER_HEIGHT;
} }
layout->tileset_primary_label = layoutObj["primary_tileset"].toString(); layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj["primary_tileset"]);
if (layout->tileset_primary_label.isEmpty()) { if (layout->tileset_primary_label.isEmpty()) {
logError(QString("Missing 'primary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); logError(QString("Missing 'primary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
return false; return false;
} }
layout->tileset_secondary_label = layoutObj["secondary_tileset"].toString(); layout->tileset_secondary_label = ParseUtil::jsonToQString(layoutObj["secondary_tileset"]);
if (layout->tileset_secondary_label.isEmpty()) { if (layout->tileset_secondary_label.isEmpty()) {
logError(QString("Missing 'secondary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); logError(QString("Missing 'secondary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
return false; return false;
} }
layout->border_path = layoutObj["border_filepath"].toString(); layout->border_path = ParseUtil::jsonToQString(layoutObj["border_filepath"]);
if (layout->border_path.isEmpty()) { if (layout->border_path.isEmpty()) {
logError(QString("Missing 'border_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); logError(QString("Missing 'border_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
return false; return false;
} }
layout->blockdata_path = layoutObj["blockdata_filepath"].toString(); layout->blockdata_path = ParseUtil::jsonToQString(layoutObj["blockdata_filepath"]);
if (layout->blockdata_path.isEmpty()) { if (layout->blockdata_path.isEmpty()) {
logError(QString("Missing 'blockdata_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); logError(QString("Missing 'blockdata_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
return false; return false;
@ -566,11 +564,11 @@ void Project::saveMapLayouts() {
OrderedJson::object layoutObj; OrderedJson::object layoutObj;
layoutObj["id"] = layout->id; layoutObj["id"] = layout->id;
layoutObj["name"] = layout->name; layoutObj["name"] = layout->name;
layoutObj["width"] = layout->width.toInt(nullptr, 0); layoutObj["width"] = layout->width;
layoutObj["height"] = layout->height.toInt(nullptr, 0); layoutObj["height"] = layout->height;
if (useCustomBorderSize) { if (useCustomBorderSize) {
layoutObj["border_width"] = layout->border_width.toInt(nullptr, 0); layoutObj["border_width"] = layout->border_width;
layoutObj["border_height"] = layout->border_height.toInt(nullptr, 0); layoutObj["border_height"] = layout->border_height;
} }
layoutObj["primary_tileset"] = layout->tileset_primary_label; layoutObj["primary_tileset"] = layout->tileset_primary_label;
layoutObj["secondary_tileset"] = layout->tileset_secondary_label; layoutObj["secondary_tileset"] = layout->tileset_secondary_label;
@ -597,10 +595,10 @@ void Project::setNewMapLayout(Map* map) {
MapLayout *layout = new MapLayout(); MapLayout *layout = new MapLayout();
layout->id = MapLayout::layoutConstantFromName(map->name); layout->id = MapLayout::layoutConstantFromName(map->name);
layout->name = QString("%1_Layout").arg(map->name); layout->name = QString("%1_Layout").arg(map->name);
layout->width = QString::number(getDefaultMapSize()); layout->width = getDefaultMapSize();
layout->height = QString::number(getDefaultMapSize()); layout->height = getDefaultMapSize();
layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); layout->border_width = DEFAULT_BORDER_WIDTH;
layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); layout->border_height = DEFAULT_BORDER_HEIGHT;
layout->border_path = QString("%2%1/border.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders)); layout->border_path = QString("%2%1/border.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders));
layout->blockdata_path = QString("%2%1/map.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders)); layout->blockdata_path = QString("%2%1/map.bin").arg(map->name).arg(projectConfig.getFilePath(ProjectFilePath::data_layouts_folders));
layout->tileset_primary_label = tilesetLabels["primary"].value(0, "gTileset_General"); layout->tileset_primary_label = tilesetLabels["primary"].value(0, "gTileset_General");
@ -1254,11 +1252,11 @@ void Project::saveMap(Map *map) {
QJsonObject newLayoutObj; QJsonObject newLayoutObj;
newLayoutObj["id"] = map->layout->id; newLayoutObj["id"] = map->layout->id;
newLayoutObj["name"] = map->layout->name; newLayoutObj["name"] = map->layout->name;
newLayoutObj["width"] = map->layout->width.toInt(); newLayoutObj["width"] = map->layout->width;
newLayoutObj["height"] = map->layout->height.toInt(); newLayoutObj["height"] = map->layout->height;
if (projectConfig.getUseCustomBorderSize()) { if (projectConfig.getUseCustomBorderSize()) {
newLayoutObj["border_width"] = map->layout->border_width.toInt(); newLayoutObj["border_width"] = map->layout->border_width;
newLayoutObj["border_height"] = map->layout->border_height.toInt(); newLayoutObj["border_height"] = map->layout->border_height;
} }
newLayoutObj["primary_tileset"] = map->layout->tileset_primary_label; newLayoutObj["primary_tileset"] = map->layout->tileset_primary_label;
newLayoutObj["secondary_tileset"] = map->layout->tileset_secondary_label; newLayoutObj["secondary_tileset"] = map->layout->tileset_secondary_label;
@ -1283,15 +1281,15 @@ void Project::saveMap(Map *map) {
mapObj["layout"] = map->layout->id; mapObj["layout"] = map->layout->id;
mapObj["music"] = map->song; mapObj["music"] = map->song;
mapObj["region_map_section"] = map->location; mapObj["region_map_section"] = map->location;
mapObj["requires_flash"] = ParseUtil::gameStringToBool(map->requiresFlash); mapObj["requires_flash"] = map->requiresFlash;
mapObj["weather"] = map->weather; mapObj["weather"] = map->weather;
mapObj["map_type"] = map->type; mapObj["map_type"] = map->type;
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
mapObj["allow_cycling"] = ParseUtil::gameStringToBool(map->allowBiking); mapObj["allow_cycling"] = map->allowBiking;
mapObj["allow_escaping"] = ParseUtil::gameStringToBool(map->allowEscapeRope); mapObj["allow_escaping"] = map->allowEscaping;
mapObj["allow_running"] = ParseUtil::gameStringToBool(map->allowRunning); mapObj["allow_running"] = map->allowRunning;
} }
mapObj["show_map_name"] = ParseUtil::gameStringToBool(map->show_location); mapObj["show_map_name"] = map->show_location;
if (projectConfig.getFloorNumberEnabled()) { if (projectConfig.getFloorNumberEnabled()) {
mapObj["floor_number"] = map->floorNumber; mapObj["floor_number"] = map->floorNumber;
} }
@ -1304,7 +1302,7 @@ void Project::saveMap(Map *map) {
if (mapNamesToMapConstants.contains(connection->map_name)) { if (mapNamesToMapConstants.contains(connection->map_name)) {
OrderedJson::object connectionObj; OrderedJson::object connectionObj;
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name); connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name);
connectionObj["offset"] = connection->offset.toInt(); connectionObj["offset"] = connection->offset;
connectionObj["direction"] = connection->direction; connectionObj["direction"] = connection->direction;
connectionsArr.append(connectionObj); connectionsArr.append(connectionObj);
} else { } else {
@ -1363,7 +1361,7 @@ void Project::saveMap(Map *map) {
// Custom header fields. // Custom header fields.
for (QString key : map->customHeaders.keys()) { for (QString key : map->customHeaders.keys()) {
mapObj[key] = map->customHeaders[key]; mapObj[key] = OrderedJson::fromQJsonValue(map->customHeaders[key]);
} }
OrderedJson mapJson(mapObj); OrderedJson mapJson(mapObj);
@ -1765,12 +1763,12 @@ bool Project::readMapGroups() {
QStringList maps; QStringList maps;
QStringList groups; QStringList groups;
for (int groupIndex = 0; groupIndex < mapGroupOrder.size(); groupIndex++) { for (int groupIndex = 0; groupIndex < mapGroupOrder.size(); groupIndex++) {
QString groupName = mapGroupOrder.at(groupIndex).toString(); QString groupName = ParseUtil::jsonToQString(mapGroupOrder.at(groupIndex));
QJsonArray mapNames = mapGroupsObj.value(groupName).toArray(); QJsonArray mapNames = mapGroupsObj.value(groupName).toArray();
groupedMaps.append(QStringList()); groupedMaps.append(QStringList());
groups.append(groupName); groups.append(groupName);
for (int j = 0; j < mapNames.size(); j++) { for (int j = 0; j < mapNames.size(); j++) {
QString mapName = mapNames.at(j).toString(); QString mapName = ParseUtil::jsonToQString(mapNames.at(j));
mapGroups.insert(mapName, groupIndex); mapGroups.insert(mapName, groupIndex);
groupedMaps[groupIndex].append(mapName); groupedMaps[groupIndex].append(mapName);
maps.append(mapName); maps.append(mapName);
@ -1782,9 +1780,9 @@ bool Project::readMapGroups() {
} }
} }
mapConstantsToMapNames.insert(NONE_MAP_CONSTANT, NONE_MAP_NAME); mapConstantsToMapNames.insert(DYNAMIC_MAP_CONSTANT, DYNAMIC_MAP_NAME);
mapNamesToMapConstants.insert(NONE_MAP_NAME, NONE_MAP_CONSTANT); mapNamesToMapConstants.insert(DYNAMIC_MAP_NAME, DYNAMIC_MAP_CONSTANT);
maps.append(NONE_MAP_NAME); maps.append(DYNAMIC_MAP_NAME);
groupNames = groups; groupNames = groups;
groupedMapNames = groupedMaps; groupedMapNames = groupedMaps;

View file

@ -831,7 +831,7 @@ void MainWindow::setLocation(QString location) {
bool MainWindow::getRequiresFlash() { bool MainWindow::getRequiresFlash() {
if (!this->editor || !this->editor->map) if (!this->editor || !this->editor->map)
return false; return false;
return ParseUtil::gameStringToBool(this->editor->map->requiresFlash); return this->editor->map->requiresFlash;
} }
void MainWindow::setRequiresFlash(bool require) { void MainWindow::setRequiresFlash(bool require) {
@ -891,7 +891,7 @@ void MainWindow::setBattleScene(QString battleScene) {
bool MainWindow::getShowLocationName() { bool MainWindow::getShowLocationName() {
if (!this->editor || !this->editor->map) if (!this->editor || !this->editor->map)
return false; return false;
return ParseUtil::gameStringToBool(this->editor->map->show_location); return this->editor->map->show_location;
} }
void MainWindow::setShowLocationName(bool show) { void MainWindow::setShowLocationName(bool show) {
@ -903,7 +903,7 @@ void MainWindow::setShowLocationName(bool show) {
bool MainWindow::getAllowRunning() { bool MainWindow::getAllowRunning() {
if (!this->editor || !this->editor->map) if (!this->editor || !this->editor->map)
return false; return false;
return ParseUtil::gameStringToBool(this->editor->map->allowRunning); return this->editor->map->allowRunning;
} }
void MainWindow::setAllowRunning(bool allow) { void MainWindow::setAllowRunning(bool allow) {
@ -915,7 +915,7 @@ void MainWindow::setAllowRunning(bool allow) {
bool MainWindow::getAllowBiking() { bool MainWindow::getAllowBiking() {
if (!this->editor || !this->editor->map) if (!this->editor || !this->editor->map)
return false; return false;
return ParseUtil::gameStringToBool(this->editor->map->allowBiking); return this->editor->map->allowBiking;
} }
void MainWindow::setAllowBiking(bool allow) { void MainWindow::setAllowBiking(bool allow) {
@ -927,13 +927,13 @@ void MainWindow::setAllowBiking(bool allow) {
bool MainWindow::getAllowEscaping() { bool MainWindow::getAllowEscaping() {
if (!this->editor || !this->editor->map) if (!this->editor || !this->editor->map)
return false; return false;
return ParseUtil::gameStringToBool(this->editor->map->allowEscapeRope); return this->editor->map->allowEscaping;
} }
void MainWindow::setAllowEscaping(bool allow) { void MainWindow::setAllowEscaping(bool allow) {
if (!this->ui) if (!this->ui)
return; return;
this->ui->checkBox_AllowEscapeRope->setChecked(allow); this->ui->checkBox_AllowEscaping->setChecked(allow);
} }
int MainWindow::getFloorNumber() { int MainWindow::getFloorNumber() {

View file

@ -56,7 +56,7 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
y = this->initialY; y = this->initialY;
} }
this->connection->offset = QString::number(newOffset); this->connection->offset = newOffset;
emit connectionMoved(this->connection); emit connectionMoved(this->connection);
return QPointF(x, y); return QPointF(x, y);
} }

View file

@ -1,10 +1,12 @@
#include "customattributestable.h" #include "customattributestable.h"
#include "parseutil.h"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QPushButton> #include <QPushButton>
#include <QTableWidget> #include <QTableWidget>
#include <QLabel> #include <QLabel>
#include <QScrollBar> #include <QScrollBar>
#include <QInputDialog>
CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) : CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
QFrame(parent) QFrame(parent)
@ -28,52 +30,34 @@ CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
layout->addWidget(buttonsFrame); layout->addWidget(buttonsFrame);
this->table = new QTableWidget(this); this->table = new QTableWidget(this);
this->table->setColumnCount(2); this->table->setColumnCount(3);
this->table->setHorizontalHeaderLabels(QStringList({"Key", "Value"})); this->table->setHorizontalHeaderLabels(QStringList({"Type", "Key", "Value"}));
this->table->horizontalHeader()->setStretchLastSection(true); this->table->horizontalHeader()->setStretchLastSection(true);
layout->addWidget(this->table); layout->addWidget(this->table);
QMap<QString, QString> customValues = this->event->getCustomValues(); QMap<QString, QJsonValue> customValues = this->event->getCustomValues();
for (auto it = customValues.begin(); it != customValues.end(); it++) { for (auto it = customValues.begin(); it != customValues.end(); it++)
int rowIndex = this->table->rowCount(); CustomAttributesTable::addAttribute(this->table, it.key(), it.value());
this->table->insertRow(rowIndex);
this->table->setItem(rowIndex, 0, new QTableWidgetItem(it.key()));
this->table->setItem(rowIndex, 1, new QTableWidgetItem(it.value()));
}
connect(addButton, &QPushButton::clicked, [=]() { connect(addButton, &QPushButton::clicked, [=]() {
int rowIndex = this->table->rowCount(); bool ok;
this->table->insertRow(rowIndex); QJsonValue value = CustomAttributesTable::pickType(this, &ok);
this->table->selectRow(rowIndex); if (ok){
this->event->setCustomValues(this->getTableFields()); CustomAttributesTable::addAttribute(this->table, "", value, true);
this->resizeVertically(); this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
this->resizeVertically();
}
}); });
connect(deleteButton, &QPushButton::clicked, [=]() { connect(deleteButton, &QPushButton::clicked, [=]() {
int rowCount = this->table->rowCount(); if (CustomAttributesTable::deleteSelectedAttributes(this->table)) {
if (rowCount > 0) { this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
QModelIndexList indexList = this->table->selectionModel()->selectedIndexes();
QList<QPersistentModelIndex> persistentIndexes;
for (QModelIndex index : indexList) {
QPersistentModelIndex persistentIndex(index);
persistentIndexes.append(persistentIndex);
}
for (QPersistentModelIndex index : persistentIndexes) {
this->table->removeRow(index.row());
}
if (this->table->rowCount() > 0) {
this->table->selectRow(0);
}
this->event->setCustomValues(this->getTableFields());
this->resizeVertically(); this->resizeVertically();
} }
}); });
connect(this->table, &QTableWidget::cellChanged, [=]() { connect(this->table, &QTableWidget::cellChanged, [=]() {
this->event->setCustomValues(this->getTableFields()); this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
}); });
this->resizeVertically(); this->resizeVertically();
@ -83,20 +67,6 @@ CustomAttributesTable::~CustomAttributesTable()
{ {
} }
QMap<QString, QString> CustomAttributesTable::getTableFields() {
QMap<QString, QString> fields;
for (int row = 0; row < table->rowCount(); row++) {
QString keyStr = "";
QString valueStr = "";
QTableWidgetItem *key = table->item(row, 0);
QTableWidgetItem *value = table->item(row, 1);
if (key) keyStr = key->text();
if (value) valueStr = value->text();
fields[keyStr] = valueStr;
}
return fields;
}
void CustomAttributesTable::resizeVertically() { void CustomAttributesTable::resizeVertically() {
int horizontalHeaderHeight = this->table->horizontalHeader()->height(); int horizontalHeaderHeight = this->table->horizontalHeader()->height();
int rowHeight = 0; int rowHeight = 0;
@ -112,3 +82,125 @@ void CustomAttributesTable::resizeVertically() {
this->table->setMinimumHeight(totalHeight); this->table->setMinimumHeight(totalHeight);
this->table->setMaximumHeight(totalHeight); this->table->setMaximumHeight(totalHeight);
} }
const QMap<QString, QJsonValue> CustomAttributesTable::getAttributes(QTableWidget * table) {
QMap<QString, QJsonValue> fields;
if (!table) return fields;
for (int row = 0; row < table->rowCount(); row++) {
QString key = "";
QTableWidgetItem *typeItem = table->item(row, 0);
QTableWidgetItem *keyItem = table->item(row, 1);
QTableWidgetItem *valueItem = table->item(row, 2);
if (keyItem) key = keyItem->text();
if (key.isEmpty() || !typeItem || !valueItem)
continue;
// Read from the table data which JSON type to save the value as
QJsonValue::Type type = static_cast<QJsonValue::Type>(typeItem->data(Qt::UserRole).toInt());
QJsonValue value;
switch (type)
{
case QJsonValue::String:
value = QJsonValue(valueItem->text());
break;
case QJsonValue::Double:
value = QJsonValue(valueItem->text().toInt());
break;
case QJsonValue::Bool:
value = QJsonValue(valueItem->checkState() == Qt::Checked);
break;
default:
// All other types will just be preserved
value = valueItem->data(Qt::UserRole).toJsonValue();
break;
}
fields[key] = value;
}
return fields;
}
QJsonValue CustomAttributesTable::pickType(QWidget * parent, bool * ok) {
const QMap<QString, QJsonValue> valueTypes = {
{"String", QJsonValue(QString(""))},
{"Number", QJsonValue(0)},
{"Boolean", QJsonValue(false)},
};
QStringList typeNames = valueTypes.keys();
QString selection = QInputDialog::getItem(parent, "", "Choose Value Type", typeNames, typeNames.indexOf("String"), false, ok);
return valueTypes.value(selection);
}
void CustomAttributesTable::addAttribute(QTableWidget * table, QString key, QJsonValue value, bool isNew) {
if (!table) return;
QTableWidgetItem * valueItem;
QJsonValue::Type type = value.type();
switch (type)
{
case QJsonValue::String:
case QJsonValue::Double:
valueItem = new QTableWidgetItem(ParseUtil::jsonToQString(value));
break;
case QJsonValue::Bool:
valueItem = new QTableWidgetItem("");
valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked);
valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
break;
default:
valueItem = new QTableWidgetItem("This value cannot be edited from this table");
valueItem->setFlags(Qt::ItemIsSelectable);
valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file
break;
}
const QHash<QJsonValue::Type, QString> typeToName = {
{QJsonValue::Bool, "Bool"},
{QJsonValue::Double, "Number"},
{QJsonValue::String, "String"},
{QJsonValue::Array, "Array"},
{QJsonValue::Object, "Object"},
{QJsonValue::Null, "Null"},
{QJsonValue::Undefined, "Null"},
};
QTableWidgetItem * typeItem = new QTableWidgetItem(typeToName[type]);
typeItem->setFlags(Qt::ItemIsEnabled);
typeItem->setData(Qt::UserRole, type); // Record the type for writing to the file
typeItem->setTextAlignment(Qt::AlignCenter);
int rowIndex = table->rowCount();
table->insertRow(rowIndex);
table->setItem(rowIndex, 0, typeItem);
table->setItem(rowIndex, 1, new QTableWidgetItem(key));
table->setItem(rowIndex, 2, valueItem);
if (isNew) {
valueItem->setText(""); // Erase the "0" in new numbers
table->selectRow(rowIndex);
}
}
bool CustomAttributesTable::deleteSelectedAttributes(QTableWidget * table) {
if (!table)
return false;
int rowCount = table->rowCount();
if (rowCount <= 0)
return false;
QModelIndexList indexList = table->selectionModel()->selectedIndexes();
QList<QPersistentModelIndex> persistentIndexes;
for (QModelIndex index : indexList) {
QPersistentModelIndex persistentIndex(index);
persistentIndexes.append(persistentIndex);
}
for (QPersistentModelIndex index : persistentIndexes) {
table->removeRow(index.row());
}
if (table->rowCount() > 0) {
table->selectRow(0);
}
return true;
}

View file

@ -85,23 +85,17 @@ void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
if (eventType == Event::Type::Warp) { if (eventType == Event::Type::Warp) {
WarpEvent *warp = dynamic_cast<WarpEvent *>(this->event); WarpEvent *warp = dynamic_cast<WarpEvent *>(this->event);
QString destMap = warp->getDestinationMap(); QString destMap = warp->getDestinationMap();
if (destMap != NONE_MAP_NAME) { int warpId = ParseUtil::gameStringToInt(warp->getDestinationWarpID());
emit editor->warpEventDoubleClicked(destMap, warp->getDestinationWarpID(), Event::Group::Warp); emit editor->warpEventDoubleClicked(destMap, warpId, Event::Group::Warp);
}
} }
else if (eventType == Event::Type::CloneObject) { else if (eventType == Event::Type::CloneObject) {
CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(this->event); CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(this->event);
QString destMap = clone->getTargetMap(); emit editor->warpEventDoubleClicked(clone->getTargetMap(), clone->getTargetID(), Event::Group::Object);
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, clone->getTargetID(), Event::Group::Object);
}
} }
else if (eventType == Event::Type::SecretBase) { else if (eventType == Event::Type::SecretBase) {
SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(this->event); SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(this->event);
QString baseId = base->getBaseID(); QString baseId = base->getBaseID();
QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_"))); QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_")));
if (destMap != NONE_MAP_NAME) { emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp);
emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp);
}
} }
} }

View file

@ -507,9 +507,9 @@ void WarpFrame::setup() {
// desination warp id // desination warp id
QFormLayout *l_form_dest_warp = new QFormLayout(); QFormLayout *l_form_dest_warp = new QFormLayout();
this->spinner_dest_warp = new NoScrollSpinBox(this); this->combo_dest_warp = new NoScrollComboBox(this);
this->spinner_dest_warp->setToolTip("The warp id on the destination map."); this->combo_dest_warp->setToolTip("The warp id on the destination map.");
l_form_dest_warp->addRow("Destination Warp", this->spinner_dest_warp); l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp);
this->layout_contents->addLayout(l_form_dest_warp); this->layout_contents->addLayout(l_form_dest_warp);
// custom attributes // custom attributes
@ -529,9 +529,9 @@ void WarpFrame::connectSignals() {
}); });
// dest id // dest id
this->spinner_dest_warp->disconnect(); this->combo_dest_warp->disconnect();
connect(this->spinner_dest_warp, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) { connect(this->combo_dest_warp, &QComboBox::currentTextChanged, [this](const QString &text) {
this->warp->setDestinationWarpID(value); this->warp->setDestinationWarpID(text);
this->warp->modify(); this->warp->modify();
}); });
} }
@ -553,7 +553,7 @@ void WarpFrame::initialize() {
} }
// dest id // dest id
this->spinner_dest_warp->setValue(this->warp->getDestinationWarpID()); this->combo_dest_warp->setCurrentText(this->warp->getDestinationWarpID());
} }
void WarpFrame::populate(Project *project) { void WarpFrame::populate(Project *project) {

View file

@ -241,7 +241,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool inclu
continue; continue;
int x = cur.x; int x = cur.x;
int y = cur.y; int y = cur.y;
int offset = connection->offset.toInt(nullptr, 0); int offset = connection->offset;
Map *connectionMap = this->editor->project->loadMap(connection->map_name); Map *connectionMap = this->editor->project->loadMap(connection->map_name);
if (connection->direction == "up") { if (connection->direction == "up") {
x += offset; x += offset;

View file

@ -117,8 +117,8 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) {
ui->comboBox_Song->addItems(project->songNames); ui->comboBox_Song->addItems(project->songNames);
if (existingLayout) { if (existingLayout) {
ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutId)->width.toInt(nullptr, 0)); ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutId)->width);
ui->spinBox_NewMap_Height->setValue(project->mapLayouts.value(layoutId)->height.toInt(nullptr, 0)); ui->spinBox_NewMap_Height->setValue(project->mapLayouts.value(layoutId)->height);
ui->comboBox_NewMap_Primary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_primary_label); ui->comboBox_NewMap_Primary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_primary_label);
ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_secondary_label); ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_secondary_label);
ui->spinBox_NewMap_Width->setDisabled(true); ui->spinBox_NewMap_Width->setDisabled(true);
@ -155,8 +155,8 @@ void NewMapPopup::setDefaultValuesImportMap(MapLayout *mapLayout) {
ui->comboBox_Song->addItems(project->songNames); ui->comboBox_Song->addItems(project->songNames);
ui->spinBox_NewMap_Width->setValue(mapLayout->width.toInt(nullptr, 0)); ui->spinBox_NewMap_Width->setValue(mapLayout->width);
ui->spinBox_NewMap_Height->setValue(mapLayout->height.toInt(nullptr, 0)); ui->spinBox_NewMap_Height->setValue(mapLayout->height);
ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_label); ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_label);
ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(mapLayout->tileset_secondary_label); ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(mapLayout->tileset_secondary_label);
@ -207,8 +207,8 @@ void NewMapPopup::setDefaultValuesProjectConfig(bool importedMap, MapLayout *map
} }
if (projectConfig.getUseCustomBorderSize()) { if (projectConfig.getUseCustomBorderSize()) {
if (importedMap) { if (importedMap) {
ui->spinBox_NewMap_BorderWidth->setValue(mapLayout->border_width.toInt(nullptr, 0)); ui->spinBox_NewMap_BorderWidth->setValue(mapLayout->border_width);
ui->spinBox_NewMap_BorderHeight->setValue(mapLayout->border_height.toInt(nullptr, 0)); ui->spinBox_NewMap_BorderHeight->setValue(mapLayout->border_height);
} }
ui->spinBox_NewMap_BorderWidth->setVisible(true); ui->spinBox_NewMap_BorderWidth->setVisible(true);
ui->spinBox_NewMap_BorderHeight->setVisible(true); ui->spinBox_NewMap_BorderHeight->setVisible(true);
@ -265,9 +265,9 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
newMap->type = this->ui->comboBox_NewMap_Type->currentText(); newMap->type = this->ui->comboBox_NewMap_Type->currentText();
newMap->location = this->ui->comboBox_NewMap_Location->currentText(); newMap->location = this->ui->comboBox_NewMap_Location->currentText();
newMap->song = this->ui->comboBox_Song->currentText(); newMap->song = this->ui->comboBox_Song->currentText();
newMap->requiresFlash = "0"; newMap->requiresFlash = false;
newMap->weather = this->project->weatherNames.value(0, "WEATHER_NONE"); newMap->weather = this->project->weatherNames.value(0, "WEATHER_NONE");
newMap->show_location = this->ui->checkBox_NewMap_Show_Location->isChecked() ? "1" : "0"; newMap->show_location = this->ui->checkBox_NewMap_Show_Location->isChecked();
newMap->battle_scene = this->project->mapBattleScenes.value(0, "MAP_BATTLE_SCENE_NORMAL"); newMap->battle_scene = this->project->mapBattleScenes.value(0, "MAP_BATTLE_SCENE_NORMAL");
if (this->existingLayout) { if (this->existingLayout) {
@ -277,14 +277,14 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
layout = new MapLayout; layout = new MapLayout;
layout->id = MapLayout::layoutConstantFromName(newMapName); layout->id = MapLayout::layoutConstantFromName(newMapName);
layout->name = QString("%1_Layout").arg(newMap->name); layout->name = QString("%1_Layout").arg(newMap->name);
layout->width = QString::number(this->ui->spinBox_NewMap_Width->value()); layout->width = this->ui->spinBox_NewMap_Width->value();
layout->height = QString::number(this->ui->spinBox_NewMap_Height->value()); layout->height = this->ui->spinBox_NewMap_Height->value();
if (projectConfig.getUseCustomBorderSize()) { if (projectConfig.getUseCustomBorderSize()) {
layout->border_width = QString::number(this->ui->spinBox_NewMap_BorderWidth->value()); layout->border_width = this->ui->spinBox_NewMap_BorderWidth->value();
layout->border_height = QString::number(this->ui->spinBox_NewMap_BorderHeight->value()); layout->border_height = this->ui->spinBox_NewMap_BorderHeight->value();
} else { } else {
layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); layout->border_width = DEFAULT_BORDER_WIDTH;
layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); layout->border_height = DEFAULT_BORDER_HEIGHT;
} }
layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText(); layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText();
layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText(); layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText();
@ -300,13 +300,13 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
} }
if (this->ui->checkBox_NewMap_Flyable->isChecked()) { if (this->ui->checkBox_NewMap_Flyable->isChecked()) {
newMap->isFlyable = "TRUE"; newMap->needsHealLocation = true;
} }
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) { if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0"; newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked();
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0"; newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked();
newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0"; newMap->allowEscaping = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked();
} }
if (projectConfig.getFloorNumberEnabled()) { if (projectConfig.getFloorNumberEnabled()) {
newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value(); newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value();

View file

@ -46,14 +46,14 @@ void Prefab::loadPrefabs() {
if (prefabObj.isEmpty()) if (prefabObj.isEmpty())
continue; continue;
int width = prefabObj["width"].toInt(); int width = ParseUtil::jsonToInt(prefabObj["width"]);
int height = prefabObj["height"].toInt(); int height = ParseUtil::jsonToInt(prefabObj["height"]);
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
continue; continue;
QString name = prefabObj["name"].toString(); QString name = ParseUtil::jsonToQString(prefabObj["name"]);
QString primaryTileset = prefabObj["primary_tileset"].toString(); QString primaryTileset = ParseUtil::jsonToQString(prefabObj["primary_tileset"]);
QString secondaryTileset = prefabObj["secondary_tileset"].toString(); QString secondaryTileset = ParseUtil::jsonToQString(prefabObj["secondary_tileset"]);
MetatileSelection selection; MetatileSelection selection;
selection.dimensions = QPoint(width, height); selection.dimensions = QPoint(width, height);
@ -65,17 +65,17 @@ void Prefab::loadPrefabs() {
QJsonArray metatiles = prefabObj["metatiles"].toArray(); QJsonArray metatiles = prefabObj["metatiles"].toArray();
for (int j = 0; j < metatiles.size(); j++) { for (int j = 0; j < metatiles.size(); j++) {
QJsonObject metatileObj = metatiles[j].toObject(); QJsonObject metatileObj = metatiles[j].toObject();
int x = metatileObj["x"].toInt(); int x = ParseUtil::jsonToInt(metatileObj["x"]);
int y = metatileObj["y"].toInt(); int y = ParseUtil::jsonToInt(metatileObj["y"]);
if (x < 0 || x >= width || y < 0 || y >= height) if (x < 0 || x >= width || y < 0 || y >= height)
continue; continue;
int index = y * width + x; int index = y * width + x;
int metatileId = metatileObj["metatile_id"].toInt(); int metatileId = ParseUtil::jsonToInt(metatileObj["metatile_id"]);
if (metatileId < 0 || metatileId >= Project::getNumMetatilesTotal()) if (metatileId < 0 || metatileId >= Project::getNumMetatilesTotal())
continue; continue;
selection.metatileItems[index].metatileId = metatileObj["metatile_id"].toInt(); selection.metatileItems[index].metatileId = ParseUtil::jsonToInt(metatileObj["metatile_id"]);
selection.collisionItems[index].collision = metatileObj["collision"].toInt(); selection.collisionItems[index].collision = ParseUtil::jsonToInt(metatileObj["collision"]);
selection.collisionItems[index].elevation = metatileObj["elevation"].toInt(); selection.collisionItems[index].elevation = ParseUtil::jsonToInt(metatileObj["elevation"]);
selection.metatileItems[index].enabled = true; selection.metatileItems[index].enabled = true;
selection.collisionItems[index].enabled = true; selection.collisionItems[index].enabled = true;
} }

View file

@ -125,13 +125,13 @@ bool RegionMapEditor::loadRegionMapEntries() {
for (auto entryRef : object["map_sections"].toArray()) { for (auto entryRef : object["map_sections"].toArray()) {
QJsonObject entryObject = entryRef.toObject(); QJsonObject entryObject = entryRef.toObject();
QString entryMapSection = entryObject["map_section"].toString(); QString entryMapSection = ParseUtil::jsonToQString(entryObject["map_section"]);
MapSectionEntry entry; MapSectionEntry entry;
entry.name = entryObject["name"].toString(); entry.name = ParseUtil::jsonToQString(entryObject["name"]);
entry.x = entryObject["x"].toInt(); entry.x = ParseUtil::jsonToInt(entryObject["x"]);
entry.y = entryObject["y"].toInt(); entry.y = ParseUtil::jsonToInt(entryObject["y"]);
entry.width = entryObject["width"].toInt(); entry.width = ParseUtil::jsonToInt(entryObject["width"]);
entry.height = entryObject["height"].toInt(); entry.height = ParseUtil::jsonToInt(entryObject["height"]);
entry.valid = true; entry.valid = true;
this->region_map_entries[entryMapSection] = entry; this->region_map_entries[entryMapSection] = entry;
} }