diff --git a/CHANGELOG.md b/CHANGELOG.md index 86009d49..a0ad5950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - A notice will be displayed when attempting to open the "Dynamic" map, rather than nothing happening. - The base game version is now auto-detected if the project name contains only one of "emerald", "firered/leafgreen", or "ruby/sapphire". - It's now possible to cancel quitting if there are unsaved changes in sub-windows. +- The triple-layer metatiles setting can now be set automatically using a project constant. ### Fixed - Fix `Add Region Map...` not updating the region map settings file. diff --git a/docsrc/manual/project-files.rst b/docsrc/manual/project-files.rst index 20849ba3..678ded32 100644 --- a/docsrc/manual/project-files.rst +++ b/docsrc/manual/project-files.rst @@ -101,6 +101,7 @@ In addition to these files, there are some specific symbol and macro names that ``define_metatiles_primary``, ``NUM_METATILES_IN_PRIMARY``, total metatiles are calculated using metatile ID mask ``define_pals_primary``, ``NUM_PALS_IN_PRIMARY``, ``define_pals_total``, ``NUM_PALS_TOTAL``, + ``define_tiles_per_metatile``, ``NUM_TILES_PER_METATILE``, to determine if triple-layer metatiles are in use. Values other than 8 or 12 are ignored ``define_map_size``, ``MAX_MAP_DATA_SIZE``, to limit map dimensions ``define_mask_metatile``, ``MAPGRID_METATILE_ID_MASK``, optionally read to get settings on ``Maps`` tab ``define_mask_collision``, ``MAPGRID_COLLISION_MASK``, optionally read to get settings on ``Maps`` tab diff --git a/include/config.h b/include/config.h index 7486919f..d5f975a2 100644 --- a/include/config.h +++ b/include/config.h @@ -196,6 +196,7 @@ enum ProjectIdentifier { define_metatiles_primary, define_pals_primary, define_pals_total, + define_tiles_per_metatile, define_map_size, define_mask_metatile, define_mask_collision, diff --git a/include/ui/projectsettingseditor.h b/include/ui/projectsettingseditor.h index 7ebf544b..41affa8b 100644 --- a/include/ui/projectsettingseditor.h +++ b/include/ui/projectsettingseditor.h @@ -61,7 +61,7 @@ class ProjectSettingsEditor : public QMainWindow void chooseImageFile(QLineEdit * filepathEdit); void chooseFile(QLineEdit * filepathEdit, const QString &description, const QString &extensions); QString stripProjectDir(QString s); - void disableParsedSetting(QWidget * widget, const QString &name, const QString &filepath); + bool disableParsedSetting(QWidget * widget, const QString &identifier, const QString &filepath); void updateMaskOverlapWarning(QLabel * warning, QList masks); QStringList getWarpBehaviorsList(); void setWarpBehaviorsList(QStringList list); diff --git a/src/config.cpp b/src/config.cpp index 818dd714..1515a725 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -90,6 +90,7 @@ const QMap> ProjectConfig::defaultIde {ProjectIdentifier::define_metatiles_primary, {"define_metatiles_primary", "NUM_METATILES_IN_PRIMARY"}}, {ProjectIdentifier::define_pals_primary, {"define_pals_primary", "NUM_PALS_IN_PRIMARY"}}, {ProjectIdentifier::define_pals_total, {"define_pals_total", "NUM_PALS_TOTAL"}}, + {ProjectIdentifier::define_tiles_per_metatile, {"define_tiles_per_metatile", "NUM_TILES_PER_METATILE"}}, {ProjectIdentifier::define_map_size, {"define_map_size", "MAX_MAP_DATA_SIZE"}}, {ProjectIdentifier::define_mask_metatile, {"define_mask_metatile", "MAPGRID_METATILE_ID_MASK"}}, {ProjectIdentifier::define_mask_collision, {"define_mask_collision", "MAPGRID_COLLISION_MASK"}}, diff --git a/src/project.cpp b/src/project.cpp index 10ace396..b5614ffb 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -113,6 +113,7 @@ bool Project::sanityCheck() { } bool Project::load() { + this->disabledSettingsNames.clear(); bool success = readMapLayouts() && readRegionMapSections() && readItemNames() @@ -1960,6 +1961,7 @@ bool Project::readFieldmapProperties() { const QString numPalsPrimaryName = projectConfig.getIdentifier(ProjectIdentifier::define_pals_primary); const QString numPalsTotalName = projectConfig.getIdentifier(ProjectIdentifier::define_pals_total); const QString maxMapSizeName = projectConfig.getIdentifier(ProjectIdentifier::define_map_size); + const QString numTilesPerMetatileName = projectConfig.getIdentifier(ProjectIdentifier::define_tiles_per_metatile); const QStringList names = { numTilesPrimaryName, numTilesTotalName, @@ -1967,6 +1969,7 @@ bool Project::readFieldmapProperties() { numPalsPrimaryName, numPalsTotalName, maxMapSizeName, + numTilesPerMetatileName, }; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap); fileWatcher.addPath(root + "/" + filename); @@ -2007,6 +2010,22 @@ bool Project::readFieldmapProperties() { .arg(Project::max_map_data_size)); } + it = defines.find(numTilesPerMetatileName); + if (it != defines.end()) { + // We can determine whether triple-layer metatiles are in-use by reading this constant. + // If the constant is missing (or is using a value other than 8 or 12) the user must tell + // us whether they're using triple-layer metatiles under Project Settings. + static const int numTilesPerLayer = 4; + int numTilesPerMetatile = it.value(); + if (numTilesPerMetatile == 2 * numTilesPerLayer) { + projectConfig.tripleLayerMetatilesEnabled = false; + this->disabledSettingsNames.insert(numTilesPerMetatileName); + } else if (numTilesPerMetatile == 3 * numTilesPerLayer) { + projectConfig.tripleLayerMetatilesEnabled = true; + this->disabledSettingsNames.insert(numTilesPerMetatileName); + } + } + return true; } @@ -2032,7 +2051,8 @@ bool Project::readFieldmapMasks() { // If users do have the defines we disable them in the settings editor and direct them to their project files. // Record the names we read so we know later which settings to disable. const QStringList defineNames = defines.keys(); - this->disabledSettingsNames = QSet(defineNames.constBegin(), defineNames.constEnd()); + for (auto name : defineNames) + this->disabledSettingsNames.insert(name); // Read Block masks auto readBlockMask = [defines](const QString name, uint16_t *value) { diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp index 8a360eb2..d84ef56b 100644 --- a/src/ui/projectsettingseditor.cpp +++ b/src/ui/projectsettingseditor.cpp @@ -133,53 +133,40 @@ void ProjectSettingsEditor::initUi() { ui->spinBox_CollisionMask->setMaximum(Block::maxValue); ui->spinBox_ElevationMask->setMaximum(Block::maxValue); - // Some settings can be determined by constants in the project. - // We reflect that here by disabling their UI elements. - if (project) { - const QString maskFilepath = projectConfig.getFilePath(ProjectFilePath::global_fieldmap); - const QString attrTableFilepath = projectConfig.getFilePath(ProjectFilePath::fieldmap); - const QString metatileIdMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_metatile); - const QString collisionMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_collision); - const QString elevationMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_elevation); - const QString behaviorMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior); - const QString layerTypeMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer); - const QString behaviorTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_behavior); - const QString layerTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_layer); - const QString encounterTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_encounter); - const QString terrainTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_terrain); - const QString attrTableName = projectConfig.getIdentifier(ProjectIdentifier::symbol_attribute_table); - - // Block masks - if (project->disabledSettingsNames.contains(metatileIdMaskName)) - this->disableParsedSetting(ui->spinBox_MetatileIdMask, metatileIdMaskName, maskFilepath); - if (project->disabledSettingsNames.contains(collisionMaskName)) - this->disableParsedSetting(ui->spinBox_CollisionMask, collisionMaskName, maskFilepath); - if (project->disabledSettingsNames.contains(elevationMaskName)) - this->disableParsedSetting(ui->spinBox_ElevationMask, elevationMaskName, maskFilepath); - - // Behavior mask - if (project->disabledSettingsNames.contains(behaviorMaskName)) - this->disableParsedSetting(ui->spinBox_BehaviorMask, behaviorMaskName, maskFilepath); - else if (project->disabledSettingsNames.contains(behaviorTableName)) - this->disableParsedSetting(ui->spinBox_BehaviorMask, attrTableName, attrTableFilepath); - - // Layer type mask - if (project->disabledSettingsNames.contains(layerTypeMaskName)) - this->disableParsedSetting(ui->spinBox_LayerTypeMask, layerTypeMaskName, maskFilepath); - else if (project->disabledSettingsNames.contains(layerTypeTableName)) - this->disableParsedSetting(ui->spinBox_LayerTypeMask, attrTableName, attrTableFilepath); - - // Encounter and terrain type masks - if (project->disabledSettingsNames.contains(encounterTypeTableName)) - this->disableParsedSetting(ui->spinBox_EncounterTypeMask, attrTableName, attrTableFilepath); - if (project->disabledSettingsNames.contains(terrainTypeTableName)) - this->disableParsedSetting(ui->spinBox_TerrainTypeMask, attrTableName, attrTableFilepath); - } + // The values for some of the settings we provide in this window can be determined using constants in the user's projects. + // If the user has these constants we disable these settings in the UI -- they can modify them using their constants. + const QString globalFieldmapPath = projectConfig.getFilePath(ProjectFilePath::global_fieldmap); + const QString constantsFieldmapPath = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap); + const QString fieldmapPath = projectConfig.getFilePath(ProjectFilePath::fieldmap); + + // Block masks + this->disableParsedSetting(ui->spinBox_MetatileIdMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_metatile), globalFieldmapPath); + this->disableParsedSetting(ui->spinBox_CollisionMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_collision), globalFieldmapPath); + this->disableParsedSetting(ui->spinBox_ElevationMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_elevation), globalFieldmapPath); + + // Behavior mask + if (!this->disableParsedSetting(ui->spinBox_BehaviorMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior), globalFieldmapPath)) + this->disableParsedSetting(ui->spinBox_BehaviorMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_behavior), fieldmapPath); + + // Layer type mask + if (!this->disableParsedSetting(ui->spinBox_LayerTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer), globalFieldmapPath)) + this->disableParsedSetting(ui->spinBox_LayerTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_layer), fieldmapPath); + + // Encounter and terrain type masks + this->disableParsedSetting(ui->spinBox_EncounterTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_encounter), fieldmapPath); + this->disableParsedSetting(ui->spinBox_TerrainTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_terrain), fieldmapPath); + + // Tripe layer metatiles + this->disableParsedSetting(ui->checkBox_EnableTripleLayerMetatiles, projectConfig.getIdentifier(ProjectIdentifier::define_tiles_per_metatile), constantsFieldmapPath); } -void ProjectSettingsEditor::disableParsedSetting(QWidget * widget, const QString &name, const QString &filepath) { - widget->setEnabled(false); - widget->setToolTip(QString("This value has been read from '%1' in %2").arg(name).arg(filepath)); +bool ProjectSettingsEditor::disableParsedSetting(QWidget * widget, const QString &identifier, const QString &filepath) { + if (project && project->disabledSettingsNames.contains(identifier)) { + widget->setEnabled(false); + widget->setToolTip(QString("This value has been set using '%1' in %2").arg(identifier).arg(filepath)); + return true; + } + return false; } // Remember the current settings tab for future sessions