Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interpret triple-layer metatiles from NUM_TILES_PER_METATILE #607

Merged
merged 1 commit into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions docsrc/manual/project-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion include/ui/projectsettingseditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<UIntSpinBox*> masks);
QStringList getWarpBehaviorsList();
void setWarpBehaviorsList(QStringList list);
Expand Down
1 change: 1 addition & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const QMap<ProjectIdentifier, QPair<QString, QString>> 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"}},
Expand Down
22 changes: 21 additions & 1 deletion src/project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ bool Project::sanityCheck() {
}

bool Project::load() {
this->disabledSettingsNames.clear();
bool success = readMapLayouts()
&& readRegionMapSections()
&& readItemNames()
Expand Down Expand Up @@ -1960,13 +1961,15 @@ 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,
numMetatilesPrimaryName,
numPalsPrimaryName,
numPalsTotalName,
maxMapSizeName,
numTilesPerMetatileName,
};
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
fileWatcher.addPath(root + "/" + filename);
Expand Down Expand Up @@ -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;
}

Expand All @@ -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<QString>(defineNames.constBegin(), defineNames.constEnd());
for (auto name : defineNames)
this->disabledSettingsNames.insert(name);

// Read Block masks
auto readBlockMask = [defines](const QString name, uint16_t *value) {
Expand Down
77 changes: 32 additions & 45 deletions src/ui/projectsettingseditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading