Parse remaining pokefirered metatile attributes, allow editing/saving them

This commit is contained in:
GriffinR 2020-03-16 16:31:08 -04:00
parent 3fa77609c6
commit bf72ecede9
8 changed files with 173 additions and 53 deletions

View file

@ -47,7 +47,7 @@
<x>0</x>
<y>0</y>
<width>272</width>
<height>539</height>
<height>625</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
@ -198,30 +198,31 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label_8">
<item row="13" column="0" colspan="3">
<widget class="QLabel" name="label_metatileLabel">
<property name="text">
<string>Metatile Label (Optional)</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_metatileLabel"/>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_5">
<item row="0" column="2">
<widget class="QLabel" name="label_layerType">
<property name="text">
<string>Metatile Behavior</string>
<string>Layer Type</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<item row="9" column="0">
<widget class="QLabel" name="label_encounterType">
<property name="text">
<string>Bottom/Top</string>
<string>Encounter Type</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_terrainType">
<property name="text">
<string>Terrain Type</string>
</property>
</widget>
</item>
@ -247,15 +248,15 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_6">
<item row="0" column="0">
<widget class="QLabel" name="label_BottomTop">
<property name="text">
<string>Layer Type</string>
<string>Bottom/Top</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBox_layerType"/>
<item row="10" column="0">
<widget class="QComboBox" name="comboBox_encounterType"/>
</item>
<item row="1" column="1">
<spacer name="horizontalSpacer_5">
@ -270,6 +271,38 @@
</property>
</spacer>
</item>
<item row="14" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_metatileLabel"/>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBox_layerType"/>
</item>
<item row="8" column="0" colspan="3">
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors" native="true"/>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label_metatileBehavior">
<property name="text">
<string>Metatile Behavior</string>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QComboBox" name="comboBox_terrainType"/>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -377,8 +410,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>367</height>
<width>384</width>
<height>265</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
@ -394,19 +427,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
@ -420,16 +440,6 @@
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGraphicsView" name="graphicsView_Tiles">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
@ -443,6 +453,29 @@
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGraphicsView" name="graphicsView_Tiles">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
@ -471,7 +504,7 @@
<x>0</x>
<y>0</y>
<width>700</width>
<height>21</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -572,6 +605,13 @@
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>NoScrollComboBox</class>
<extends>QWidget</extends>
<header>noscrollcombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -11,8 +11,10 @@ public:
Metatile();
public:
QList<Tile> *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();

View file

@ -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();

View file

@ -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()) {

View file

@ -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<Tile>;
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);

View file

@ -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);
}

View file

@ -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<char>(metatile->behavior));
data.append(static_cast<char>((metatile->layerType << 4) & 0xF0));
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
for (Metatile *metatile : *tileset->metatiles) {
data.append(static_cast<char>(metatile->behavior));
data.append(static_cast<char>(metatile->behavior >> 8) |
static_cast<char>(metatile->terrainType << 1));
data.append(static_cast<char>(0));
data.append(static_cast<char>(metatile->encounterType) |
static_cast<char>(metatile->layerType << 5));
}
} else {
for (Metatile *metatile : *tileset->metatiles) {
data.append(static_cast<char>(metatile->behavior));
data.append(static_cast<char>((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<unsigned char>(data.at(i * 4 + 3)) << 24) |
(static_cast<unsigned char>(data.at(i * 4 + 2)) << 16) |
(static_cast<unsigned char>(data.at(i * 4 + 1)) << 8) |
(static_cast<unsigned char>(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<unsigned char>(data.at(i * 2 + 1)) << 8) | static_cast<unsigned char>(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";

View file

@ -5,6 +5,7 @@
#include "metatileparser.h"
#include "paletteutil.h"
#include "imageexport.h"
#include "config.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QDialogButtonBox>
@ -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<uint8_t>(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<uint8_t>(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);
}