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
- 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.
- 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
@ -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 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.
- If any JSON data is the incorrect type Porymap will now attempt to convert it.
### Fixed
- Fix events losing their assigned script when the script autocomplete is used.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -72,7 +72,11 @@ public:
static QString removeLineComments(QString text, const QStringList &commentSymbols);
static QStringList splitShellCommand(QStringView command);
static int gameStringToInt(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:
QString root;

View file

@ -60,6 +60,9 @@
#include <QPair>
#include <QFile>
#include <QTextStream>
#include <QJsonValue>
#include <QJsonArray>
#include <QJsonObject>
#include <memory>
#include <initializer_list>
@ -129,6 +132,8 @@ public:
int>::type = 0>
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
// Json(bool(some_pointer)) if that behavior is desired.
Json(void *) = delete;

View file

@ -196,7 +196,7 @@ private slots:
void on_checkBox_ShowLocation_stateChanged(int selected);
void on_checkBox_AllowRunning_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_actionUse_Encounter_Json_triggered(bool checked);
void on_actionMonitor_Project_Files_triggered(bool checked);
@ -219,6 +219,7 @@ private slots:
void on_toolButton_deleteObject_clicked();
void addNewEvent(Event::Type type);
void tryAddEventTab(QWidget * tab, Event::Group group);
void displayEventTabs();
void updateSelectedObjects();
void updateObjects();
@ -387,6 +388,7 @@ private:
void redrawMetatileSelection();
QObjectList shortcutableObjects() const;
void addCustomHeaderValue(QString key, QJsonValue value, bool isNew = false);
};
enum MapListUserRoles {

View file

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

View file

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

View file

@ -12,11 +12,15 @@ public:
explicit CustomAttributesTable(Event *event, QWidget *parent = nullptr);
~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:
Event *event;
QTableWidget *table;
void resizeVertically();
QMap<QString, QString> getTableFields();
};
#endif // CUSTOMATTRIBUTESTABLE_H

View file

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

View file

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

View file

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

View file

@ -16,17 +16,17 @@ QString MapLayout::layoutConstantFromName(QString mapName) {
}
int MapLayout::getWidth() {
return width.toInt(nullptr, 0);
return width;
}
int MapLayout::getHeight() {
return height.toInt(nullptr, 0);
return height;
}
int MapLayout::getBorderWidth() {
return border_width.toInt(nullptr, 0);
return border_width;
}
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->width = QString::number(mapWidth);
mapLayout->height = QString::number(mapHeight);
mapLayout->border_width = (borderWidth == 0) ? QString::number(2) : QString::number(borderWidth);
mapLayout->border_height = (borderHeight == 0) ? QString::number(2) : QString::number(borderHeight);
mapLayout->width = mapWidth;
mapLayout->height = mapHeight;
mapLayout->border_width = (borderWidth == 0) ? DEFAULT_BORDER_WIDTH : borderWidth;
mapLayout->border_height = (borderHeight == 0) ? DEFAULT_BORDER_HEIGHT : borderHeight;
QList<QString> tilesets = project->tilesetLabelsOrdered;

View file

