diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui
index d9e19dcc..f153538c 100644
--- a/forms/mainwindow.ui
+++ b/forms/mainwindow.ui
@@ -3012,9 +3012,7 @@
Options
-
-
@@ -3065,14 +3063,6 @@
Ctrl+S
-
-
- true
-
-
- Show Wild Encounter Tables
-
-
true
@@ -3081,14 +3071,6 @@
Monitor Project Files
-
-
- true
-
-
- Use Poryscript
-
-
true
diff --git a/forms/projectsettingseditor.ui b/forms/projectsettingseditor.ui
index 442291dc..529992ea 100644
--- a/forms/projectsettingseditor.ui
+++ b/forms/projectsettingseditor.ui
@@ -72,15 +72,8 @@
New Map Defaults
- -
-
-
- The default metatile value that will be used to fill new maps
-
-
- Fill Metatile
-
-
+
-
+
-
@@ -92,19 +85,6 @@
- -
-
-
- A comma-separated list of metatile values that will be used to fill new map borders
-
-
- Border Metatiles
-
-
-
- -
-
-
-
@@ -118,12 +98,6 @@
- -
-
-
- -
-
-
-
@@ -134,6 +108,52 @@
+ -
+
+
+ -
+
+
+ The default metatile value that will be used to fill new maps
+
+
+ Fill Metatile
+
+
+
+ -
+
+
+ A comma-separated list of metatile values that will be used to fill new map borders
+
+
+ Border Metatiles
+
+
+
+ -
+
+
+ 0x
+
+
+ 16
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
@@ -217,16 +237,6 @@
Tilesets / Metatiles
- -
-
-
- The mask used to read/write Metatile Behavior from the metatile's attributes data. If 0, this attribute is disabled.
-
-
- Behavior mask
-
-
-
-
@@ -237,15 +247,18 @@
- -
-
-
- The mask used to read/write Layer Type from the metatile's attributes data. If 0, this attribute is disabled.
+
-
+
+
+ Qt::Vertical
-
- Layer Type mask
+
+
+ 20
+ 15
+
-
+
-
@@ -264,32 +277,16 @@
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 15
-
-
-
+
-
+
- -
-
-
- -
-
-
- -
-
+
-
+
- The mask used to read/write Encounter Type from the metatile's attributes data. If 0, this attribute is disabled.
+ Whether the C data outputted for new tilesets will include the "isCompressed" field
- Encounter Type mask
+ Output 'isCompressed' field
@@ -306,27 +303,35 @@
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
+
-
+
+
+ 0x
-
-
- 40
- 20
-
+
+ 16
-
+
+
+ -
+
+
+ 0x
+
+
+ 16
+
+
+
+ -
+
+
+ The mask used to read/write Encounter Type from the metatile's attributes data. If 0, this attribute is disabled.
+
+
+ Encounter Type mask
+
+
-
@@ -338,13 +343,43 @@
- -
-
+
-
+
- Whether the C data outputted for new tilesets will include the "isCompressed" field
+ The mask used to read/write Metatile Behavior from the metatile's attributes data. If 0, this attribute is disabled.
- Output 'isCompressed' field
+ Behavior mask
+
+
+
+ -
+
+
+ The mask used to read/write Layer Type from the metatile's attributes data. If 0, this attribute is disabled.
+
+
+ Layer Type mask
+
+
+
+ -
+
+
+ 0x
+
+
+ 16
+
+
+
+ -
+
+
+ 0x
+
+
+ 16
diff --git a/include/config.h b/include/config.h
index cb927caa..72d42bbf 100644
--- a/include/config.h
+++ b/include/config.h
@@ -10,8 +10,8 @@
#include
// In both versions the default new map border is a generic tree
-#define DEFAULT_BORDER_RSE (QList{468, 469, 476, 477})
-#define DEFAULT_BORDER_FRLG (QList{20, 21, 28, 29})
+#define DEFAULT_BORDER_RSE (QList{0x1D4, 0x1D5, 0x1DC, 0x1DD})
+#define DEFAULT_BORDER_FRLG (QList{0x14, 0x15, 0x1C, 0x1D})
#define CONFIG_BACKWARDS_COMPATABILITY
@@ -26,6 +26,7 @@ class KeyValueConfigBase
public:
void save();
void load();
+ void setSaveDisabled(bool disabled);
virtual ~KeyValueConfigBase();
virtual void reset() = 0;
protected:
@@ -37,6 +38,8 @@ protected:
bool getConfigBool(QString key, QString value);
int getConfigInteger(QString key, QString value, int min, int max, int defaultValue);
uint32_t getConfigUint32(QString key, QString value, uint32_t min, uint32_t max, uint32_t defaultValue);
+private:
+ bool saveDisabled = false;
};
class PorymapConfig: public KeyValueConfigBase
@@ -203,20 +206,11 @@ public:
}
virtual void reset() override {
this->baseGameVersion = BaseGameVersion::pokeemerald;
- this->useCustomBorderSize = false;
- this->enableEventWeatherTrigger = true;
- this->enableEventSecretBase = true;
- this->enableHiddenItemQuantity = false;
- this->enableHiddenItemRequiresItemfinder = false;
- this->enableHealLocationRespawnData = false;
- this->enableEventCloneObject = false;
- this->enableFloorNumber = false;
- this->createMapTextFile = false;
+ // Reset non-version-specific settings
this->usePoryScript = false;
this->enableTripleLayerMetatiles = false;
this->newMapMetatileId = 1;
this->newMapElevation = 3;
- this->newMapBorderMetatileIds = DEFAULT_BORDER_RSE;
this->defaultPrimaryTileset = "gTileset_General";
this->prefabFilepath = QString();
this->prefabImportPrompted = false;
@@ -225,10 +219,12 @@ public:
this->filePaths.clear();
this->readKeys.clear();
}
- static const QStringList baseGameVersions;
+ static const QStringList versionStrings;
+ void reset(BaseGameVersion baseGameVersion);
void setBaseGameVersion(BaseGameVersion baseGameVersion);
BaseGameVersion getBaseGameVersion();
QString getBaseGameVersionString();
+ BaseGameVersion stringToBaseGameVersion(QString string, bool * ok = nullptr);
void setUsePoryScript(bool usePoryScript);
bool getUsePoryScript();
void setProjectDir(QString projectDir);
@@ -255,16 +251,17 @@ public:
bool getTripleLayerMetatilesEnabled();
int getNumLayersInMetatile();
int getNumTilesInMetatile();
- void setNewMapMetatileId(int metatileId);
- int getNewMapMetatileId();
- QString getNewMapMetatileIdString();
+ void setNewMapMetatileId(uint16_t metatileId);
+ uint16_t getNewMapMetatileId();
void setNewMapElevation(int elevation);
int getNewMapElevation();
- void setNewMapBorderMetatileIds(QList metatileIds);
- QList getNewMapBorderMetatileIds();
+ void setNewMapBorderMetatileIds(QList metatileIds);
+ QList getNewMapBorderMetatileIds();
QString getNewMapBorderMetatileIdsString();
QString getDefaultPrimaryTileset();
QString getDefaultSecondaryTileset();
+ void setDefaultPrimaryTileset(QString tilesetName);
+ void setDefaultSecondaryTileset(QString tilesetName);
void setFilePath(ProjectFilePath pathId, QString path);
QString getFilePath(ProjectFilePath pathId);
void setPrefabFilepath(QString filepath);
@@ -276,12 +273,17 @@ public:
void setTilesetsHaveIsCompressed(bool has);
bool getTilesetsHaveIsCompressed();
int getMetatileAttributesSize();
+ void setMetatileAttributesSize(int size);
uint32_t getMetatileBehaviorMask();
uint32_t getMetatileTerrainTypeMask();
uint32_t getMetatileEncounterTypeMask();
uint32_t getMetatileLayerTypeMask();
- static QString getMaskString(uint32_t mask);
+ void setMetatileBehaviorMask(uint32_t mask);
+ void setMetatileTerrainTypeMask(uint32_t mask);
+ void setMetatileEncounterTypeMask(uint32_t mask);
+ void setMetatileLayerTypeMask(uint32_t mask);
bool getMapAllowFlagsEnabled();
+ void setMapAllowFlagsEnabled(bool enabled);
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
@@ -303,9 +305,9 @@ private:
bool enableFloorNumber;
bool createMapTextFile;
bool enableTripleLayerMetatiles;
- int newMapMetatileId;
+ uint16_t newMapMetatileId;
int newMapElevation;
- QList newMapBorderMetatileIds;
+ QList newMapBorderMetatileIds;
QString defaultPrimaryTileset;
QString defaultSecondaryTileset;
QStringList readKeys;
diff --git a/include/core/metatile.h b/include/core/metatile.h
index 49fb5c7b..c3bda046 100644
--- a/include/core/metatile.h
+++ b/include/core/metatile.h
@@ -93,6 +93,7 @@ public:
static QPoint coordFromPixmapCoord(const QPointF &pixelCoord);
static int getDefaultAttributesSize(BaseGameVersion version);
static void setCustomLayout(Project*);
+ static QString getMetatileIdString(uint16_t metatileId) { return "0x" + QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper(); };
private:
// Stores how each attribute should be laid out for all metatiles, according to the user's config
diff --git a/include/mainwindow.h b/include/mainwindow.h
index c6c30b42..32bb03eb 100644
--- a/include/mainwindow.h
+++ b/include/mainwindow.h
@@ -198,9 +198,7 @@ private slots:
void on_checkBox_AllowBiking_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);
- void on_actionUse_Poryscript_triggered(bool checked);
void on_actionOpen_Recent_Project_On_Launch_triggered(bool checked);
void on_actionEdit_Shortcuts_triggered();
diff --git a/include/ui/projectsettingseditor.h b/include/ui/projectsettingseditor.h
index 16b28b0b..6e1f7ed5 100644
--- a/include/ui/projectsettingseditor.h
+++ b/include/ui/projectsettingseditor.h
@@ -31,11 +31,17 @@ private:
NoScrollComboBox *combo_baseGameVersion;
NoScrollComboBox *combo_attributesSize;
+ bool hasUnsavedChanges = false;
+
void initUi();
void saveFields();
+ void connectSignals();
+ void refresh();
+ bool prompt(const QString &text);
private slots:
void dialogButtonClicked(QAbstractButton *button);
+ void markEdited();
};
#endif // PROJECTSETTINGSEDITOR_H
diff --git a/src/config.cpp b/src/config.cpp
index 9419a7b4..037511ee 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -119,6 +119,9 @@ void KeyValueConfigBase::load() {
}
void KeyValueConfigBase::save() {
+ if (this->saveDisabled)
+ return;
+
QString text = "";
QMap map = this->getKeyValueMap();
for (QMap::iterator it = map.begin(); it != map.end(); it++) {
@@ -163,6 +166,11 @@ uint32_t KeyValueConfigBase::getConfigUint32(QString key, QString value, uint32_
return qMin(max, qMax(min, result));
}
+// For temporarily disabling saving during frequent config changes.
+void KeyValueConfigBase::setSaveDisabled(bool disabled) {
+ this->saveDisabled = disabled;
+}
+
const QMap mapSortOrderMap = {
{MapSortOrder::Group, "group"},
{MapSortOrder::Layout, "layout"},
@@ -513,24 +521,34 @@ int PorymapConfig::getPaletteEditorBitDepth() {
return this->paletteEditorBitDepth;
}
-const QStringList ProjectConfig::baseGameVersions = {
+const QStringList ProjectConfig::versionStrings = {
"pokeruby",
"pokefirered",
"pokeemerald",
};
const QMap baseGameVersionMap = {
- {BaseGameVersion::pokeruby, ProjectConfig::baseGameVersions[0]},
- {BaseGameVersion::pokefirered, ProjectConfig::baseGameVersions[1]},
- {BaseGameVersion::pokeemerald, ProjectConfig::baseGameVersions[2]},
+ {BaseGameVersion::pokeruby, ProjectConfig::versionStrings[0]},
+ {BaseGameVersion::pokefirered, ProjectConfig::versionStrings[1]},
+ {BaseGameVersion::pokeemerald, ProjectConfig::versionStrings[2]},
};
const QMap baseGameVersionReverseMap = {
- {ProjectConfig::baseGameVersions[0], BaseGameVersion::pokeruby},
- {ProjectConfig::baseGameVersions[1], BaseGameVersion::pokefirered},
- {ProjectConfig::baseGameVersions[2], BaseGameVersion::pokeemerald},
+ {ProjectConfig::versionStrings[0], BaseGameVersion::pokeruby},
+ {ProjectConfig::versionStrings[1], BaseGameVersion::pokefirered},
+ {ProjectConfig::versionStrings[2], BaseGameVersion::pokeemerald},
};
+BaseGameVersion ProjectConfig::stringToBaseGameVersion(QString string, bool * ok) {
+ if (baseGameVersionReverseMap.contains(string)) {
+ if (ok) *ok = true;
+ return baseGameVersionReverseMap.value(string);
+ } else {
+ if (ok) *ok = false;
+ return BaseGameVersion::pokeemerald;
+ }
+}
+
ProjectConfig projectConfig;
QString ProjectConfig::getConfigFilepath() {
@@ -540,13 +558,10 @@ QString ProjectConfig::getConfigFilepath() {
void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
if (key == "base_game_version") {
- QString baseGameVersion = value.toLower();
- if (baseGameVersionReverseMap.contains(baseGameVersion)) {
- this->baseGameVersion = baseGameVersionReverseMap.value(baseGameVersion);
- } else {
- this->baseGameVersion = BaseGameVersion::pokeemerald;
+ bool ok;
+ this->baseGameVersion = this->stringToBaseGameVersion(value.toLower(), &ok);
+ if (!ok)
logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby', 'pokefirered' or 'pokeemerald'.").arg(value));
- }
} else if (key == "use_poryscript") {
this->usePoryScript = getConfigBool(key, value);
} else if (key == "use_custom_border_size") {
@@ -571,24 +586,18 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
} else if (key == "enable_triple_layer_metatiles") {
this->enableTripleLayerMetatiles = getConfigBool(key, value);
} else if (key == "new_map_metatile") {
- this->newMapMetatileId = getConfigInteger(key, value, 0, 1023, 0);
+ this->newMapMetatileId = getConfigUint32(key, value, 0, 1023, 0);
} else if (key == "new_map_elevation") {
this->newMapElevation = getConfigInteger(key, value, 0, 15, 3);
} else if (key == "new_map_border_metatiles") {
this->newMapBorderMetatileIds.clear();
QList metatileIds = value.split(",");
- const int maxSize = DEFAULT_BORDER_WIDTH * DEFAULT_BORDER_HEIGHT;
- const int size = qMin(metatileIds.size(), maxSize);
- int i;
- for (i = 0; i < size; i++) {
- int metatileId = getConfigInteger(key, metatileIds.at(i), 0, 1023, 0);
+ for (int i = 0; i < metatileIds.size(); i++) {
+ // TODO: The max of 1023 here should eventually reflect Project::num_metatiles_total-1,
+ // but the config is parsed well before that constant is.
+ int metatileId = getConfigUint32(key, metatileIds.at(i), 0, 1023, 0);
this->newMapBorderMetatileIds.append(metatileId);
}
- // TODO: If insufficient metatiles are provided, it should loop the provided metatiles instead.
- for (; i < maxSize; i++) {
- // Set any metatiles not provided to 0
- this->newMapBorderMetatileIds.append(0);
- }
} else if (key == "default_primary_tileset") {
this->defaultPrimaryTileset = value;
} else if (key == "default_secondary_tileset") {
@@ -646,6 +655,13 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
readKeys.append(key);
}
+// Restore config to version-specific defaults
+void::ProjectConfig::reset(BaseGameVersion baseGameVersion) {
+ this->reset();
+ this->setBaseGameVersion(baseGameVersion);
+ this->setUnreadKeys();
+}
+
void ProjectConfig::setUnreadKeys() {
// Set game-version specific defaults for any config field that wasn't read
bool isPokefirered = this->baseGameVersion == BaseGameVersion::pokefirered;
@@ -682,7 +698,7 @@ QMap ProjectConfig::getKeyValueMap() {
map.insert("enable_floor_number", QString::number(this->enableFloorNumber));
map.insert("create_map_text_file", QString::number(this->createMapTextFile));
map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles));
- map.insert("new_map_metatile", this->getNewMapMetatileIdString());
+ map.insert("new_map_metatile", Metatile::getMetatileIdString(this->newMapMetatileId));
map.insert("new_map_elevation", QString::number(this->newMapElevation));
map.insert("new_map_border_metatiles", this->getNewMapBorderMetatileIdsString());
map.insert("default_primary_tileset", this->defaultPrimaryTileset);
@@ -695,10 +711,10 @@ QMap ProjectConfig::getKeyValueMap() {
map.insert("tilesets_have_callback", QString::number(this->tilesetsHaveCallback));
map.insert("tilesets_have_is_compressed", QString::number(this->tilesetsHaveIsCompressed));
map.insert("metatile_attributes_size", QString::number(this->metatileAttributesSize));
- map.insert("metatile_behavior_mask", getMaskString(this->metatileBehaviorMask));
- map.insert("metatile_terrain_type_mask", getMaskString(this->metatileTerrainTypeMask));
- map.insert("metatile_encounter_type_mask", getMaskString(this->metatileEncounterTypeMask));
- map.insert("metatile_layer_type_mask", getMaskString(this->metatileLayerTypeMask));
+ map.insert("metatile_behavior_mask", "0x" + QString::number(this->metatileBehaviorMask, 16).toUpper());
+ map.insert("metatile_terrain_type_mask", "0x" + QString::number(this->metatileTerrainTypeMask, 16).toUpper());
+ map.insert("metatile_encounter_type_mask", "0x" + QString::number(this->metatileEncounterTypeMask, 16).toUpper());
+ map.insert("metatile_layer_type_mask", "0x" + QString::number(this->metatileLayerTypeMask, 16).toUpper());
map.insert("enable_map_allow_flags", QString::number(this->enableMapAllowFlags));
return map;
}
@@ -875,19 +891,15 @@ int ProjectConfig::getNumTilesInMetatile() {
return this->enableTripleLayerMetatiles ? 12 : 8;
}
-void ProjectConfig::setNewMapMetatileId(int metatileId) {
+void ProjectConfig::setNewMapMetatileId(uint16_t metatileId) {
this->newMapMetatileId = metatileId;
this->save();
}
-int ProjectConfig::getNewMapMetatileId() {
+uint16_t ProjectConfig::getNewMapMetatileId() {
return this->newMapMetatileId;
}
-QString ProjectConfig::getNewMapMetatileIdString() {
- return "0x" + QString::number(this->newMapMetatileId, 16).toUpper();
-}
-
void ProjectConfig::setNewMapElevation(int elevation) {
this->newMapElevation = elevation;
this->save();
@@ -897,19 +909,19 @@ int ProjectConfig::getNewMapElevation() {
return this->newMapElevation;
}
-void ProjectConfig::setNewMapBorderMetatileIds(QList metatileIds) {
+void ProjectConfig::setNewMapBorderMetatileIds(QList metatileIds) {
this->newMapBorderMetatileIds = metatileIds;
this->save();
}
-QList ProjectConfig::getNewMapBorderMetatileIds() {
+QList ProjectConfig::getNewMapBorderMetatileIds() {
return this->newMapBorderMetatileIds;
}
QString ProjectConfig::getNewMapBorderMetatileIdsString() {
QStringList metatiles;
for (auto metatileId : this->newMapBorderMetatileIds){
- metatiles << ("0x" + QString::number(metatileId, 16).toUpper());
+ metatiles << Metatile::getMetatileIdString(metatileId);
}
return metatiles.join(",");
}
@@ -922,6 +934,16 @@ QString ProjectConfig::getDefaultSecondaryTileset() {
return this->defaultSecondaryTileset;
}
+void ProjectConfig::setDefaultPrimaryTileset(QString tilesetName) {
+ this->defaultPrimaryTileset = tilesetName;
+ this->save();
+}
+
+void ProjectConfig::setDefaultSecondaryTileset(QString tilesetName) {
+ this->defaultSecondaryTileset = tilesetName;
+ this->save();
+}
+
void ProjectConfig::setPrefabFilepath(QString filepath) {
this->prefabFilepath = filepath;
this->save();
@@ -965,6 +987,11 @@ int ProjectConfig::getMetatileAttributesSize() {
return this->metatileAttributesSize;
}
+void ProjectConfig::setMetatileAttributesSize(int size) {
+ this->metatileAttributesSize = size;
+ this->save();
+}
+
uint32_t ProjectConfig::getMetatileBehaviorMask() {
return this->metatileBehaviorMask;
}
@@ -981,14 +1008,35 @@ uint32_t ProjectConfig::getMetatileLayerTypeMask() {
return this->metatileLayerTypeMask;
}
-QString ProjectConfig::getMaskString(uint32_t mask) {
- return "0x" + QString::number(mask, 16).toUpper();
+void ProjectConfig::setMetatileBehaviorMask(uint32_t mask) {
+ this->metatileBehaviorMask = mask;
+ this->save();
+}
+
+void ProjectConfig::setMetatileTerrainTypeMask(uint32_t mask) {
+ this->metatileTerrainTypeMask = mask;
+ this->save();
+}
+
+void ProjectConfig::setMetatileEncounterTypeMask(uint32_t mask) {
+ this->metatileEncounterTypeMask = mask;
+ this->save();
+}
+
+void ProjectConfig::setMetatileLayerTypeMask(uint32_t mask) {
+ this->metatileLayerTypeMask = mask;
+ this->save();
}
bool ProjectConfig::getMapAllowFlagsEnabled() {
return this->enableMapAllowFlags;
}
+void ProjectConfig::setMapAllowFlagsEnabled(bool enabled) {
+ this->enableMapAllowFlags = enabled;
+ this->save();
+}
+
UserConfig userConfig;
diff --git a/src/editor.cpp b/src/editor.cpp
index 23234b87..9996460e 100644
--- a/src/editor.cpp
+++ b/src/editor.cpp
@@ -933,8 +933,7 @@ void Editor::onHoveredMovementPermissionCleared() {
QString Editor::getMetatileDisplayMessage(uint16_t metatileId) {
Metatile *metatile = Tileset::getMetatile(metatileId, map->layout->tileset_primary, map->layout->tileset_secondary);
QString label = Tileset::getMetatileLabel(metatileId, map->layout->tileset_primary, map->layout->tileset_secondary);
- QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper();
- QString message = QString("Metatile: 0x%1").arg(hexString);
+ QString message = QString("Metatile: %1").arg(Metatile::getMetatileIdString(metatileId));
if (label.size())
message += QString(" \"%1\"").arg(label);
if (metatile && metatile->behavior) // Skip MB_NORMAL
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 9ceb9b94..b40f5ef0 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -369,13 +369,11 @@ void MainWindow::markMapEdited() {
}
void MainWindow::setWildEncountersUIEnabled(bool enabled) {
- ui->actionUse_Encounter_Json->setChecked(enabled);
ui->mainTabBar->setTabEnabled(4, enabled);
}
void MainWindow::setProjectSpecificUIVisibility()
{
- ui->actionUse_Poryscript->setChecked(projectConfig.getUsePoryScript());
this->setWildEncountersUIEnabled(userConfig.getEncounterJsonActive());
bool hasFlags = projectConfig.getMapAllowFlagsEnabled();
@@ -1757,25 +1755,11 @@ void MainWindow::on_actionCursor_Tile_Outline_triggered()
}
}
-void MainWindow::on_actionUse_Encounter_Json_triggered(bool checked)
-{
- QMessageBox warning(this);
- warning.setText("You must reload the project for this setting to take effect.");
- warning.setIcon(QMessageBox::Information);
- warning.exec();
- userConfig.setEncounterJsonActive(checked);
-}
-
void MainWindow::on_actionMonitor_Project_Files_triggered(bool checked)
{
porymapConfig.setMonitorFiles(checked);
}
-void MainWindow::on_actionUse_Poryscript_triggered(bool checked)
-{
- projectConfig.setUsePoryScript(checked);
-}
-
void MainWindow::on_actionOpen_Recent_Project_On_Launch_triggered(bool checked)
{
porymapConfig.setReopenOnLaunch(checked);
diff --git a/src/project.cpp b/src/project.cpp
index 92a71e2f..66e5aba8 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -957,9 +957,9 @@ void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *second
}
for (QString defineName : definesOut.keys()) {
int value = defines[defineName];
- QString line = QString("#define %1 0x%2\n")
+ QString line = QString("#define %1 %2\n")
.arg(defineName, -1 * longestLength)
- .arg(QString("%1").arg(value, 3, 16, QChar('0')).toUpper());
+ .arg(Metatile::getMetatileIdString(value));
outputText += line;
}
i += j;
@@ -1142,16 +1142,21 @@ void Project::setNewMapBorder(Map *map) {
map->layout->border.clear();
int width = map->getBorderWidth();
int height = map->getBorderHeight();
- if (width != DEFAULT_BORDER_WIDTH || height != DEFAULT_BORDER_HEIGHT) {
+
+ const QList configMetatileIds = projectConfig.getNewMapBorderMetatileIds();
+ if (configMetatileIds.length() != width * height) {
+ // Border size doesn't match the number of default border metatiles.
+ // Fill the border with empty metatiles.
for (int i = 0; i < width * height; i++) {
map->layout->border.append(0);
}
} else {
- QList metatileIds = projectConfig.getNewMapBorderMetatileIds();
- for (int i = 0; i < DEFAULT_BORDER_WIDTH * DEFAULT_BORDER_HEIGHT; i++) {
- map->layout->border.append(qint16(metatileIds.at(i)));
+ // Fill the border with the default metatiles from the config.
+ for (int i = 0; i < width * height; i++) {
+ map->layout->border.append(configMetatileIds.at(i));
}
}
+
map->layout->lastCommitBlocks.border = map->layout->border;
map->layout->lastCommitBlocks.borderDimensions = QSize(width, height);
}
@@ -2174,8 +2179,8 @@ bool Project::readCoordEventWeatherNames() {
fileWatcher.addPath(root + "/" + filename);
coordEventWeatherNames = parser.readCDefinesSorted(filename, prefixes);
if (coordEventWeatherNames.isEmpty()) {
- logError(QString("Failed to read coord event weather constants from %1").arg(filename));
- return false;
+ logWarn(QString("Failed to read coord event weather constants from %1. Disabling Weather Trigger events.").arg(filename));
+ projectConfig.setEventWeatherTriggerEnabled(false);
}
return true;
}
@@ -2189,8 +2194,8 @@ bool Project::readSecretBaseIds() {
fileWatcher.addPath(root + "/" + filename);
secretBaseIds = parser.readCDefinesSorted(filename, prefixes);
if (secretBaseIds.isEmpty()) {
- logError(QString("Failed to read secret base id constants from %1").arg(filename));
- return false;
+ logWarn(QString("Failed to read secret base id constants from '%1'. Disabling Secret Base events.").arg(filename));
+ projectConfig.setEventSecretBaseEnabled(false);
}
return true;
}
diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp
index c6f2ef6a..5aeb9deb 100644
--- a/src/ui/projectsettingseditor.cpp
+++ b/src/ui/projectsettingseditor.cpp
@@ -22,8 +22,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project)
ui->setupUi(this);
initUi();
setAttribute(Qt::WA_DeleteOnClose);
- connect(ui->buttonBox, &QDialogButtonBox::clicked,
- this, &ProjectSettingsEditor::dialogButtonClicked);
+ connectSignals();
+ refresh();
}
ProjectSettingsEditor::~ProjectSettingsEditor()
@@ -31,8 +31,76 @@ ProjectSettingsEditor::~ProjectSettingsEditor()
delete ui;
}
+void ProjectSettingsEditor::connectSignals() {
+ connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &ProjectSettingsEditor::dialogButtonClicked);
+
+ // Connect combo boxes
+ QList combos = ui->centralwidget->findChildren();
+ foreach(auto i, combos)
+ connect(i, &QComboBox::currentTextChanged, this, &ProjectSettingsEditor::markEdited);
+
+ // Connect check boxes
+ QList checkboxes = ui->centralwidget->findChildren();
+ foreach(auto i, checkboxes)
+ connect(i, &QCheckBox::stateChanged, this, &ProjectSettingsEditor::markEdited);
+
+ // Connect spin boxes
+ QList spinBoxes = ui->centralwidget->findChildren();
+ foreach(auto i, spinBoxes)
+ connect(i, QOverload::of(&QSpinBox::valueChanged), [this](int) { this->markEdited(); });
+
+ // Connect line edits
+ QList lineEdits = ui->centralwidget->findChildren();
+ foreach(auto i, lineEdits)
+ connect(i, &QLineEdit::textEdited, this, &ProjectSettingsEditor::markEdited);
+}
+
+void ProjectSettingsEditor::markEdited() {
+ this->hasUnsavedChanges = true;
+}
+
void ProjectSettingsEditor::initUi() {
- // Block signals while setting initial UI states
+ // Create Default Tilesets combo boxes
+ auto *defaultTilesetsLayout = new QFormLayout(ui->groupBox_DefaultTilesets);
+ combo_defaultPrimaryTileset = new NoScrollComboBox(ui->groupBox_DefaultTilesets);
+ combo_defaultSecondaryTileset = new NoScrollComboBox(ui->groupBox_DefaultTilesets);
+ if (project) combo_defaultPrimaryTileset->addItems(project->primaryTilesetLabels);
+ if (project) combo_defaultSecondaryTileset->addItems(project->secondaryTilesetLabels);
+ defaultTilesetsLayout->addRow("Primary Tileset", combo_defaultPrimaryTileset);
+ defaultTilesetsLayout->addRow("Secondary Tileset", combo_defaultSecondaryTileset);
+
+ // Create Base game version combo box
+ combo_baseGameVersion = new NoScrollComboBox(ui->widget_BaseGameVersion);
+ combo_baseGameVersion->addItems(ProjectConfig::versionStrings);
+ combo_baseGameVersion->setEditable(false);
+ ui->layout_BaseGameVersion->insertRow(0, "Base game version", combo_baseGameVersion);
+
+ // Create Attributes size combo box
+ auto *attributesSizeLayout = new QFormLayout(ui->widget_SizeDropdown);
+ combo_attributesSize = new NoScrollComboBox(ui->widget_SizeDropdown);
+ combo_attributesSize->addItems({"1", "2", "4"});
+ combo_attributesSize->setEditable(false);
+ attributesSizeLayout->addRow("", combo_attributesSize);
+
+ // Validate that the border metatiles text is a comma-separated list of hex values
+ static const QRegularExpression expression("^((0[xX])?[A-Fa-f0-9]+,)*(0[xX])?[A-Fa-f0-9]$");
+ QRegularExpressionValidator *validator = new QRegularExpressionValidator(expression);
+ ui->lineEdit_BorderMetatiles->setValidator(validator);
+
+ ui->spinBox_Elevation->setMaximum(15);
+ ui->spinBox_FillMetatile->setMaximum(Project::getNumMetatilesTotal() - 1);
+
+ // TODO: These need to be subclassed to handle larger values
+ ui->spinBox_BehaviorMask->setMaximum(INT_MAX);
+ ui->spinBox_EncounterTypeMask->setMaximum(INT_MAX);
+ ui->spinBox_LayerTypeMask->setMaximum(INT_MAX);
+ ui->spinBox_TerrainTypeMask->setMaximum(INT_MAX);
+
+ // TODO: File picker for prefabs?
+}
+
+// Set UI states using config data
+void ProjectSettingsEditor::refresh() {
const QSignalBlocker blocker0(combo_defaultPrimaryTileset);
const QSignalBlocker blocker1(combo_defaultSecondaryTileset);
const QSignalBlocker blocker2(combo_baseGameVersion);
@@ -54,41 +122,21 @@ void ProjectSettingsEditor::initUi() {
const QSignalBlocker blocker12(ui->checkBox_OutputCallback);
const QSignalBlocker blocker13(ui->checkBox_OutputIsCompressed);
const QSignalBlocker blocker14(ui->spinBox_Elevation);
- const QSignalBlocker blocker15(ui->lineEdit_BorderMetatiles);
- const QSignalBlocker blocker16(ui->lineEdit_FillMetatile);
- const QSignalBlocker blocker17(ui->lineEdit_PrefabsPath);
- const QSignalBlocker blocker18(ui->lineEdit_BehaviorMask);
- const QSignalBlocker blocker19(ui->lineEdit_EncounterTypeMask);
- const QSignalBlocker blocker1A(ui->lineEdit_LayerTypeMask);
- const QSignalBlocker blocker1B(ui->lineEdit_TerrainTypeMask);
+ const QSignalBlocker blocker15(ui->spinBox_FillMetatile);
+ const QSignalBlocker blocker16(ui->spinBox_BehaviorMask);
+ const QSignalBlocker blocker17(ui->spinBox_EncounterTypeMask);
+ const QSignalBlocker blocker18(ui->spinBox_LayerTypeMask);
+ const QSignalBlocker blocker19(ui->spinBox_TerrainTypeMask);
+ const QSignalBlocker blocker1A(ui->lineEdit_BorderMetatiles);
+ const QSignalBlocker blocker1B(ui->lineEdit_PrefabsPath);
- // Create Default Tilesets combo boxes
- auto *defaultTilesetsLayout = new QFormLayout(ui->groupBox_DefaultTilesets);
- combo_defaultPrimaryTileset = new NoScrollComboBox(ui->groupBox_DefaultTilesets);
- combo_defaultSecondaryTileset = new NoScrollComboBox(ui->groupBox_DefaultTilesets);
- if (project) combo_defaultPrimaryTileset->addItems(project->primaryTilesetLabels);
- if (project) combo_defaultSecondaryTileset->addItems(project->secondaryTilesetLabels);
+ // Set combo box texts
combo_defaultPrimaryTileset->setTextItem(projectConfig.getDefaultPrimaryTileset());
combo_defaultSecondaryTileset->setTextItem(projectConfig.getDefaultSecondaryTileset());
- defaultTilesetsLayout->addRow("Primary Tileset", combo_defaultPrimaryTileset);
- defaultTilesetsLayout->addRow("Secondary Tileset", combo_defaultSecondaryTileset);
-
- // Create Base game version combo box
- combo_baseGameVersion = new NoScrollComboBox(ui->widget_BaseGameVersion);
- combo_baseGameVersion->addItems(ProjectConfig::baseGameVersions);
combo_baseGameVersion->setTextItem(projectConfig.getBaseGameVersionString());
- combo_baseGameVersion->setEditable(false);
- ui->layout_BaseGameVersion->insertRow(0, "Base game version", combo_baseGameVersion);
-
- // Create Attributes size combo box
- auto *attributesSizeLayout = new QFormLayout(ui->widget_SizeDropdown);
- combo_attributesSize = new NoScrollComboBox(ui->widget_SizeDropdown);
- combo_attributesSize->addItems({"1", "2", "4"});
combo_attributesSize->setTextItem(QString::number(projectConfig.getMetatileAttributesSize()));
- combo_attributesSize->setEditable(false);
- attributesSizeLayout->addRow("", combo_attributesSize);
- // Init check boxes
+ // Set check box states
ui->checkBox_UsePoryscript->setChecked(projectConfig.getUsePoryScript());
ui->checkBox_ShowWildEncounterTables->setChecked(userConfig.getEncounterJsonActive());
ui->checkBox_CreateTextFile->setChecked(projectConfig.getCreateMapTextFileEnabled());
@@ -106,71 +154,107 @@ void ProjectSettingsEditor::initUi() {
ui->checkBox_OutputCallback->setChecked(projectConfig.getTilesetsHaveCallback());
ui->checkBox_OutputIsCompressed->setChecked(projectConfig.getTilesetsHaveIsCompressed());
- // Init spinners
- ui->spinBox_Elevation->setRange(0, 15);
+ // Set spin box values
ui->spinBox_Elevation->setValue(projectConfig.getNewMapElevation());
+ ui->spinBox_FillMetatile->setValue(projectConfig.getNewMapMetatileId());
+ ui->spinBox_BehaviorMask->setValue(projectConfig.getMetatileBehaviorMask());
+ ui->spinBox_EncounterTypeMask->setValue(projectConfig.getMetatileEncounterTypeMask());
+ ui->spinBox_LayerTypeMask->setValue(projectConfig.getMetatileLayerTypeMask());
+ ui->spinBox_TerrainTypeMask->setValue(projectConfig.getMetatileTerrainTypeMask());
- // Init text boxes
- // TODO: Validator for Border Metatiles and Fill Metatile
+ // Set line edit texts
ui->lineEdit_BorderMetatiles->setText(projectConfig.getNewMapBorderMetatileIdsString());
- ui->lineEdit_FillMetatile->setText(projectConfig.getNewMapMetatileIdString());
ui->lineEdit_PrefabsPath->setText(projectConfig.getPrefabFilepath(false));
- QString mask = ProjectConfig::getMaskString(projectConfig.getMetatileBehaviorMask());
- ui->lineEdit_BehaviorMask->setText(mask);
- mask = ProjectConfig::getMaskString(projectConfig.getMetatileEncounterTypeMask());
- ui->lineEdit_EncounterTypeMask->setText(mask);
- mask = ProjectConfig::getMaskString(projectConfig.getMetatileLayerTypeMask());
- ui->lineEdit_LayerTypeMask->setText(mask);
- mask = ProjectConfig::getMaskString(projectConfig.getMetatileTerrainTypeMask());
- ui->lineEdit_TerrainTypeMask->setText(mask);
}
+// TODO: Certain setting changes may require project reload
+
void ProjectSettingsEditor::saveFields() {
- // TODO
- /*
- TODO combo_defaultPrimaryTileset
- TODO combo_defaultSecondaryTileset
- setBaseGameVersion combo_baseGameVersion
- TODO combo_attributesSize
- setUsePoryScript ui->checkBox_UsePoryscript
- userConfig.setEncounterJsonActive ui->checkBox_ShowWildEncounterTables
- setCreateMapTextFileEnabled ui->checkBox_CreateTextFile
- setPrefabImportPrompted ui->checkBox_PrefabImportPrompted
- setTripleLayerMetatilesEnabled ui->checkBox_EnableTripleLayerMetatiles
- setHiddenItemRequiresItemfinderEnabled ui->checkBox_EnableRequiresItemfinder
- setHiddenItemQuantityEnabled ui->checkBox_EnableQuantity
- setEventCloneObjectEnabled ui->checkBox_EnableCloneObjects
- setEventWeatherTriggerEnabled ui->checkBox_EnableWeatherTriggers
- setEventSecretBaseEnabled ui->checkBox_EnableSecretBases
- setHealLocationRespawnDataEnabled ui->checkBox_EnableRespawn
- TODO ui->checkBox_EnableAllowFlags
- setFloorNumberEnabled ui->checkBox_EnableFloorNumber
- setUseCustomBorderSize ui->checkBox_EnableCustomBorderSize
- setTilesetsHaveCallback ui->checkBox_OutputCallback
- setTilesetsHaveIsCompressed ui->checkBox_OutputIsCompressed
- setNewMapElevation ui->spinBox_Elevation
- setPrefabFilepath ui->lineEdit_PrefabsPath
- TODO ui->lineEdit_BehaviorMask
- TODO ui->lineEdit_EncounterTypeMask
- TODO ui->lineEdit_LayerTypeMask
- TODO ui->lineEdit_TerrainTypeMask
- setNewMapMetatileId ui->lineEdit_FillMetatile
- setNewMapBorderMetatileIds ui->lineEdit_BorderMetatiles
- */
+ if (!this->hasUnsavedChanges)
+ return;
+
+ // Prevent a call to save() for each of the config settings
+ projectConfig.setSaveDisabled(true);
+ userConfig.setSaveDisabled(true);
+
+ projectConfig.setDefaultPrimaryTileset(combo_defaultPrimaryTileset->currentText());
+ projectConfig.setDefaultSecondaryTileset(combo_defaultSecondaryTileset->currentText());
+ projectConfig.setBaseGameVersion(projectConfig.stringToBaseGameVersion(combo_baseGameVersion->currentText()));
+ projectConfig.setMetatileAttributesSize(combo_attributesSize->currentText().toInt());
+ projectConfig.setUsePoryScript(ui->checkBox_UsePoryscript->isChecked());
+ userConfig.setEncounterJsonActive(ui->checkBox_ShowWildEncounterTables->isChecked());
+ projectConfig.setCreateMapTextFileEnabled(ui->checkBox_CreateTextFile->isChecked());
+ projectConfig.setPrefabImportPrompted(ui->checkBox_PrefabImportPrompted->isChecked());
+ projectConfig.setTripleLayerMetatilesEnabled(ui->checkBox_EnableTripleLayerMetatiles->isChecked());
+ projectConfig.setHiddenItemRequiresItemfinderEnabled(ui->checkBox_EnableRequiresItemfinder->isChecked());
+ projectConfig.setHiddenItemQuantityEnabled(ui->checkBox_EnableQuantity->isChecked());
+ projectConfig.setEventCloneObjectEnabled(ui->checkBox_EnableCloneObjects->isChecked());
+ projectConfig.setEventWeatherTriggerEnabled(ui->checkBox_EnableWeatherTriggers->isChecked());
+ projectConfig.setEventSecretBaseEnabled(ui->checkBox_EnableSecretBases->isChecked());
+ projectConfig.setHealLocationRespawnDataEnabled(ui->checkBox_EnableRespawn->isChecked());
+ projectConfig.setMapAllowFlagsEnabled(ui->checkBox_EnableAllowFlags->isChecked());
+ projectConfig.setFloorNumberEnabled(ui->checkBox_EnableFloorNumber->isChecked());
+ projectConfig.setUseCustomBorderSize(ui->checkBox_EnableCustomBorderSize->isChecked());
+ projectConfig.setTilesetsHaveCallback(ui->checkBox_OutputCallback->isChecked());
+ projectConfig.setTilesetsHaveIsCompressed(ui->checkBox_OutputIsCompressed->isChecked());
+ projectConfig.setNewMapElevation(ui->spinBox_Elevation->value());
+ projectConfig.setNewMapMetatileId(ui->spinBox_FillMetatile->value());
+ projectConfig.setMetatileBehaviorMask(ui->spinBox_BehaviorMask->value());
+ projectConfig.setMetatileTerrainTypeMask(ui->spinBox_EncounterTypeMask->value());
+ projectConfig.setMetatileEncounterTypeMask(ui->spinBox_LayerTypeMask->value());
+ projectConfig.setMetatileLayerTypeMask(ui->spinBox_TerrainTypeMask->value());
+ projectConfig.setPrefabFilepath(ui->lineEdit_PrefabsPath->text());
+
+ // Parse border metatile list
+ QList metatileIdStrings = ui->lineEdit_BorderMetatiles->text().split(",");
+ QList metatileIds;
+ for (auto s : metatileIdStrings) {
+ uint16_t metatileId = s.toUInt(nullptr, 0);
+ metatileIds.append(qMin(metatileId, static_cast(Project::getNumMetatilesTotal() - 1)));
+ }
+ projectConfig.setNewMapBorderMetatileIds(metatileIds);
+
+ projectConfig.setSaveDisabled(false);
+ projectConfig.save();
+ userConfig.setSaveDisabled(false);
+ userConfig.save();
+
+ this->hasUnsavedChanges = false;
emit saved();
}
+// TODO: Standard prompt replacement?
+bool ProjectSettingsEditor::prompt(const QString &text) {
+ QMessageBox messageBox(this);
+ messageBox.setText(text);
+ messageBox.setIcon(QMessageBox::Question);
+ messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); // TODO: Cancel
+ return messageBox.exec() == QMessageBox::Yes;
+}
+
void ProjectSettingsEditor::dialogButtonClicked(QAbstractButton *button) {
auto buttonRole = ui->buttonBox->buttonRole(button);
if (buttonRole == QDialogButtonBox::AcceptRole) {
- // TODO: Prompt for unsaved changes
saveFields();
close();
- } else if (buttonRole == QDialogButtonBox::ResetRole) {
- // TODO
} else if (buttonRole == QDialogButtonBox::ApplyRole) {
saveFields();
+ } else if (buttonRole == QDialogButtonBox::ResetRole) {
+ // Restore Defaults
+ // TODO: Confirm dialogue?
+ const QString versionText = combo_baseGameVersion->currentText();
+ if (!prompt(QString("Restore default config settings for %1?").arg(versionText)))
+ return;
+ projectConfig.reset(projectConfig.stringToBaseGameVersion(versionText));
+ projectConfig.save();
+ userConfig.reset();
+ userConfig.save();
+ refresh();
} else if (buttonRole == QDialogButtonBox::RejectRole) {
+ if (this->hasUnsavedChanges && !prompt(QString("Discard unsaved changes?"))) {
+ // TODO:
+ // Unsaved changes prompt
+ }
close();
}
// TODO: Save geometry on close
diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp
index e8fc6be5..8c4d67e1 100644
--- a/src/ui/tileseteditor.cpp
+++ b/src/ui/tileseteditor.cpp
@@ -348,8 +348,7 @@ void TilesetEditor::drawSelectedTiles() {
void TilesetEditor::onHoveredMetatileChanged(uint16_t metatileId) {
QString label = Tileset::getMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset);
- QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper();
- QString message = QString("Metatile: 0x%1").arg(hexString);
+ QString message = QString("Metatile: %1").arg(Metatile::getMetatileIdString(metatileId));
if (label.size() != 0) {
message += QString(" \"%1\"").arg(label);
}