Support map JSON data

This commit is contained in:
Marcus Huderle 2019-02-01 11:43:25 -06:00 committed by huderlem
parent d2508b1f1d
commit 94686e6f0a
12 changed files with 625 additions and 890 deletions

View file

@ -4,6 +4,7 @@
#include <QString>
#include <QPixmap>
#include <QMap>
#include <QJsonObject>
class EventType
{
@ -64,13 +65,13 @@ public:
static Event* createNewHiddenItemEvent();
static Event* createNewSecretBaseEvent();
QString buildObjectEventMacro(int);
QString buildWarpEventMacro(QMap<QString, QString>*);
QString buildTriggerEventMacro();
QString buildWeatherTriggerEventMacro();
QString buildSignEventMacro();
QString buildHiddenItemEventMacro();
QString buildSecretBaseEventMacro();
QJsonObject buildObjectEventJSON();
QJsonObject buildWarpEventJSON(QMap<QString, QString>*);
QJsonObject buildTriggerEventJSON();
QJsonObject buildWeatherTriggerEventJSON();
QJsonObject buildSignEventJSON();
QJsonObject buildHiddenItemEventJSON();
QJsonObject buildSecretBaseEventJSON();
void setPixmapFromSpritesheet(QImage, int, int);
int getPixelX();
int getPixelY();

View file

@ -24,18 +24,13 @@ public:
QString name;
QString constantName;
QString group_num;
QString layout_label;
QString events_label;
QString scripts_label;
QString connections_label;
QString song;
QString layout_id;
QString layoutId;
QString location;
QString requiresFlash;
QString isFlyable;
QString weather;
QString type;
QString unknown;
QString show_location;
QString allowRunning;
QString allowBiking;

View file

@ -10,14 +10,12 @@
class MapLayout {
public:
MapLayout() {}
int index;
static QString layoutConstantFromName(QString mapName);
QString id;
QString name;
QString label;
QString width;
QString height;
QString border_label;
QString border_path;
QString blockdata_label;
QString blockdata_path;
QString tileset_primary_label;
QString tileset_secondary_label;
@ -31,11 +29,6 @@ public:
Blockdata *cached_collision = nullptr;
Blockdata *cached_border = nullptr;
bool has_unsaved_changes = false;
public:
static QString getNameFromLabel(QString label) {
// ASSUMPTION: strip off "_Layout" from layout label. Directories in 'data/layouts/' must be well-formed.
return label.replace(label.lastIndexOf("_Layout"), label.length(), "");
}
};
#endif // MAPLAYOUT_H

View file

@ -226,6 +226,7 @@ private:
enum MapListUserRoles {
GroupRole = Qt::UserRole + 1, // Used to hold the map group number.
TypeRole, // Used to differentiate between the different layers of the map list tree view.
TypeRole2, // Used for various extra data needed.
};
#endif // MAINWINDOW_H

View file

@ -26,6 +26,7 @@ public:
QMap<QString, QString>* mapNamesToMapConstants;
QList<QString> mapLayoutsTable;
QList<QString> mapLayoutsTableMaster;
QString layoutsLabel;
QMap<QString, MapLayout*> mapLayouts;
QMap<QString, MapLayout*> mapLayoutsMaster;
QStringList *regionMapSections = nullptr;
@ -39,7 +40,6 @@ public:
QStringList *coordEventWeatherNames = nullptr;
QStringList *secretBaseIds = nullptr;
QStringList *bgEventFacingDirections = nullptr;
QStringList mapsWithConnections;
QMap<QString, int> metatileBehaviorMap;
QMap<int, QString> metatileBehaviorMapInverse;
@ -70,25 +70,22 @@ public:
QList<QStringList>* getLabelMacros(QList<QStringList>*, QString);
QStringList* getLabelValues(QList<QStringList>*, QString);
bool readMapHeader(Map*);
void readMapLayoutsTable();
void readAllMapLayouts();
QStringList* readLayoutValues(QString layoutName);
void readMapLayout(Map*);
void readMapsWithConnections();
bool loadMapData(Map*);
void readMapLayouts();
void loadMapLayout(Map*);
void loadMapTilesets(Map*);
void loadTilesetAssets(Tileset*);
void loadTilesetTiles(Tileset*, QImage);
void loadTilesetMetatiles(Tileset*);
void saveBlockdata(Map*);
void saveMapBorder(Map*);
void saveLayoutBlockdata(Map*);
void saveLayoutBorder(Map*);
void writeBlockdata(QString, Blockdata*);
void saveAllMaps();
void saveMap(Map*);
void saveAllDataStructures();
void saveAllMapLayouts();
void saveMapGroupsTable();
void saveMapLayouts();
void saveMapGroups();
void saveMapConstantsHeader();
void saveHealLocationStruct(Map*);
void saveTilesets(Tileset*, Tileset*);
@ -116,12 +113,9 @@ public:
QString fixPalettePath(QString path);
QString fixGraphicPath(QString path);
void readMapEvents(Map *map);
void loadMapConnections(Map *map);
void loadMapBorder(Map *map);
void saveMapEvents(Map *map);
void saveMapHealEvents(Map *map);
QStringList readCArray(QString text, QString label);
QString readCIncbin(QString text, QString label);
@ -134,17 +128,10 @@ public:
static int getNumPalettesPrimary();
static int getNumPalettesTotal();
private:
QString getMapLayoutsTableFilepath();
QString getMapLayoutFilepath(QString);
void saveMapHeader(Map*);
void saveMapConnections(Map*);
void saveTilesetMetatileAttributes(Tileset*);
void saveTilesetMetatiles(Tileset*);
void saveTilesetTilesImage(Tileset*);
void saveTilesetPalettes(Tileset*, bool);
void updateMapsWithConnections(Map*);
void saveMapsWithConnections();
void saveMapLayoutsTable();
void updateMapLayout(Map*);
void readCDefinesSorted(QString, QStringList, QStringList*);
void readCDefinesSorted(QString, QStringList, QStringList*, QString, int);

View file

@ -19,8 +19,8 @@ public:
~NewMapPopup();
Map *map;
int group;
bool changeLayout;
QString layoutName;
bool existingLayout;
QString layoutId;
void init(int, int, QString, QString);
void useLayout(QString);

View file

@ -139,100 +139,98 @@ int Event::getPixelY()
return (this->y() * 16) - qMax(0, this->spriteHeight - 16);
}
QString Event::buildObjectEventMacro(int item_index)
QJsonObject Event::buildObjectEventJSON()
{
int radius_x = this->getInt("radius_x");
int radius_y = this->getInt("radius_y");
uint16_t x = this->getU16("x");
uint16_t y = this->getU16("y");
QJsonObject eventObj;
eventObj["graphics_id"] = this->get("sprite");
eventObj["x"] = this->getU16("x");
eventObj["y"] = this->getU16("y");
eventObj["elevation"] = this->getInt("elevation");
eventObj["movement_type"] = this->get("movement_type");
eventObj["movement_range_x"] = this->getInt("radius_x");
eventObj["movement_range_y"] = this->getInt("radius_y");
eventObj["trainer_type"] = this->get("trainer_type");
eventObj["trainer_sight_or_berry_tree_id"] = this->get("sight_radius_tree_id");
eventObj["script"] = this->get("script_label");
eventObj["flag"] = this->get("event_flag");
QString text = "";
text += QString("\tobject_event %1").arg(item_index + 1);
text += QString(", %1").arg(this->get("sprite"));
text += QString(", %1").arg(this->get("replacement"));
text += QString(", %1").arg(x);
text += QString(", %1").arg(y);
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("movement_type"));
text += QString(", %1").arg(radius_x);
text += QString(", %1").arg(radius_y);
text += QString(", %1").arg(this->get("trainer_type"));
text += QString(", %1").arg(this->get("sight_radius_tree_id"));
text += QString(", %1").arg(this->get("script_label"));
text += QString(", %1").arg(this->get("event_flag"));
text += "\n";
return text;
return eventObj;
}
QString Event::buildWarpEventMacro(QMap<QString, QString> *mapNamesToMapConstants)
QJsonObject Event::buildWarpEventJSON(QMap<QString, QString> *mapNamesToMapConstants)
{
QString text = "";
text += QString("\twarp_def %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("destination_warp"));
text += QString(", %1").arg(mapNamesToMapConstants->value(this->get("destination_map_name")));
text += "\n";
return text;
QJsonObject warpObj;
warpObj["x"] = this->getU16("x");
warpObj["y"] = this->getU16("y");
warpObj["elevation"] = this->getInt("elevation");
warpObj["dest_map"] = mapNamesToMapConstants->value(this->get("destination_map_name"));
warpObj["dest_warp_id"] = this->getInt("destination_warp");
return warpObj;
}
QString Event::buildTriggerEventMacro()
QJsonObject Event::buildTriggerEventJSON()
{
QString text = "";
text += QString("\tcoord_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("script_var"));
text += QString(", %1").arg(this->get("script_var_value"));
text += QString(", %1").arg(this->get("script_label"));
text += "\n";
return text;
QJsonObject triggerObj;
triggerObj["type"] = "trigger";
triggerObj["x"] = this->getU16("x");
triggerObj["y"] = this->getU16("y");
triggerObj["elevation"] = this->getInt("elevation");
triggerObj["var"] = this->get("script_var");
triggerObj["var_value"] = this->get("script_var_value");
triggerObj["script"] = this->get("script_label");
return triggerObj;
}
QString Event::buildWeatherTriggerEventMacro()
QJsonObject Event::buildWeatherTriggerEventJSON()
{
QString text = "";
text += QString("\tcoord_weather_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("weather"));
text += "\n";
return text;
QJsonObject weatherObj;
weatherObj["type"] = "weather";
weatherObj["x"] = this->getU16("x");
weatherObj["y"] = this->getU16("y");
weatherObj["elevation"] = this->getInt("elevation");
weatherObj["weather"] = this->get("weather");
return weatherObj;
}
QString Event::buildSignEventMacro()
QJsonObject Event::buildSignEventJSON()
{
QString text = "";
text += QString("\tbg_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("player_facing_direction"));
text += QString(", %1").arg(this->get("script_label"));
text += "\n";
return text;
QJsonObject signObj;
signObj["type"] = "sign";
signObj["x"] = this->getU16("x");
signObj["y"] = this->getU16("y");
signObj["elevation"] = this->getInt("elevation");
signObj["player_facing_dir"] = this->get("player_facing_direction");
signObj["script"] = this->get("script_label");
return signObj;
}
QString Event::buildHiddenItemEventMacro()
QJsonObject Event::buildHiddenItemEventJSON()
{
QString text = "";
text += QString("\tbg_hidden_item_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("item"));
text += QString(", %1").arg(this->get("flag"));
text += "\n";
return text;
QJsonObject hiddenItemObj;
hiddenItemObj["type"] = "hidden_item";
hiddenItemObj["x"] = this->getU16("x");
hiddenItemObj["y"] = this->getU16("y");
hiddenItemObj["elevation"] = this->getInt("elevation");
hiddenItemObj["item"] = this->get("item");
hiddenItemObj["flag"] = this->get("flag");
return hiddenItemObj;
}
QString Event::buildSecretBaseEventMacro()
QJsonObject Event::buildSecretBaseEventJSON()
{
QString text = "";
text += QString("\tbg_secret_base_event %1").arg(this->get("x"));
text += QString(", %1").arg(this->get("y"));
text += QString(", %1").arg(this->get("elevation"));
text += QString(", %1").arg(this->get("secret_base_id"));
text += "\n";
return text;
QJsonObject secretBaseObj;
secretBaseObj["type"] = "secret_base";
secretBaseObj["x"] = this->getU16("x");
secretBaseObj["y"] = this->getU16("y");
secretBaseObj["elevation"] = this->getInt("elevation");
secretBaseObj["secret_base_id"] = this->get("secret_base_id");
return secretBaseObj;
}
void Event::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight)

View file

@ -1,2 +1,16 @@
#include "maplayout.h"
#include <QRegularExpression>
QString MapLayout::layoutConstantFromName(QString mapName) {
// Transform map names of the form 'GraniteCave_B1F` into layout constants like 'LAYOUT_GRANITE_CAVE_B1F'.
QString nameWithUnderscores = mapName.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2");
QString withMapAndUppercase = "LAYOUT_" + nameWithUnderscores.toUpper();
QString constantName = withMapAndUppercase.replace(QRegularExpression("_+"), "_");
// Handle special cases.
// SSTidal should be SS_TIDAL, rather than SSTIDAL
constantName = constantName.replace("SSTIDAL", "SS_TIDAL");
return constantName;
}

View file

@ -1225,6 +1225,8 @@ DraggablePixmapItem* Editor::addNewEvent(QString event_type) {
Event *event = Event::createNewEvent(event_type, map->name);
event->put("map_name", map->name);
if (event_type == "event_heal_location") {
HealLocation hl = HealLocation::fromEvent(event);
project->flyableMaps.append(hl);
event->put("index", project->flyableMaps.length());
}
map->addEvent(event);

View file

@ -580,8 +580,7 @@ void MainWindow::on_checkBox_AllowEscapeRope_clicked(bool checked)
void MainWindow::loadDataStructures() {
Project *project = editor->project;
project->readMapLayoutsTable();
project->readAllMapLayouts();
project->readMapLayouts();
project->readRegionMapSections();
project->readItemNames();
project->readFlagNames();
@ -593,7 +592,6 @@ void MainWindow::loadDataStructures() {
project->readCoordEventWeatherNames();
project->readSecretBaseIds();
project->readBgEventFacingDirections();
project->readMapsWithConnections();
project->readMetatileBehaviors();
project->readTilesetProperties();
}
@ -674,17 +672,21 @@ void MainWindow::sortMapList() {
}
case MapSortOrder::Layout:
{
QMap<QString, int> layoutIndices;
for (int i = 0; i < project->mapLayoutsTable.length(); i++) {
QString layoutName = project->mapLayoutsTable.value(i);
QStandardItem *layout = new QStandardItem;
layout->setText(layoutName);
layout->setIcon(folderIcon);
layout->setEditable(false);
layout->setData(layoutName, Qt::UserRole);
layout->setData("map_layout", MapListUserRoles::TypeRole);
layout->setData(i, MapListUserRoles::GroupRole);
root->appendRow(layout);
mapGroupItemsList->append(layout);
QString layoutId = project->mapLayoutsTable.value(i);
MapLayout *layout = project->mapLayouts.value(layoutId);
QStandardItem *layoutItem = new QStandardItem;
layoutItem->setText(layout->name);
layoutItem->setIcon(folderIcon);
layoutItem->setEditable(false);
layoutItem->setData(layout->name, Qt::UserRole);
layoutItem->setData("map_layout", MapListUserRoles::TypeRole);
layoutItem->setData(layout->id, MapListUserRoles::TypeRole2);
layoutItem->setData(i, MapListUserRoles::GroupRole);
root->appendRow(layoutItem);
mapGroupItemsList->append(layoutItem);
layoutIndices[layoutId] = i;
}
for (int i = 0; i < project->groupNames->length(); i++) {
QStringList names = project->groupedMapNames.value(i);
@ -692,7 +694,7 @@ void MainWindow::sortMapList() {
QString map_name = names.value(j);
QStandardItem *map = createMapItem(map_name, i, j);
QString layoutId = project->readMapLayoutId(map_name);
QStandardItem *layoutItem = mapGroupItemsList->at(layoutId.toInt() - 1);
QStandardItem *layoutItem = mapGroupItemsList->at(layoutIndices.value(layoutId));
layoutItem->setIcon(mapFolderIcon);
layoutItem->appendRow(map);
mapListIndexes.insert(map_name, map->index());
@ -746,10 +748,10 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point)
connect(actions, SIGNAL(triggered(QAction*)), this, SLOT(onAddNewMapToAreaClick(QAction*)));
menu->exec(QCursor::pos());
} else if (itemType == "map_layout") {
QString layoutName = selectedItem->data(Qt::UserRole).toString();
QString layoutId = selectedItem->data(MapListUserRoles::TypeRole2).toString();
QMenu* menu = new QMenu(this);
QActionGroup* actions = new QActionGroup(menu);
actions->addAction(menu->addAction("Add New Map with Layout"))->setData(layoutName);
actions->addAction(menu->addAction("Add New Map with Layout"))->setData(layoutId);
connect(actions, SIGNAL(triggered(QAction*)), this, SLOT(onAddNewMapToLayoutClick(QAction*)));
menu->exec(QCursor::pos());
}
@ -769,17 +771,17 @@ void MainWindow::onAddNewMapToAreaClick(QAction* triggeredAction)
void MainWindow::onAddNewMapToLayoutClick(QAction* triggeredAction)
{
QString layoutName = triggeredAction->data().toString();
openNewMapPopupWindow(MapSortOrder::Layout, layoutName);
QString layoutId = triggeredAction->data().toString();
openNewMapPopupWindow(MapSortOrder::Layout, layoutId);
}
void MainWindow::onNewMapCreated() {
QString newMapName = this->newmapprompt->map->name;
int newMapGroup = this->newmapprompt->group;
Map *newMap_ = this->newmapprompt->map;
bool updateLayout = this->newmapprompt->changeLayout;
bool existingLayout = this->newmapprompt->existingLayout;
Map *newMap = editor->project->addNewMapToGroup(newMapName, newMapGroup, newMap_, updateLayout);
Map *newMap = editor->project->addNewMapToGroup(newMapName, newMapGroup, newMap_, existingLayout);
logInfo(QString("Created a new map named %1.").arg(newMapName));

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ NewMapPopup::NewMapPopup(QWidget *parent, Project *project) :
{
ui->setupUi(this);
this->project = project;
this->changeLayout = false;
this->existingLayout = false;
}
NewMapPopup::~NewMapPopup()
@ -24,7 +24,7 @@ NewMapPopup::~NewMapPopup()
delete ui;
}
void NewMapPopup::init(int type, int group, QString sec, QString layout) {
void NewMapPopup::init(int type, int group, QString sec, QString layoutId) {
switch (type)
{
case MapSortOrder::Group:
@ -34,15 +34,15 @@ void NewMapPopup::init(int type, int group, QString sec, QString layout) {
setDefaultValues(group, sec);
break;
case MapSortOrder::Layout:
useLayout(layout);
useLayout(layoutId);
setDefaultValues(group, QString());
break;
}
}
void NewMapPopup::useLayout(QString mapName) {
this->changeLayout = true;
this->layoutName = mapName;
void NewMapPopup::useLayout(QString layoutId) {
this->existingLayout = true;
this->layoutId = layoutId;
}
void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) {
@ -55,11 +55,11 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) {
ui->comboBox_NewMap_Group->addItems(*project->groupNames);
ui->comboBox_NewMap_Group->setCurrentText("gMapGroup" + QString::number(groupNum));
if (changeLayout) {
ui->spinBox_NewMap_Width->setValue(project->mapLayouts.value(layoutName)->width.toInt(nullptr, 0));
ui->spinBox_NewMap_Height->setValue(project->mapLayouts.value(layoutName)->height.toInt(nullptr, 0));
ui->comboBox_NewMap_Primary_Tileset->setCurrentText(project->mapLayouts.value(layoutName)->tileset_primary_label);
ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutName)->tileset_secondary_label);
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->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);
ui->spinBox_NewMap_Height->setDisabled(true);
ui->comboBox_NewMap_Primary_Tileset->setDisabled(true);
@ -110,38 +110,35 @@ void NewMapPopup::on_lineEdit_NewMap_Name_textChanged(const QString &text) {
void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
Map *newMap = new Map;
MapLayout *layout = new MapLayout;
MapLayout *layout;
// If map name is not unique, use default value. Also use only valid characters.
QString newMapName = this->ui->lineEdit_NewMap_Name->text().remove(QRegularExpression("[^a-zA-Z0-9_]+"));
if (project->mapNames->contains(newMapName) || newMapName.isEmpty()) {
newMapName = project->getNewMapName();
}
newMap->name = newMapName;
newMap->name = newMapName;
newMap->type = this->ui->comboBox_NewMap_Type->currentText();
newMap->location = this->ui->comboBox_NewMap_Location->currentText();
newMap->song = "MUS_DAN02";
newMap->requiresFlash = "0";
newMap->weather = "WEATHER_SUNNY";
newMap->show_location = "1";
newMap->battle_scene = "MAP_BATTLE_SCENE_NORMAL";
if (this->existingLayout) {
layout = this->project->mapLayouts.value(this->layoutId);
} else {
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->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText();
layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText();
layout->border_label = QString("%1_MapBorder").arg(newMap->name);
layout->blockdata_label = QString("%1_MapBlockdata").arg(newMap->name);
if (changeLayout) {
layout->label = layoutName;
layout->name = MapLayout::getNameFromLabel(layout->label);
QString block_path = QString("%1/data/layout/%2/map.bin").arg(project->root).arg(MapLayout::getNameFromLabel(layoutName));
QString border_path = QString("%1/data/layout/%2/border.bin").arg(project->root).arg(MapLayout::getNameFromLabel(layoutName));
layout->blockdata = project->readBlockdata(block_path);
layout->border = project->readBlockdata(border_path);
newMap->needsLayoutDir = false;
} else {
layout->border_path = QString("data/layouts/%1/border.bin").arg(newMap->name);
layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(newMap->name);
layout->label = QString("%1_Layout").arg(newMap->name);
layout->name = MapLayout::getNameFromLabel(layout->label);
layout->border_path = QString("data/layouts/%1/border.bin").arg(newMapName);
layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(newMapName);
}
if (this->ui->checkBox_NewMap_Flyable->isChecked()) {
@ -155,14 +152,10 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
}
group = this->ui->comboBox_NewMap_Group->currentText().remove("gMapGroup").toInt();
newMap->layout = layout;
newMap->layout_label = layout->label;
newMap->layoutId = layout->id;
newMap->group_num = QString::number(group);
map = newMap;
emit applied();
this->close();
}