@ -404,13 +404,17 @@ QMap<QString, QString> ParseUtil::readNamedIndexCArray(const QString &filename,
return map;
}
bool ParseUtil::gameStringToBool(QString gameString, bool * ok) {
int ParseUtil::gameStringToInt(QString gameString, bool * ok) {
if (ok) *ok = true;
if (QString::compare(gameString, "TRUE", Qt::CaseInsensitive) == 0)
return true;
return 1;
if (QString::compare(gameString, "FALSE", Qt::CaseInsensitive) == 0)
return false;
return gameString.toInt(ok) != 0;
return 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) {
@ -522,6 +526,48 @@ bool ParseUtil::ensureFieldsExist(const QJsonObject &obj, const QList<QString> &
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) {
if (scriptLabel.isEmpty())
return 0;

View file

@ -10,6 +10,7 @@
#include "editcommands.h"
#include "config.h"
#include "scripting.h"
#include "customattributestable.h"
#include <QCheckBox>
#include <QPainter>
#include <QMouseEvent>
@ -176,7 +177,7 @@ void Editor::setEditingConnections() {
bool controlsEnabled = selected_connection_item != nullptr;
setConnectionEditControlsEnabled(controlsEnabled);
if (selected_connection_item) {
onConnectionOffsetChanged(selected_connection_item->connection->offset.toInt());
onConnectionOffsetChanged(selected_connection_item->connection->offset);
setConnectionMap(selected_connection_item->connection->map_name);
setCurrentConnectionDirection(selected_connection_item->connection->direction);
}
@ -774,7 +775,7 @@ void Editor::setCurrentConnectionDirection(QString curDirection) {
selected_connection_item->connection->direction = curDirection;
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;
int x = 0, y = 0;
if (selected_connection_item->connection->direction == "up") {
@ -820,7 +821,7 @@ void Editor::updateCurrentConnectionDirection(QString curDirection) {
void Editor::onConnectionMoved(MapConnection* connection) {
updateMirroredConnectionOffset(connection);
onConnectionOffsetChanged(connection->offset.toInt());
onConnectionOffsetChanged(connection->offset);
maskNonVisibleConnectionTiles();
}
@ -834,7 +835,7 @@ void Editor::onConnectionOffsetChanged(int newOffset) {
void Editor::setConnectionEditControlValues(MapConnection* connection) {
QString mapName = connection ? connection->map_name : "";
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_ConnectionDirection->blockSignals(true);
@ -883,7 +884,7 @@ void Editor::onConnectionItemSelected(ConnectionPixmapItem* connectionItem) {
setConnectionEditControlValues(selected_connection_item->connection);
ui->spinBox_ConnectionOffset->setMaximum(selected_connection_item->getMaxOffset());
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) {
@ -1565,7 +1566,7 @@ void Editor::createConnectionItem(MapConnection* connection, bool hide) {
}
QPixmap pixmap = connected_map->renderConnection(*connection, map->layout);
int offset = connection->offset.toInt(nullptr, 0);
int offset = connection->offset;
int x = 0, y = 0;
if (connection->direction == "up") {
x = offset * 16;
@ -1728,7 +1729,7 @@ void Editor::updateConnectionOffset(int offset) {
selected_connection_item->blockSignals(true);
offset = qMin(offset, selected_connection_item->getMaxOffset());
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") {
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") {
@ -1747,7 +1748,7 @@ void Editor::setConnectionMap(QString mapName) {
if (!selected_connection_item)
return;
if (mapName.isEmpty() || mapName == NONE_MAP_NAME) {
if (mapName.isEmpty() || mapName == DYNAMIC_MAP_NAME) {
removeCurrentConnection();
return;
}
@ -1783,7 +1784,7 @@ void Editor::addNewConnection() {
MapConnection* newConnection = new MapConnection;
newConnection->direction = minDirection;
newConnection->offset = "0";
newConnection->offset = 0;
newConnection->map_name = defaultMapName;
map->connections.append(newConnection);
createConnectionItem(newConnection, true);
@ -1851,7 +1852,7 @@ void Editor::updateMirroredConnection(MapConnection* connection, QString origina
otherMap->connections.append(mirrorConnection);
}
mirrorConnection->offset = QString::number(-connection->offset.toInt());
mirrorConnection->offset = -connection->offset;
}
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
if (connection) {
map->connections.removeOne(connection);
@ -1909,7 +1910,7 @@ void Editor::updateDiveEmergeMap(QString mapName, QString direction) {
if (!connection) {
connection = new MapConnection;
connection->direction = direction;
connection->offset = "0";
connection->offset = 0;
connection->map_name = mapName;
map->connections.append(connection);
updateMirroredConnection(connection, connection->direction, connection->map_name);
@ -1952,17 +1953,7 @@ void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback)
void Editor::updateCustomMapHeaderValues(QTableWidget *table)
{
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;
}
map->customHeaders = fields;
map->customHeaders = CustomAttributesTable::getAttributes(table);
emit editedMapData();
}

View file

@ -308,6 +308,33 @@ const Json & JsonArray::operator[] (int i) const {
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
*/

View file

@ -381,28 +381,28 @@ void MainWindow::setProjectSpecificUIVisibility()
case BaseGameVersion::pokeruby:
ui->checkBox_AllowRunning->setVisible(false);
ui->checkBox_AllowBiking->setVisible(false);
ui->checkBox_AllowEscapeRope->setVisible(false);
ui->checkBox_AllowEscaping->setVisible(false);
ui->label_AllowRunning->setVisible(false);
ui->label_AllowBiking->setVisible(false);
ui->label_AllowEscapeRope->setVisible(false);
ui->label_AllowEscaping->setVisible(false);
ui->actionRegion_Map_Editor->setVisible(true);
break;
case BaseGameVersion::pokeemerald:
ui->checkBox_AllowRunning->setVisible(true);
ui->checkBox_AllowBiking->setVisible(true);
ui->checkBox_AllowEscapeRope->setVisible(true);
ui->checkBox_AllowEscaping->setVisible(true);
ui->label_AllowRunning->setVisible(true);
ui->label_AllowBiking->setVisible(true);
ui->label_AllowEscapeRope->setVisible(true);
ui->label_AllowEscaping->setVisible(true);
ui->actionRegion_Map_Editor->setVisible(true);
break;
case BaseGameVersion::pokefirered:
ui->checkBox_AllowRunning->setVisible(true);
ui->checkBox_AllowBiking->setVisible(true);
ui->checkBox_AllowEscapeRope->setVisible(true);
ui->checkBox_AllowEscaping->setVisible(true);
ui->label_AllowRunning->setVisible(true);
ui->label_AllowBiking->setVisible(true);
ui->label_AllowEscapeRope->setVisible(true);
ui->label_AllowEscaping->setVisible(true);
ui->actionRegion_Map_Editor->setVisible(true);
break;
}
@ -719,6 +719,10 @@ void MainWindow::refreshMapScene()
}
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.
if (!editor->project->mapNames.contains(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.
event_id -= Event::getIndexOffset(event_group);
int index = event_id - Event::getIndexOffset(event_group);
QList<Event*> events = editor->map->events[event_group];
if (event_id < events.length() && event_id >= 0) {
Event *event = events.at(event_id);
if (index < events.length() && index >= 0) {
Event *event = events.at(index);
for (DraggablePixmapItem *item : editor->getObjects()) {
if (item->event == event) {
editor->selected_events->clear();
@ -748,6 +752,9 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_
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 blockerB(ui->checkBox_AllowBiking);
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_ShowLocation->setChecked(false);
ui->checkBox_AllowRunning->setChecked(false);
ui->checkBox_AllowBiking->setChecked(false);
ui->checkBox_AllowEscapeRope->setChecked(false);
ui->checkBox_AllowEscaping->setChecked(false);
if (!editor || !editor->map || !editor->project) {
ui->frame_3->setEnabled(false);
return;
@ -793,27 +800,24 @@ void MainWindow::displayMapProperties() {
ui->comboBox_Song->setCurrentText(map->song);
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_Type->setCurrentText(map->type);
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) {
ui->checkBox_AllowRunning->setChecked(ParseUtil::gameStringToBool(map->allowRunning));
ui->checkBox_AllowBiking->setChecked(ParseUtil::gameStringToBool(map->allowBiking));
ui->checkBox_AllowEscapeRope->setChecked(ParseUtil::gameStringToBool(map->allowEscapeRope));
ui->checkBox_AllowRunning->setChecked(map->allowRunning);
ui->checkBox_AllowBiking->setChecked(map->allowBiking);
ui->checkBox_AllowEscaping->setChecked(map->allowEscaping);
}
ui->spinBox_FloorNumber->setValue(map->floorNumber);
// Custom fields table.
ui->tableWidget_CustomHeaderFields->blockSignals(true);
ui->tableWidget_CustomHeaderFields->setRowCount(0);
for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++) {
int rowIndex = ui->tableWidget_CustomHeaderFields->rowCount();
ui->tableWidget_CustomHeaderFields->insertRow(rowIndex);
ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 0, new QTableWidgetItem(it.key()));
ui->tableWidget_CustomHeaderFields->setItem(rowIndex, 1, new QTableWidgetItem(it.value()));
}
for (auto it = map->customHeaders.begin(); it != map->customHeaders.end(); it++)
CustomAttributesTable::addAttribute(ui->tableWidget_CustomHeaderFields, it.key(), it.value());
ui->tableWidget_CustomHeaderFields->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
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)
{
if (editor && editor->map) {
bool checked = selected == Qt::Checked;
if (checked) {
editor->map->requiresFlash = "TRUE";
} else {
editor->map->requiresFlash = "FALSE";
}
editor->map->requiresFlash = (selected == Qt::Checked);
markMapEdited();
}
}
@ -873,12 +872,7 @@ void MainWindow::on_checkBox_Visibility_stateChanged(int selected)
void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected)
{
if (editor && editor->map) {
bool checked = selected == Qt::Checked;
if (checked) {
editor->map->show_location = "TRUE";
} else {
editor->map->show_location = "FALSE";
}
editor->map->show_location = (selected == Qt::Checked);
markMapEdited();
}
}
@ -886,12 +880,7 @@ void MainWindow::on_checkBox_ShowLocation_stateChanged(int selected)
void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected)
{
if (editor && editor->map) {
bool checked = selected == Qt::Checked;
if (checked) {
editor->map->allowRunning = "1";
} else {
editor->map->allowRunning = "0";
}
editor->map->allowRunning = (selected == Qt::Checked);
markMapEdited();
}
}
@ -899,25 +888,15 @@ void MainWindow::on_checkBox_AllowRunning_stateChanged(int selected)
void MainWindow::on_checkBox_AllowBiking_stateChanged(int selected)
{
if (editor && editor->map) {
bool checked = selected == Qt::Checked;
if (checked) {
editor->map->allowBiking = "1";
} else {
editor->map->allowBiking = "0";
}
editor->map->allowBiking = (selected == Qt::Checked);
markMapEdited();
}
}
void MainWindow::on_checkBox_AllowEscapeRope_stateChanged(int selected)
void MainWindow::on_checkBox_AllowEscaping_stateChanged(int selected)
{
if (editor && editor->map) {
bool checked = selected == Qt::Checked;
if (checked) {
editor->map->allowEscapeRope = "1";
} else {
editor->map->allowEscapeRope = "0";
}
editor->map->allowEscaping = (selected == Qt::Checked);
markMapEdited();
}
}
@ -1202,7 +1181,7 @@ void MainWindow::onNewMapCreated() {
sortMapList();
setMap(newMapName, true);
if (ParseUtil::gameStringToBool(newMap->isFlyable)) {
if (newMap->needsHealLocation) {
addNewEvent(Event::Type::HealLocation);
editor->project->saveHealLocations(newMap);
editor->save();
@ -1605,8 +1584,8 @@ void MainWindow::paste() {
}
QJsonArray metatilesArray = pasteObject["metatile_selection"].toArray();
QJsonArray collisionsArray = pasteObject["collision_selection"].toArray();
int width = pasteObject["width"].toInt();
int height = pasteObject["height"].toInt();
int width = ParseUtil::jsonToInt(pasteObject["width"]);
int height = ParseUtil::jsonToInt(pasteObject["height"]);
QList<uint16_t> metatiles;
QList<QPair<uint16_t, uint16_t>> collisions;
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() {
const QSignalBlocker blocker(ui->tabWidget_EventType);
ui->tabWidget_EventType->clear();
if (editor->map->events.value(Event::Group::Object).length())
ui->tabWidget_EventType->addTab(eventTabObjectWidget, "Objects");
if (editor->map->events.value(Event::Group::Warp).length())
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");
tryAddEventTab(eventTabObjectWidget, Event::Group::Object);
tryAddEventTab(eventTabWarpWidget, Event::Group::Warp);
tryAddEventTab(eventTabTriggerWidget, Event::Group::Coord);
tryAddEventTab(eventTabBGWidget, Event::Group::Bg);
tryAddEventTab(eventTabHealspotWidget, Event::Group::Heal);
}
void MainWindow::updateObjects() {
@ -2785,33 +2759,18 @@ void MainWindow::togglePreferenceSpecificUi() {
void MainWindow::on_pushButton_AddCustomHeaderField_clicked()
{
int rowIndex = this->ui->tableWidget_CustomHeaderFields->rowCount();
this->ui->tableWidget_CustomHeaderFields->insertRow(rowIndex);
this->ui->tableWidget_CustomHeaderFields->selectRow(rowIndex);
this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
bool ok;
QJsonValue value = CustomAttributesTable::pickType(this, &ok);
if (ok){
CustomAttributesTable::addAttribute(this->ui->tableWidget_CustomHeaderFields, "", value, true);
this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
}
}
void MainWindow::on_pushButton_DeleteCustomHeaderField_clicked()
{
int rowCount = this->ui->tableWidget_CustomHeaderFields->rowCount();
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);
}
if (CustomAttributesTable::deleteSelectedAttributes(this->ui->tableWidget_CustomHeaderFields))
this->editor->updateCustomMapHeaderValues(this->ui->tableWidget_CustomHeaderFields);
}
}
void MainWindow::on_tableWidget_CustomHeaderFields_cellChanged(int, int)

View file

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

View file

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

View file

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

View file

@ -1,10 +1,12 @@
#include "customattributestable.h"
#include "parseutil.h"
#include <QHBoxLayout>
#include <QHeaderView>
#include <QPushButton>
#include <QTableWidget>
#include <QLabel>
#include <QScrollBar>
#include <QInputDialog>
CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
QFrame(parent)
@ -28,52 +30,34 @@ CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
layout->addWidget(buttonsFrame);
this->table = new QTableWidget(this);
this->table->setColumnCount(2);
this->table->setHorizontalHeaderLabels(QStringList({"Key", "Value"}));
this->table->setColumnCount(3);
this->table->setHorizontalHeaderLabels(QStringList({"Type", "Key", "Value"}));
this->table->horizontalHeader()->setStretchLastSection(true);
layout->addWidget(this->table);
QMap<QString, QString> customValues = this->event->getCustomValues();
for (auto it = customValues.begin(); it != customValues.end(); it++) {
int rowIndex = this->table->rowCount();
this->table->insertRow(rowIndex);
this->table->setItem(rowIndex, 0, new QTableWidgetItem(it.key()));
this->table->setItem(rowIndex, 1, new QTableWidgetItem(it.value()));
}
QMap<QString, QJsonValue> customValues = this->event->getCustomValues();
for (auto it = customValues.begin(); it != customValues.end(); it++)
CustomAttributesTable::addAttribute(this->table, it.key(), it.value());
connect(addButton, &QPushButton::clicked, [=]() {
int rowIndex = this->table->rowCount();
this->table->insertRow(rowIndex);
this->table->selectRow(rowIndex);
this->event->setCustomValues(this->getTableFields());
this->resizeVertically();
bool ok;
QJsonValue value = CustomAttributesTable::pickType(this, &ok);
if (ok){
CustomAttributesTable::addAttribute(this->table, "", value, true);
this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
this->resizeVertically();
}
});
connect(deleteButton, &QPushButton::clicked, [=]() {
int rowCount = this->table->rowCount();
if (rowCount > 0) {
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());
if (CustomAttributesTable::deleteSelectedAttributes(this->table)) {
this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
this->resizeVertically();
}
});
connect(this->table, &QTableWidget::cellChanged, [=]() {
this->event->setCustomValues(this->getTableFields());
this->event->setCustomValues(CustomAttributesTable::getAttributes(this->table));
});
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() {
int horizontalHeaderHeight = this->table->horizontalHeader()->height();
int rowHeight = 0;
@ -112,3 +82,125 @@ void CustomAttributesTable::resizeVertically() {
this->table->setMinimumHeight(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) {
WarpEvent *warp = dynamic_cast<WarpEvent *>(this->event);
QString destMap = warp->getDestinationMap();
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, warp->getDestinationWarpID(), Event::Group::Warp);
}
int warpId = ParseUtil::gameStringToInt(warp->getDestinationWarpID());
emit editor->warpEventDoubleClicked(destMap, warpId, Event::Group::Warp);
}
else if (eventType == Event::Type::CloneObject) {
CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(this->event);
QString destMap = clone->getTargetMap();
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, clone->getTargetID(), Event::Group::Object);
}
emit editor->warpEventDoubleClicked(clone->getTargetMap(), clone->getTargetID(), Event::Group::Object);
}
else if (eventType == Event::Type::SecretBase) {
SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(this->event);
QString baseId = base->getBaseID();
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
QFormLayout *l_form_dest_warp = new QFormLayout();
this->spinner_dest_warp = new NoScrollSpinBox(this);
this->spinner_dest_warp->setToolTip("The warp id on the destination map.");
l_form_dest_warp->addRow("Destination Warp", this->spinner_dest_warp);
this->combo_dest_warp = new NoScrollComboBox(this);
this->combo_dest_warp->setToolTip("The warp id on the destination map.");
l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp);
this->layout_contents->addLayout(l_form_dest_warp);
// custom attributes
@ -529,9 +529,9 @@ void WarpFrame::connectSignals() {
});
// dest id
this->spinner_dest_warp->disconnect();
connect(this->spinner_dest_warp, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) {
this->warp->setDestinationWarpID(value);
this->combo_dest_warp->disconnect();
connect(this->combo_dest_warp, &QComboBox::currentTextChanged, [this](const QString &text) {
this->warp->setDestinationWarpID(text);
this->warp->modify();
});
}
@ -553,7 +553,7 @@ void WarpFrame::initialize() {
}
// dest id
this->spinner_dest_warp->setValue(this->warp->getDestinationWarpID());
this->combo_dest_warp->setCurrentText(this->warp->getDestinationWarpID());
}
void WarpFrame::populate(Project *project) {

View file

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

View file

@ -117,8 +117,8 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) {
ui->comboBox_Song->addItems(project->songNames);
if (existingLayout) {
ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutId)->width.toInt(nullptr, 0));
ui->spinBox_NewMap_Height->setValue(project->mapLayouts.value(layoutId)->height.toInt(nullptr, 0));
ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutId)->width);
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_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_secondary_label);
ui->spinBox_NewMap_Width->setDisabled(true);
@ -155,8 +155,8 @@ void NewMapPopup::setDefaultValuesImportMap(MapLayout *mapLayout) {
ui->comboBox_Song->addItems(project->songNames);
ui->spinBox_NewMap_Width->setValue(mapLayout->width.toInt(nullptr, 0));
ui->spinBox_NewMap_Height->setValue(mapLayout->height.toInt(nullptr, 0));
ui->spinBox_NewMap_Width->setValue(mapLayout->width);
ui->spinBox_NewMap_Height->setValue(mapLayout->height);
ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_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 (importedMap) {
ui->spinBox_NewMap_BorderWidth->setValue(mapLayout->border_width.toInt(nullptr, 0));
ui->spinBox_NewMap_BorderHeight->setValue(mapLayout->border_height.toInt(nullptr, 0));
ui->spinBox_NewMap_BorderWidth->setValue(mapLayout->border_width);
ui->spinBox_NewMap_BorderHeight->setValue(mapLayout->border_height);
}
ui->spinBox_NewMap_BorderWidth->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->location = this->ui->comboBox_NewMap_Location->currentText();
newMap->song = this->ui->comboBox_Song->currentText();
newMap->requiresFlash = "0";
newMap->requiresFlash = false;
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");
if (this->existingLayout) {
@ -277,14 +277,14 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
layout = new MapLayout;
layout->id = MapLayout::layoutConstantFromName(newMapName);
layout->name = QString("%1_Layout").arg(newMap->name);
layout->width = QString::number(this->ui->spinBox_NewMap_Width->value());
layout->height = QString::number(this->ui->spinBox_NewMap_Height->value());
layout->width = this->ui->spinBox_NewMap_Width->value();
layout->height = this->ui->spinBox_NewMap_Height->value();
if (projectConfig.getUseCustomBorderSize()) {
layout->border_width = QString::number(this->ui->spinBox_NewMap_BorderWidth->value());
layout->border_height = QString::number(this->ui->spinBox_NewMap_BorderHeight->value());
layout->border_width = this->ui->spinBox_NewMap_BorderWidth->value();
layout->border_height = this->ui->spinBox_NewMap_BorderHeight->value();
} else {
layout->border_width = QString::number(DEFAULT_BORDER_WIDTH);
layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT);
layout->border_width = DEFAULT_BORDER_WIDTH;
layout->border_height = DEFAULT_BORDER_HEIGHT;
}
layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_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()) {
newMap->isFlyable = "TRUE";
newMap->needsHealLocation = true;
}
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokeruby) {
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0";
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0";
newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0";
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked();
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked();
newMap->allowEscaping = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked();
}
if (projectConfig.getFloorNumberEnabled()) {
newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value();

View file

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

View file

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