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> <x>0</x>
<y>0</y> <y>0</y>
<width>272</width> <width>272</width>
<height>539</height> <height>625</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
@ -198,30 +198,31 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="4" column="0" colspan="3"> <item row="13" column="0" colspan="3">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_metatileLabel">
<property name="text"> <property name="text">
<string>Metatile Label (Optional)</string> <string>Metatile Label (Optional)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="3"> <item row="0" column="2">
<widget class="QLineEdit" name="lineEdit_metatileLabel"/> <widget class="QLabel" name="label_layerType">
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Metatile Behavior</string> <string>Layer Type</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="3"> <item row="9" column="0">
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors"/> <widget class="QLabel" name="label_encounterType">
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text"> <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> </property>
</widget> </widget>
</item> </item>
@ -247,15 +248,15 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2"> <item row="0" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_BottomTop">
<property name="text"> <property name="text">
<string>Layer Type</string> <string>Bottom/Top</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2"> <item row="10" column="0">
<widget class="QComboBox" name="comboBox_layerType"/> <widget class="QComboBox" name="comboBox_encounterType"/>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<spacer name="horizontalSpacer_5"> <spacer name="horizontalSpacer_5">
@ -270,6 +271,38 @@
</property> </property>
</spacer> </spacer>
</item> </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> </layout>
</widget> </widget>
</item> </item>
@ -377,8 +410,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>384</width>
<height>367</height> <height>265</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
@ -394,19 +427,6 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </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"> <item row="0" column="1">
<spacer name="verticalSpacer_3"> <spacer name="verticalSpacer_3">
<property name="orientation"> <property name="orientation">
@ -420,16 +440,6 @@
</property> </property>
</spacer> </spacer>
</item> </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"> <item row="2" column="1">
<spacer name="verticalSpacer_4"> <spacer name="verticalSpacer_4">
<property name="orientation"> <property name="orientation">
@ -443,6 +453,29 @@
</property> </property>
</spacer> </spacer>
</item> </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"> <item row="1" column="0">
<spacer name="horizontalSpacer_3"> <spacer name="horizontalSpacer_3">
<property name="orientation"> <property name="orientation">
@ -471,7 +504,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>700</width> <width>700</width>
<height>21</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
@ -572,6 +605,13 @@
</property> </property>
</action> </action>
</widget> </widget>
<customwidgets>
<customwidget>
<class>NoScrollComboBox</class>
<extends>QWidget</extends>
<header>noscrollcombobox.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View file

@ -11,8 +11,10 @@ public:
Metatile(); Metatile();
public: public:
QList<Tile> *tiles = nullptr; QList<Tile> *tiles = nullptr;
uint8_t behavior; uint16_t behavior; // 8 bits RSE, 9 bits FRLG
uint8_t layerType; uint8_t layerType;
uint8_t encounterType; // FRLG only
uint8_t terrainType; // FRLG only
QString label; QString label;
Metatile *copy(); Metatile *copy();

View file

@ -77,6 +77,10 @@ private slots:
void on_comboBox_layerType_activated(int arg1); 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_Primary_Tiles_Image_triggered();
void on_actionExport_Secondary_Tiles_Image_triggered(); void on_actionExport_Secondary_Tiles_Image_triggered();

View file

