diff --git a/forms/tileseteditor.ui b/forms/tileseteditor.ui
index 90b0cc15..e1e8810a 100644
--- a/forms/tileseteditor.ui
+++ b/forms/tileseteditor.ui
@@ -47,7 +47,7 @@
0
0
272
- 539
+ 625
@@ -198,30 +198,31 @@
false
- -
-
+
-
+
Metatile Label (Optional)
- -
-
-
- -
-
+
-
+
- Metatile Behavior
+ Layer Type
- -
-
-
- -
-
+
-
+
- Bottom/Top
+ Encounter Type
+
+
+
+ -
+
+
+ Terrain Type
@@ -247,15 +248,15 @@
- -
-
+
-
+
- Layer Type
+ Bottom/Top
- -
-
+
-
+
-
@@ -270,6 +271,38 @@
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Metatile Behavior
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
@@ -377,8 +410,8 @@
0
0
- 400
- 367
+ 384
+ 265
@@ -394,19 +427,6 @@
0
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
@@ -420,16 +440,6 @@
- -
-
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOff
-
-
-
-
@@ -443,6 +453,29 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+
-
@@ -471,7 +504,7 @@
0
0
700
- 21
+ 22
+
+
+ NoScrollComboBox
+ QWidget
+
+
+
diff --git a/include/core/metatile.h b/include/core/metatile.h
index b1be4d75..77a3c687 100644
--- a/include/core/metatile.h
+++ b/include/core/metatile.h
@@ -11,8 +11,10 @@ public:
Metatile();
public:
QList *tiles = nullptr;
- uint8_t behavior;
+ uint16_t behavior; // 8 bits RSE, 9 bits FRLG
uint8_t layerType;
+ uint8_t encounterType; // FRLG only
+ uint8_t terrainType; // FRLG only
QString label;
Metatile *copy();
diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h
index 1095b0be..f4205b38 100644
--- a/include/ui/tileseteditor.h
+++ b/include/ui/tileseteditor.h
@@ -77,6 +77,10 @@ private slots:
void on_comboBox_layerType_activated(int arg1);
+ void on_comboBox_encounterType_activated(int arg1);
+
+ void on_comboBox_terrainType_activated(int arg1);
+
void on_actionExport_Primary_Tiles_Image_triggered();
void on_actionExport_Secondary_Tiles_Image_triggered();
diff --git a/src/core/map.cpp b/src/core/map.cpp
index 4f89c6c6..8573cc29 100644
--- a/src/core/map.cpp
+++ b/src/core/map.cpp
@@ -412,7 +412,6 @@ void Map::undo() {
if (!commit)
return;
-
if (layout->blockdata) {
layout->blockdata->copyFrom(commit->metatiles);
if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) {
diff --git a/src/core/metatile.cpp b/src/core/metatile.cpp
index c35a7fcf..7bf3030d 100644
--- a/src/core/metatile.cpp
+++ b/src/core/metatile.cpp
@@ -11,6 +11,8 @@ Metatile* Metatile::copy() {
Metatile *copy = new Metatile;
copy->behavior = this->behavior;
copy->layerType = this->layerType;
+ copy->encounterType = this->encounterType;
+ copy->terrainType = this->terrainType;
copy->tiles = new QList;
copy->label = this->label;
for (Tile tile : *this->tiles) {
@@ -22,6 +24,8 @@ Metatile* Metatile::copy() {
void Metatile::copyInPlace(Metatile *other) {
this->behavior = other->behavior;
this->layerType = other->layerType;
+ this->encounterType = other->encounterType;
+ this->terrainType = other->terrainType;
this->label = other->label;
for (int i = 0; i < this->tiles->length(); i++) {
(*this->tiles)[i] = other->tiles->at(i);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 89bc9bc5..c5130f2e 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -995,6 +995,8 @@ void MainWindow::on_actionNew_Tileset_triggered() {
}
mt->behavior = 0;
mt->layerType = 0;
+ mt->encounterType = 0;
+ mt->terrainType = 0;
newSet->metatiles->append(mt);
}
diff --git a/src/project.cpp b/src/project.cpp
index d48616b7..85640f2b 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -941,9 +941,21 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
QFile attrs_file(tileset->metatile_attrs_path);
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QByteArray data;
- for (Metatile *metatile : *tileset->metatiles) {
- data.append(static_cast(metatile->behavior));
- data.append(static_cast((metatile->layerType << 4) & 0xF0));
+
+ if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
+ for (Metatile *metatile : *tileset->metatiles) {
+ data.append(static_cast(metatile->behavior));
+ data.append(static_cast(metatile->behavior >> 8) |
+ static_cast(metatile->terrainType << 1));
+ data.append(static_cast(0));
+ data.append(static_cast(metatile->encounterType) |
+ static_cast(metatile->layerType << 5));
+ }
+ } else {
+ for (Metatile *metatile : *tileset->metatiles) {
+ data.append(static_cast(metatile->behavior));
+ data.append(static_cast((metatile->layerType << 4) & 0xF0));
+ }
}
attrs_file.write(data);
} else {
@@ -1483,15 +1495,22 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
if (num_metatileAttrs > num_metatiles)
num_metatileAttrs = num_metatiles;
}
+ bool unusedAttribute = false;
for (int i = 0; i < num_metatileAttrs; i++) {
int value = (static_cast(data.at(i * 4 + 3)) << 24) |
(static_cast(data.at(i * 4 + 2)) << 16) |
(static_cast(data.at(i * 4 + 1)) << 8) |
(static_cast(data.at(i * 4 + 0)));
-
tileset->metatiles->at(i)->behavior = value & 0x1FF;
+ tileset->metatiles->at(i)->terrainType = (value & 0x3E00) >> 9;
+ tileset->metatiles->at(i)->encounterType = (value & 0x7000000) >> 24;
tileset->metatiles->at(i)->layerType = (value & 0x60000000) >> 29;
+ if (value & ~(0x67003FFF))
+ unusedAttribute = true;
+ logInfo(QString("").arg(tileset->metatiles->at(i)->terrainType));
}
+ if (unusedAttribute)
+ logWarn(QString("Unrecognized metatile attributes in %1 will not be saved.").arg(tileset->metatile_attrs_path));
} else {
int num_metatileAttrs = data.length() / 2;
if (num_metatiles != num_metatileAttrs) {
@@ -1503,6 +1522,8 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
int value = (static_cast(data.at(i * 2 + 1)) << 8) | static_cast(data.at(i * 2));
tileset->metatiles->at(i)->behavior = value & 0xFF;
tileset->metatiles->at(i)->layerType = (value & 0xF000) >> 12;
+ tileset->metatiles->at(i)->encounterType = 0;
+ tileset->metatiles->at(i)->terrainType = 0;
}
}
} else {
@@ -1974,7 +1995,7 @@ bool Project::readMovementTypes() {
}
bool Project::readInitialFacingDirections() {
- // TODO: This file is not yet decompiled in pokefirered. Remove once resolved
+ // TODO: This array is not yet decompiled in pokefirered. Remove once resolved
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered)
return true;
QString filename = "src/event_object_movement.c";
diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp
index 85b94c35..1c36e60d 100644
--- a/src/ui/tileseteditor.cpp
+++ b/src/ui/tileseteditor.cpp
@@ -5,6 +5,7 @@
#include "metatileparser.h"
#include "paletteutil.h"
#include "imageexport.h"
+#include "config.h"
#include
#include
#include
@@ -61,6 +62,25 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString
this->ui->spinBox_paletteSelector->setMinimum(0);
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1);
+ if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
+ this->ui->comboBox_encounterType->setVisible(true);
+ this->ui->label_encounterType->setVisible(true);
+ this->ui->comboBox_encounterType->addItem("None", 0);
+ this->ui->comboBox_encounterType->addItem("Grass", 1);
+ this->ui->comboBox_encounterType->addItem("Surf", 2);
+ this->ui->comboBox_terrainType->setVisible(true);
+ this->ui->label_terrainType->setVisible(true);
+ this->ui->comboBox_terrainType->addItem("Normal", 0);
+ this->ui->comboBox_terrainType->addItem("Grass", 1);
+ this->ui->comboBox_terrainType->addItem("Water", 2);
+ this->ui->comboBox_terrainType->addItem("Waterfall", 3);
+ } else {
+ this->ui->comboBox_encounterType->setVisible(false);
+ this->ui->label_encounterType->setVisible(false);
+ this->ui->comboBox_terrainType->setVisible(false);
+ this->ui->label_terrainType->setVisible(false);
+ }
+
//only allow characters valid for a symbol
QRegExp expression("[_A-Za-z0-9]*$");
QRegExpValidator *validator = new QRegExpValidator(expression);
@@ -206,6 +226,10 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
this->ui->comboBox_metatileBehaviors->setCurrentIndex(this->ui->comboBox_metatileBehaviors->findData(this->metatile->behavior));
this->ui->lineEdit_metatileLabel->setText(this->metatile->label);
this->ui->comboBox_layerType->setCurrentIndex(this->ui->comboBox_layerType->findData(this->metatile->layerType));
+ if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
+ this->ui->comboBox_encounterType->setCurrentIndex(this->ui->comboBox_encounterType->findData(this->metatile->encounterType));
+ this->ui->comboBox_terrainType->setCurrentIndex(this->ui->comboBox_terrainType->findData(this->metatile->terrainType));
+ }
}
void TilesetEditor::onHoveredTileChanged(uint16_t tile) {
@@ -355,6 +379,26 @@ void TilesetEditor::on_comboBox_layerType_activated(int layerType)
}
}
+void TilesetEditor::on_comboBox_encounterType_activated(int encounterType)
+{
+ if (this->metatile) {
+ Metatile *prevMetatile = this->metatile->copy();
+ this->metatile->encounterType = static_cast(encounterType);
+ MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
+ metatileHistory.push(commit);
+ }
+}
+
+void TilesetEditor::on_comboBox_terrainType_activated(int terrainType)
+{
+ if (this->metatile) {
+ Metatile *prevMetatile = this->metatile->copy();
+ this->metatile->terrainType = static_cast(terrainType);
+ MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
+ metatileHistory.push(commit);
+ }
+}
+
void TilesetEditor::on_actionSave_Tileset_triggered()
{
saveMetatileLabel();
@@ -559,6 +603,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
Metatile *metatile = new Metatile;
metatile->behavior = 0;
metatile->layerType = 0;
+ metatile->encounterType = 0;
+ metatile->terrainType = 0;
for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile);
}
@@ -577,6 +623,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
Metatile *metatile = new Metatile;
metatile->behavior = 0;
metatile->layerType = 0;
+ metatile->encounterType = 0;
+ metatile->terrainType = 0;
for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile);
}