diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 7fc0974c..6f9e1f9c 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -236,23 +236,23 @@ - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -365,8 +365,8 @@ 0 0 - 543 - 600 + 508 + 665 @@ -893,8 +893,8 @@ 0 0 - 443 - 74 + 442 + 77 @@ -1081,10 +1081,10 @@ - 8 + 0 0 - 431 - 341 + 425 + 419 @@ -1499,8 +1499,8 @@ 0 0 - 430 - 521 + 98 + 28 @@ -1544,8 +1544,8 @@ 0 0 - 430 - 521 + 98 + 28 @@ -1589,8 +1589,8 @@ 0 0 - 430 - 521 + 98 + 28 @@ -1634,8 +1634,8 @@ 0 0 - 430 - 521 + 98 + 28 @@ -1679,8 +1679,8 @@ 0 0 - 430 - 521 + 98 + 28 @@ -1730,8 +1730,8 @@ 0 0 - 430 - 521 + 98 + 28 @@ -2431,8 +2431,8 @@ 0 0 - 118 - 118 + 101 + 101 @@ -2693,7 +2693,7 @@ 0 0 1287 - 22 + 21 @@ -2742,6 +2742,7 @@ + @@ -3022,6 +3023,11 @@ Export Map Stitch Image... + + + Import Map from Advance Map 1.92... + + @@ -3034,6 +3040,7 @@ AdjustingStackedWidget QStackedWidget
adjustingstackedwidget.h
+ 1 GraphicsView diff --git a/include/core/mapparser.h b/include/core/mapparser.h new file mode 100644 index 00000000..21e3074e --- /dev/null +++ b/include/core/mapparser.h @@ -0,0 +1,16 @@ +#ifndef MAPPARSER_H +#define MAPPARSER_H + +#include "maplayout.h" +#include "project.h" +#include +#include + +class MapParser +{ +public: + MapParser(); + MapLayout *parse(QString filepath, bool *error, Project *project); +}; + +#endif // MAPPARSER_H diff --git a/include/mainwindow.h b/include/mainwindow.h index f6b382c2..f7761678 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -131,8 +131,10 @@ private slots: void onTilesetsSaved(QString, QString); void onWildMonDataChanged(); void openNewMapPopupWindow(int, QVariant); + void openNewMapPopupWindowImportMap(MapLayout *); void onNewMapCreated(); void onMapCacheCleared(); + void importMapFromAdvanceMap1_92(); void on_action_NewMap_triggered(); void on_actionNew_Tileset_triggered(); @@ -189,6 +191,7 @@ private slots: void on_action_Export_Map_Image_triggered(); void on_actionExport_Stitched_Map_Image_triggered(); + void on_actionImport_Map_from_Advance_Map_1_92_triggered(); void on_comboBox_ConnectionDirection_currentIndexChanged(const QString &arg1); void on_spinBox_ConnectionOffset_valueChanged(int offset); diff --git a/include/project.h b/include/project.h index 179a5a93..93d533b8 100644 --- a/include/project.h +++ b/include/project.h @@ -89,6 +89,7 @@ public: Tileset* loadTileset(QString, Tileset *tileset = nullptr); Tileset* getTileset(QString, bool forceLoad = false); QMap tilesetLabels; + QList tilesetLabelsOrdered; Blockdata* readBlockdata(QString); bool loadBlockdata(Map*); @@ -99,7 +100,7 @@ public: bool readMapGroups(); Map* addNewMapToGroup(QString mapName, int groupNum); - Map* addNewMapToGroup(QString, int, Map*, bool); + Map* addNewMapToGroup(QString, int, Map*, bool, bool); QString getNewMapName(); QString getProjectTitle(); diff --git a/include/ui/newmappopup.h b/include/ui/newmappopup.h index c573b16e..13c4dfe5 100644 --- a/include/ui/newmappopup.h +++ b/include/ui/newmappopup.h @@ -20,8 +20,10 @@ public: Map *map; int group; bool existingLayout; + bool importedMap; QString layoutId; void init(int, int, QString, QString); + void initImportMap(MapLayout *); void useLayout(QString); void connectSignals(); @@ -32,6 +34,7 @@ private: Ui::NewMapPopup *ui; Project *project; void setDefaultValues(int, QString); + void setDefaultValuesImportMap(MapLayout *); bool checkNewMapDimensions(); private slots: diff --git a/porymap.pro b/porymap.pro index 04fb94e2..34cbed60 100644 --- a/porymap.pro +++ b/porymap.pro @@ -21,6 +21,7 @@ SOURCES += src/core/block.cpp \ src/core/imageexport.cpp \ src/core/map.cpp \ src/core/maplayout.cpp \ + src/core/mapparser.cpp \ src/core/metatile.cpp \ src/core/metatileparser.cpp \ src/core/paletteutil.cpp \ @@ -87,6 +88,7 @@ HEADERS += include/core/block.h \ include/core/map.h \ include/core/mapconnection.h \ include/core/maplayout.h \ + include/core/mapparser.h \ include/core/metatile.h \ include/core/metatileparser.h \ include/core/paletteutil.h \ diff --git a/src/core/mapparser.cpp b/src/core/mapparser.cpp new file mode 100644 index 00000000..18a0f918 --- /dev/null +++ b/src/core/mapparser.cpp @@ -0,0 +1,93 @@ +#include "mapparser.h" +#include "config.h" +#include "log.h" +#include "project.h" + +MapParser::MapParser() +{ + +} + +MapLayout *MapParser::parse(QString filepath, bool *error, Project *project) +{ + QFile file(filepath); + if (!file.open(QIODevice::ReadOnly)) { + *error = true; + logError(QString("Could not open Advance Map 1.92 Map .map file '%1': ").arg(filepath) + file.errorString()); + return nullptr; + } + + QByteArray in = file.readAll(); + file.close(); + + if (in.length() < 20 || in.length() % 2 != 0) { + *error = true; + logError(QString("Advance Map 1.92 Map .map file '%1' is an unexpected size.").arg(filepath)); + return nullptr; + } + + int mapDataOffset = 20; + int mapWidth = static_cast(in.at(0)) | + (static_cast(in.at(1)) << 8) | + (static_cast(in.at(2)) << 16) | + (static_cast(in.at(3)) << 24); + int mapHeight = static_cast(in.at(4)) | + (static_cast(in.at(5)) << 8) | + (static_cast(in.at(6)) << 16) | + (static_cast(in.at(7)) << 24); + int mapPrimaryTilesetNum = static_cast(in.at(8)) | + (static_cast(in.at(9)) << 8) | + (static_cast(in.at(10)) << 16) | + (static_cast(in.at(11)) << 24); + int mapSecondaryTilesetNum = static_cast(in.at(12)) | + (static_cast(in.at(13)) << 8) | + (static_cast(in.at(14)) << 16) | + (static_cast(in.at(15)) << 24); + + /*int maxMetatiles = primaryTileset ? Project::getNumMetatilesPrimary() : Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary(); + int numMetatiles = static_cast(in.at(0)) | + (static_cast(in.at(1)) << 8) | + (static_cast(in.at(2)) << 16) | + (static_cast(in.at(3)) << 24); + if (numMetatiles > maxMetatiles) { + *error = true; + logError(QString(".bvd file contains data for %1 metatiles, but the maximum number of metatiles is %2.").arg(numMetatiles).arg(maxMetatiles)); + return nullptr; + } + + if (numMetatiles < 1) { + *error = true; + logError(QString(".bvd file contains no data for metatiles.")); + return nullptr; + }*/ + + int numMetatiles = mapWidth * mapHeight; + int expectedFileSize = numMetatiles * 2 + 20; + if (in.length() != expectedFileSize) { + *error = true; + logError(QString(".map file is an unexpected size. Expected %1 bytes, but it has %2 bytes.").arg(expectedFileSize).arg(in.length())); + return nullptr; + } + + Blockdata *blockdata = new Blockdata(); + for (int i = mapDataOffset; (i + 1) < in.length(); i += 2) { + uint16_t word = static_cast((in[i] & 0xff) + ((in[i + 1] & 0xff) << 8)); + blockdata->addBlock(word); + } + + MapLayout *mapLayout = new MapLayout(); + mapLayout->width = QString::number(mapWidth); + mapLayout->height = QString::number(mapHeight); + QList tilesets = project->tilesetLabelsOrdered; + if (mapPrimaryTilesetNum > tilesets.size()) + mapLayout->tileset_primary_label = tilesets.at(0); + else + mapLayout->tileset_primary_label = tilesets.at(mapPrimaryTilesetNum); + + if (mapSecondaryTilesetNum > tilesets.size()) + mapLayout->tileset_secondary_label = tilesets.at(1); + else + mapLayout->tileset_secondary_label = tilesets.at(mapSecondaryTilesetNum); + mapLayout->blockdata = blockdata->copy(); + return mapLayout; +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ee1bd97e..f4465c6a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -13,6 +13,7 @@ #include "adjustingstackedwidget.h" #include "draggablepixmapitem.h" #include "editcommands.h" +#include "mapparser.h" #include #include @@ -1025,8 +1026,9 @@ void MainWindow::onNewMapCreated() { int newMapGroup = this->newmapprompt->group; Map *newMap_ = this->newmapprompt->map; bool existingLayout = this->newmapprompt->existingLayout; + bool importedMap = this->newmapprompt->importedMap; - Map *newMap = editor->project->addNewMapToGroup(newMapName, newMapGroup, newMap_, existingLayout); + Map *newMap = editor->project->addNewMapToGroup(newMapName, newMapGroup, newMap_, existingLayout, importedMap); logInfo(QString("Created a new map named %1.").arg(newMapName)); @@ -1079,6 +1081,24 @@ void MainWindow::openNewMapPopupWindow(int type, QVariant data) { this->newmapprompt->setAttribute(Qt::WA_DeleteOnClose); } +void MainWindow::openNewMapPopupWindowImportMap(MapLayout *mapLayout) { + if (!this->newmapprompt) { + this->newmapprompt = new NewMapPopup(this, this->editor->project); + } + if (!this->newmapprompt->isVisible()) { + this->newmapprompt->show(); + } else { + this->newmapprompt->raise(); + this->newmapprompt->activateWindow(); + } + + this->newmapprompt->initImportMap(mapLayout); + + connect(this->newmapprompt, SIGNAL(applied()), this, SLOT(onNewMapCreated())); + connect(this->newmapprompt, &QObject::destroyed, [=](QObject *) { this->newmapprompt = nullptr; }); + this->newmapprompt->setAttribute(Qt::WA_DeleteOnClose); +} + void MainWindow::on_action_NewMap_triggered() { openNewMapPopupWindow(MapSortOrder::Group, 0); } @@ -2319,6 +2339,54 @@ void MainWindow::on_actionExport_Stitched_Map_Image_triggered() { showExportMapImageWindow(true); } +void MainWindow::on_actionImport_Map_from_Advance_Map_1_92_triggered(){ + importMapFromAdvanceMap1_92(); +} + +void MainWindow::importMapFromAdvanceMap1_92() +{ + QString filepath = QFileDialog::getOpenFileName( + this, + QString("Import Map from Advance Map 1.92"), + this->editor->project->root, + "Advance Map 1.92 Map Files (*.map)"); + if (filepath.isEmpty()) { + return; + } + + MapParser parser; + bool error = false; + MapLayout *mapLayout = parser.parse(filepath, &error, editor->project); + if (error) { + QMessageBox msgBox(this); + msgBox.setText("Failed to import map from Advance Map 1.92 .map file."); + QString message = QString("The .map file could not be processed. View porymap.log for specific errors."); + msgBox.setInformativeText(message); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Icon::Critical); + msgBox.exec(); + return; + } + + // TODO: This is crude because it makes a history entry for every newly-imported metatile. + // Revisit this when tiles and num metatiles are added to tileset editory history. + /* int metatileIdBase = primary ? 0 : Project::getNumMetatilesPrimary(); + for (int i = 0; i < metatiles->length(); i++) { + if (i >= tileset->metatiles->length()) { + break; + } + + Metatile *prevMetatile = tileset->metatiles->at(i)->copy(); + MetatileHistoryItem *commit = new MetatileHistoryItem(static_cast(metatileIdBase + i), prevMetatile, metatiles->at(i)->copy()); + metatileHistory.push(commit); + }*/ + + //tileset->metatiles = metatiles; + //this->refresh(); + //this->hasUnsavedChanges = true; + openNewMapPopupWindowImportMap(mapLayout); +} + void MainWindow::showExportMapImageWindow(bool stitchMode) { if (!editor->project) return; diff --git a/src/project.cpp b/src/project.cpp index 3ef73e35..594827fa 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1907,7 +1907,7 @@ Map* Project::addNewMapToGroup(QString mapName, int groupNum) { return map; } -Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool existingLayout) { +Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool existingLayout, bool importedMap) { mapNames->append(mapName); mapGroups->insert(mapName, groupNum); groupedMapNames[groupNum].append(mapName); @@ -1923,7 +1923,13 @@ Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool if (!existingLayout) { mapLayouts.insert(map->layoutId, map->layout); mapLayoutsTable.append(map->layoutId); - setNewMapBlockdata(map); + if (importedMap) { + map->layout->lastCommitMapBlocks.blocks = new Blockdata; + map->layout->lastCommitMapBlocks.blocks->copyFrom(map->layout->blockdata); + map->layout->lastCommitMapBlocks.dimensions = QSize(map->getWidth(), map->getHeight()); + } else { + setNewMapBlockdata(map); + } setNewMapBorder(map); } @@ -1972,6 +1978,7 @@ QMap Project::getTilesetLabels() { QStringList secondaryTilesets; allTilesets.insert("primary", primaryTilesets); allTilesets.insert("secondary", secondaryTilesets); + QList tilesetLabelsOrdered; QString filename = "data/tilesets/headers.inc"; QString headers_text = parser.readTextFile(root + "/" + filename); @@ -2000,8 +2007,10 @@ QMap Project::getTilesetLabels() { allTilesets["secondary"].append(tilesetLabel); else allTilesets["primary"].append(tilesetLabel); + tilesetLabelsOrdered.append(tilesetLabel); } this->tilesetLabels = allTilesets; + this->tilesetLabelsOrdered = tilesetLabelsOrdered; return allTilesets; } diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 697881a4..ce3a7166 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -17,6 +17,7 @@ NewMapPopup::NewMapPopup(QWidget *parent, Project *project) : ui->setupUi(this); this->project = project; this->existingLayout = false; + this->importedMap = false; } NewMapPopup::~NewMapPopup() @@ -41,6 +42,12 @@ void NewMapPopup::init(int type, int group, QString sec, QString layoutId) { connectSignals(); } +void NewMapPopup::initImportMap(MapLayout *mapLayout) { + this->importedMap = true; + setDefaultValuesImportMap(mapLayout); + connectSignals(); +} + bool NewMapPopup::checkNewMapDimensions() { int numMetatiles = project->getMapDataSize(ui->spinBox_NewMap_Width->value(), ui->spinBox_NewMap_Height->value()); int maxMetatiles = project->getMaxMapDataSize(); @@ -164,6 +171,81 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) { } } +void NewMapPopup::setDefaultValuesImportMap(MapLayout *mapLayout) { + ui->lineEdit_NewMap_Name->setText(project->getNewMapName()); + + QMap tilesets = project->getTilesetLabels(); + ui->comboBox_NewMap_Primary_Tileset->addItems(tilesets.value("primary")); + ui->comboBox_NewMap_Secondary_Tileset->addItems(tilesets.value("secondary")); + + ui->comboBox_NewMap_Group->addItems(*project->groupNames); + ui->comboBox_NewMap_Group->setCurrentText(project->groupNames->at(0)); + + + ui->spinBox_NewMap_Width->setValue(mapLayout->width.toInt(nullptr, 0)); + ui->spinBox_NewMap_Height->setValue(mapLayout->height.toInt(nullptr, 0)); + ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_label); + ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(mapLayout->tileset_secondary_label); + ui->spinBox_NewMap_BorderWidth->setValue(DEFAULT_BORDER_WIDTH); + ui->spinBox_NewMap_BorderHeight->setValue(DEFAULT_BORDER_HEIGHT); + + ui->comboBox_NewMap_Type->addItems(*project->mapTypes); + ui->comboBox_NewMap_Location->addItems(project->mapSectionValueToName.values()); + ui->checkBox_NewMap_Show_Location->setChecked(true); + + ui->frame_NewMap_Options->setEnabled(true); + + switch (projectConfig.getBaseGameVersion()) + { + case BaseGameVersion::pokeruby: + ui->checkBox_NewMap_Allow_Running->setVisible(false); + ui->checkBox_NewMap_Allow_Biking->setVisible(false); + ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(false); + ui->label_NewMap_Allow_Running->setVisible(false); + ui->label_NewMap_Allow_Biking->setVisible(false); + ui->label_NewMap_Allow_Escape_Rope->setVisible(false); + break; + case BaseGameVersion::pokeemerald: + ui->checkBox_NewMap_Allow_Running->setVisible(true); + ui->checkBox_NewMap_Allow_Biking->setVisible(true); + ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(true); + ui->label_NewMap_Allow_Running->setVisible(true); + ui->label_NewMap_Allow_Biking->setVisible(true); + ui->label_NewMap_Allow_Escape_Rope->setVisible(true); + break; + case BaseGameVersion::pokefirered: + ui->checkBox_NewMap_Allow_Running->setVisible(true); + ui->checkBox_NewMap_Allow_Biking->setVisible(true); + ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(true); + ui->label_NewMap_Allow_Running->setVisible(true); + ui->label_NewMap_Allow_Biking->setVisible(true); + ui->label_NewMap_Allow_Escape_Rope->setVisible(true); + break; + } + if (projectConfig.getUseCustomBorderSize()) { + ui->spinBox_NewMap_BorderWidth->setVisible(true); + ui->spinBox_NewMap_BorderHeight->setVisible(true); + ui->label_NewMap_BorderWidth->setVisible(true); + ui->label_NewMap_BorderHeight->setVisible(true); + } else { + ui->spinBox_NewMap_BorderWidth->setVisible(false); + ui->spinBox_NewMap_BorderHeight->setVisible(false); + ui->label_NewMap_BorderWidth->setVisible(false); + ui->label_NewMap_BorderHeight->setVisible(false); + } + if (projectConfig.getFloorNumberEnabled()) { + ui->spinBox_NewMap_Floor_Number->setVisible(true); + ui->label_NewMap_Floor_Number->setVisible(true); + } else { + ui->spinBox_NewMap_Floor_Number->setVisible(false); + ui->label_NewMap_Floor_Number->setVisible(false); + } + + map = new Map(); + map->layout = new MapLayout(); + map->layout->blockdata = mapLayout->blockdata->copy(); +} + void NewMapPopup::on_lineEdit_NewMap_Name_textChanged(const QString &text) { if (project->mapNames->contains(text)) { QPalette palette = this->ui->lineEdit_NewMap_Name->palette(); @@ -201,7 +283,7 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { if (this->existingLayout) { layout = this->project->mapLayouts.value(this->layoutId); - newMap->needsLayoutDir = false; + newMap->needsLayoutDir = false; } else { layout = new MapLayout; layout->id = MapLayout::layoutConstantFromName(newMapName); @@ -221,6 +303,10 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(newMapName); } + if (this->importedMap) { + layout->blockdata = map->layout->blockdata->copy(); + } + if (this->ui->checkBox_NewMap_Flyable->isChecked()) { newMap->isFlyable = "TRUE"; }