@ -412,7 +412,6 @@ void Map::undo() {
if (!commit) if (!commit)
return; return;
if (layout->blockdata) { if (layout->blockdata) {
layout->blockdata->copyFrom(commit->metatiles); layout->blockdata->copyFrom(commit->metatiles);
if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) { if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) {

View file

@ -11,6 +11,8 @@ Metatile* Metatile::copy() {
Metatile *copy = new Metatile; Metatile *copy = new Metatile;
copy->behavior = this->behavior; copy->behavior = this->behavior;
copy->layerType = this->layerType; copy->layerType = this->layerType;
copy->encounterType = this->encounterType;
copy->terrainType = this->terrainType;
copy->tiles = new QList<Tile>; copy->tiles = new QList<Tile>;
copy->label = this->label; copy->label = this->label;
for (Tile tile : *this->tiles) { for (Tile tile : *this->tiles) {
@ -22,6 +24,8 @@ Metatile* Metatile::copy() {
void Metatile::copyInPlace(Metatile *other) { void Metatile::copyInPlace(Metatile *other) {
this->behavior = other->behavior; this->behavior = other->behavior;
this->layerType = other->layerType; this->layerType = other->layerType;
this->encounterType = other->encounterType;
this->terrainType = other->terrainType;
this->label = other->label; this->label = other->label;
for (int i = 0; i < this->tiles->length(); i++) { for (int i = 0; i < this->tiles->length(); i++) {
(*this->tiles)[i] = other->tiles->at(i); (*this->tiles)[i] = other->tiles->at(i);

View file

@ -995,6 +995,8 @@ void MainWindow::on_actionNew_Tileset_triggered() {
} }
mt->behavior = 0; mt->behavior = 0;
mt->layerType = 0; mt->layerType = 0;
mt->encounterType = 0;
mt->terrainType = 0;
newSet->metatiles->append(mt); newSet->metatiles->append(mt);
} }

View file

@ -941,9 +941,21 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
QFile attrs_file(tileset->metatile_attrs_path); QFile attrs_file(tileset->metatile_attrs_path);
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QByteArray data; QByteArray data;
for (Metatile *metatile : *tileset->metatiles) {
data.append(static_cast<char>(metatile->behavior)); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
data.append(static_cast<char>((metatile->layerType << 4) & 0xF0)); 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); attrs_file.write(data);
} else { } else {
@ -1483,15 +1495,22 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
if (num_metatileAttrs > num_metatiles) if (num_metatileAttrs > num_metatiles)
num_metatileAttrs = num_metatiles; num_metatileAttrs = num_metatiles;
} }
bool unusedAttribute = false;
for (int i = 0; i < num_metatileAttrs; i++) { for (int i = 0; i < num_metatileAttrs; i++) {
int value = (static_cast<unsigned char>(data.at(i * 4 + 3)) << 24) | 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 + 2)) << 16) |
(static_cast<unsigned char>(data.at(i * 4 + 1)) << 8) | (static_cast<unsigned char>(data.at(i * 4 + 1)) << 8) |
(static_cast<unsigned char>(data.at(i * 4 + 0))); (static_cast<unsigned char>(data.at(i * 4 + 0)));
tileset->metatiles->at(i)->behavior = value & 0x1FF; 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; 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 { } else {
int num_metatileAttrs = data.length() / 2; int num_metatileAttrs = data.length() / 2;
if (num_metatiles != num_metatileAttrs) { 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)); 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)->behavior = value & 0xFF;
tileset->metatiles->at(i)->layerType = (value & 0xF000) >> 12; tileset->metatiles->at(i)->layerType = (value & 0xF000) >> 12;
tileset->metatiles->at(i)->encounterType = 0;
tileset->metatiles->at(i)->terrainType = 0;
} }
} }
} else { } else {
@ -1974,7 +1995,7 @@ bool Project::readMovementTypes() {
} }
bool Project::readInitialFacingDirections() { 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) if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered)
return true; return true;
QString filename = "src/event_object_movement.c"; QString filename = "src/event_object_movement.c";

View file

@ -5,6 +5,7 @@
#include "metatileparser.h" #include "metatileparser.h"
#include "paletteutil.h" #include "paletteutil.h"
#include "imageexport.h" #include "imageexport.h"
#include "config.h"
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
@ -61,6 +62,25 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString
this->ui->spinBox_paletteSelector->setMinimum(0); this->ui->spinBox_paletteSelector->setMinimum(0);
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1); 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 //only allow characters valid for a symbol
QRegExp expression("[_A-Za-z0-9]*$"); QRegExp expression("[_A-Za-z0-9]*$");
QRegExpValidator *validator = new QRegExpValidator(expression); 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->comboBox_metatileBehaviors->setCurrentIndex(this->ui->comboBox_metatileBehaviors->findData(this->metatile->behavior));
this->ui->lineEdit_metatileLabel->setText(this->metatile->label); this->ui->lineEdit_metatileLabel->setText(this->metatile->label);
this->ui->comboBox_layerType->setCurrentIndex(this->ui->comboBox_layerType->findData(this->metatile->layerType)); 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) { 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() void TilesetEditor::on_actionSave_Tileset_triggered()
{ {
saveMetatileLabel(); saveMetatileLabel();
@ -559,6 +603,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
Metatile *metatile = new Metatile; Metatile *metatile = new Metatile;
metatile->behavior = 0; metatile->behavior = 0;
metatile->layerType = 0; metatile->layerType = 0;
metatile->encounterType = 0;
metatile->terrainType = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile); metatile->tiles->append(tile);
} }
@ -577,6 +623,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
Metatile *metatile = new Metatile; Metatile *metatile = new Metatile;
metatile->behavior = 0; metatile->behavior = 0;
metatile->layerType = 0; metatile->layerType = 0;
metatile->encounterType = 0;
metatile->terrainType = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile); metatile->tiles->append(tile);
} }