From 3eca227d07e0a47c1493b23ae7b0c42d88cb20c6 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 11 Mar 2020 01:52:00 -0400 Subject: [PATCH 01/33] Basic pokefirered empty layout, floor number, version selection support --- forms/mainwindow.ui | 17 ++++++++++++ forms/newmappopup.ui | 17 ++++++++++++ include/core/map.h | 1 + src/config.cpp | 5 +++- src/mainwindow.cpp | 16 ++++++++++- src/project.cpp | 60 ++++++++++++++++++++++++++++++++++++------ src/ui/newmappopup.cpp | 17 ++++++++++++ 7 files changed, 123 insertions(+), 10 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 68d458c9..676b8174 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2094,6 +2094,23 @@ </property> </widget> </item> + <item row="11" column="0"> + <widget class="QLabel" name="label_FloorNumber"> + <property name="text"> + <string>Floor Number</string> + </property> + </widget> + </item> + <item row="11" column="1"> + <widget class="QSpinBox" name="spinBox_FloorNumber"> + <property name="toolTip"> + <string><html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html></string> + </property> + <property name="maximum"> + <number>127</number> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/forms/newmappopup.ui b/forms/newmappopup.ui index 209c078d..41aaaf77 100644 --- a/forms/newmappopup.ui +++ b/forms/newmappopup.ui @@ -231,6 +231,23 @@ </property> </widget> </item> + <item row="12" column="0"> + <widget class="QLabel" name="label_NewMap_Floor_Number"> + <property name="text"> + <string>Floor Number</string> + </property> + </widget> + </item> + <item row="12" column="1"> + <widget class="QSpinBox" name="spinBox_NewMap_Floor_Number"> + <property name="toolTip"> + <string><html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html></string> + </property> + <property name="maximum"> + <number>127</number> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/include/core/map.h b/include/core/map.h index 8ecc0a9e..7f9ff989 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -35,6 +35,7 @@ public: QString allowRunning; QString allowBiking; QString allowEscapeRope; + int floorNumber; QString battle_scene; QString sharedEventsMap = ""; QString sharedScriptsMap = ""; diff --git a/src/config.cpp b/src/config.cpp index ed76cd1b..50e5ca83 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -324,11 +324,13 @@ QString PorymapConfig::getTheme() { const QMap<BaseGameVersion, QString> baseGameVersionMap = { {BaseGameVersion::pokeruby, "pokeruby"}, + {BaseGameVersion::pokefirered, "pokefirered"}, {BaseGameVersion::pokeemerald, "pokeemerald"}, }; const QMap<QString, BaseGameVersion> baseGameVersionReverseMap = { {"pokeruby", BaseGameVersion::pokeruby}, + {"pokefirered", BaseGameVersion::pokefirered}, {"pokeemerald", BaseGameVersion::pokeemerald}, }; @@ -346,7 +348,7 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { this->baseGameVersion = baseGameVersionReverseMap.value(baseGameVersion); } else { this->baseGameVersion = BaseGameVersion::pokeemerald; - logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby' or 'pokeemerald'.").arg(value)); + logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby', 'pokefirered' or 'pokeemerald'.").arg(value)); } } else if (key == "use_encounter_json") { bool ok; @@ -387,6 +389,7 @@ void ProjectConfig::onNewConfigFileCreated() { QComboBox *baseGameVersionComboBox = new QComboBox(); baseGameVersionComboBox->addItem("pokeruby", BaseGameVersion::pokeruby); + baseGameVersionComboBox->addItem("pokefirered", BaseGameVersion::pokefirered); baseGameVersionComboBox->addItem("pokeemerald", BaseGameVersion::pokeemerald); form.addRow(new QLabel("Game Version"), baseGameVersionComboBox); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fc0c2f12..4fe9f98b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -160,19 +160,31 @@ void MainWindow::setProjectSpecificUIVisibility() ui->checkBox_AllowRunning->setVisible(false); ui->checkBox_AllowBiking->setVisible(false); ui->checkBox_AllowEscapeRope->setVisible(false); + ui->spinBox_FloorNumber->setVisible(false); ui->label_AllowRunning->setVisible(false); ui->label_AllowBiking->setVisible(false); ui->label_AllowEscapeRope->setVisible(false); + ui->label_FloorNumber->setVisible(false); break; case BaseGameVersion::pokeemerald: ui->checkBox_AllowRunning->setVisible(true); ui->checkBox_AllowBiking->setVisible(true); ui->checkBox_AllowEscapeRope->setVisible(true); + ui->spinBox_FloorNumber->setVisible(false); ui->label_AllowRunning->setVisible(true); ui->label_AllowBiking->setVisible(true); ui->label_AllowEscapeRope->setVisible(true); + ui->label_FloorNumber->setVisible(false); break; case BaseGameVersion::pokefirered: + ui->checkBox_AllowRunning->setVisible(true); + ui->checkBox_AllowBiking->setVisible(true); + ui->checkBox_AllowEscapeRope->setVisible(true); + ui->spinBox_FloorNumber->setVisible(true); + ui->label_AllowRunning->setVisible(true); + ui->label_AllowBiking->setVisible(true); + ui->label_AllowEscapeRope->setVisible(true); + ui->label_FloorNumber->setVisible(true); break; } } @@ -504,6 +516,7 @@ void MainWindow::displayMapProperties() { ui->checkBox_AllowRunning->setChecked(map->allowRunning.toInt() > 0 || map->allowRunning == "TRUE"); ui->checkBox_AllowBiking->setChecked(map->allowBiking.toInt() > 0 || map->allowBiking == "TRUE"); ui->checkBox_AllowEscapeRope->setChecked(map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE"); + ui->spinBox_FloorNumber->setValue(map->floorNumber); // Custom fields table. ui->tableWidget_CustomHeaderFields->blockSignals(true); @@ -620,7 +633,6 @@ bool MainWindow::loadDataStructures() { && project->readMapBattleScenes() && project->readWeatherNames() && project->readCoordEventWeatherNames() - && project->readSecretBaseIds() && project->readBgEventFacingDirections() && project->readMetatileBehaviors() && project->readTilesetProperties() @@ -628,6 +640,8 @@ bool MainWindow::loadDataStructures() { && project->readMiscellaneousConstants() && project->readSpeciesIconPaths() && project->readWildMonData(); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald || projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) + success = success && project->readSecretBaseIds(); if (!success) { return false; } diff --git a/src/project.cpp b/src/project.cpp index 20c864cc..294b6d45 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -100,8 +100,8 @@ QMap<QString, bool> Project::getTopLevelMapFields() { {"requires_flash", true}, {"weather", true}, {"map_type", true}, - {"allow_bike", true}, - {"allow_escape_rope", true}, + {"allow_cycling", true}, + {"allow_escaping", true}, {"allow_running", true}, {"show_map_name", true}, {"battle_scene", true}, @@ -113,6 +113,31 @@ QMap<QString, bool> Project::getTopLevelMapFields() { {"shared_events_map", true}, {"shared_scripts_map", true}, }; + } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + return QMap<QString, bool> + { + {"id", true}, + {"name", true}, + {"layout", true}, + {"music", true}, + {"region_map_section", true}, + {"requires_flash", true}, + {"weather", true}, + {"map_type", true}, + {"allow_cycling", true}, + {"allow_escaping", true}, + {"allow_running", true}, + {"show_map_name", true}, + {"floor_number", true}, + {"battle_scene", true}, + {"connections", true}, + {"object_events", true}, + {"warp_events", true}, + {"coord_events", true}, + {"bg_events", true}, + {"shared_events_map", true}, + {"shared_scripts_map", true}, + }; } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { return QMap<QString, bool> { @@ -164,9 +189,14 @@ bool Project::loadMapData(Map* map) { map->show_location = QString::number(mapObj["show_map_name"].toBool()); map->battle_scene = mapObj["battle_scene"].toString(); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald) { - map->allowBiking = QString::number(mapObj["allow_bike"].toBool()); - map->allowEscapeRope = QString::number(mapObj["allow_escape_rope"].toBool()); + map->allowBiking = QString::number(mapObj["allow_cycling"].toBool()); + map->allowEscapeRope = QString::number(mapObj["allow_escaping"].toBool()); map->allowRunning = QString::number(mapObj["allow_running"].toBool()); + } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + map->allowBiking = QString::number(mapObj["allow_cycling"].toBool()); + map->allowEscapeRope = QString::number(mapObj["allow_escaping"].toBool()); + map->allowRunning = QString::number(mapObj["allow_running"].toBool()); + map->floorNumber = mapObj["floor_number"].toInt(); } map->sharedEventsMap = mapObj["shared_events_map"].toString(); map->sharedScriptsMap = mapObj["shared_scripts_map"].toString(); @@ -386,6 +416,12 @@ void Project::setNewMapHeader(Map* map, int mapIndex) { map->allowEscapeRope = "0"; map->allowRunning = "1"; map->show_location = "1"; + } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + map->allowBiking = "1"; + map->allowEscapeRope = "0"; + map->allowRunning = "1"; + map->show_location = "1"; + map->floorNumber = 0; } map->battle_scene = "MAP_BATTLE_SCENE_NORMAL"; @@ -446,6 +482,8 @@ bool Project::readMapLayouts() { }; for (int i = 0; i < layouts.size(); i++) { QJsonObject layoutObj = layouts[i].toObject(); + if (layoutObj.isEmpty()) + continue; if (!parser.ensureFieldsExist(layoutObj, requiredFields)) { logError(QString("Layout %1 is missing field(s) in %2.").arg(i).arg(layoutsFilepath)); return false; @@ -1048,14 +1086,14 @@ void Project::saveMap(Map *map) { QString text = this->getScriptDefaultString(projectConfig.getUsePoryScript(), map->name); saveTextFile(root + "/data/maps/" + map->name + "/scripts" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), text); - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby || projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { // Create file data/maps/<map_name>/text.inc saveTextFile(root + "/data/maps/" + map->name + "/text" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), "\n"); } // Simply append to data/event_scripts.s. text = QString("\n\t.include \"data/maps/%1/scripts.inc\"\n").arg(map->name); - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby || projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { text += QString("\t.include \"data/maps/%1/text.inc\"\n").arg(map->name); } appendTextFile(root + "/data/event_scripts.s", text); @@ -1115,10 +1153,11 @@ void Project::saveMap(Map *map) { mapObj["requires_flash"] = map->requiresFlash.toInt() > 0 || map->requiresFlash == "TRUE"; mapObj["weather"] = map->weather; mapObj["map_type"] = map->type; - mapObj["allow_bike"] = map->allowBiking.toInt() > 0 || map->allowBiking == "TRUE"; - mapObj["allow_escape_rope"] = map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE"; + mapObj["allow_cycling"] = map->allowBiking.toInt() > 0 || map->allowBiking == "TRUE"; + mapObj["allow_escaping"] = map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE"; mapObj["allow_running"] = map->allowRunning.toInt() > 0 || map->allowRunning == "TRUE"; mapObj["show_map_name"] = map->show_location.toInt() > 0 || map->show_location == "TRUE"; + mapObj["floor_number"] = map->floorNumber; mapObj["battle_scene"] = map->battle_scene; // Connections @@ -1863,6 +1902,9 @@ bool Project::readMovementTypes() { } bool Project::readInitialFacingDirections() { + // TODO: This file is not yet decompiled in pokefirered. Remove once resolved + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) + return true; QString filename = "src/event_object_movement.c"; facingDirections = parser.readNamedIndexCArray(filename, "gInitialMovementTypeFacingDirections"); if (facingDirections.isEmpty()) { @@ -1909,6 +1951,8 @@ bool Project::readWeatherNames() { } bool Project::readCoordEventWeatherNames() { + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) + return true; coordEventWeatherNames->clear(); QStringList prefixes = (QStringList() << "COORD_EVENT_WEATHER_"); QString filename = "include/constants/weather.h"; diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index e0938227..9ba8936f 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -81,19 +81,31 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) { ui->checkBox_NewMap_Allow_Running->setVisible(false); ui->checkBox_NewMap_Allow_Biking->setVisible(false); ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(false); + ui->spinBox_NewMap_Floor_Number->setVisible(false); ui->label_NewMap_Allow_Running->setVisible(false); ui->label_NewMap_Allow_Biking->setVisible(false); ui->label_NewMap_Allow_Escape_Rope->setVisible(false); + ui->label_NewMap_Floor_Number->setVisible(false); break; case BaseGameVersion::pokeemerald: ui->checkBox_NewMap_Allow_Running->setVisible(true); ui->checkBox_NewMap_Allow_Biking->setVisible(true); ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(true); + ui->spinBox_NewMap_Floor_Number->setVisible(false); ui->label_NewMap_Allow_Running->setVisible(true); ui->label_NewMap_Allow_Biking->setVisible(true); ui->label_NewMap_Allow_Escape_Rope->setVisible(true); + ui->label_NewMap_Floor_Number->setVisible(false); break; case BaseGameVersion::pokefirered: + ui->checkBox_NewMap_Allow_Running->setVisible(true); + ui->checkBox_NewMap_Allow_Biking->setVisible(true); + ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(true); + ui->spinBox_NewMap_Floor_Number->setVisible(true); + ui->label_NewMap_Allow_Running->setVisible(true); + ui->label_NewMap_Allow_Biking->setVisible(true); + ui->label_NewMap_Allow_Escape_Rope->setVisible(true); + ui->label_NewMap_Floor_Number->setVisible(true); break; } } @@ -152,6 +164,11 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0"; newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0"; newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0"; + } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0"; + newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0"; + newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0"; + newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value(); } group = project->groupNames->indexOf(this->ui->comboBox_NewMap_Group->currentText()); From eb44201f5b21d3a362d0090db53a910a0055e26b Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 11 Mar 2020 02:35:24 -0400 Subject: [PATCH 02/33] Skip MUS_DAN02 for pokefirered --- src/project.cpp | 4 +++- src/ui/newmappopup.cpp | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index 294b6d45..83de74f1 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -403,20 +403,22 @@ QString Project::readMapLocation(QString map_name) { } void Project::setNewMapHeader(Map* map, int mapIndex) { - map->song = "MUS_DAN02"; map->layoutId = QString("%1").arg(mapIndex); map->location = "MAPSEC_LITTLEROOT_TOWN"; map->requiresFlash = "FALSE"; map->weather = "WEATHER_SUNNY"; map->type = "MAP_TYPE_TOWN"; if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { + map->song = "MUS_DAN02"; map->show_location = "TRUE"; } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald) { + map->song = "MUS_DAN02"; map->allowBiking = "1"; map->allowEscapeRope = "0"; map->allowRunning = "1"; map->show_location = "1"; } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + map->song = "MUS_MASARA"; map->allowBiking = "1"; map->allowEscapeRope = "0"; map->allowRunning = "1"; diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 9ba8936f..9191a73f 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -135,7 +135,11 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->name = newMapName; newMap->type = this->ui->comboBox_NewMap_Type->currentText(); newMap->location = this->ui->comboBox_NewMap_Location->currentText(); - newMap->song = "MUS_DAN02"; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + newMap->song = "MUS_MASARA"; + } else { + newMap->song = "MUS_DAN02"; + } newMap->requiresFlash = "0"; newMap->weather = "WEATHER_SUNNY"; newMap->show_location = "1"; From 7125cd7c8d8e4a985b970b9561e610e18ae2a469 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 11 Mar 2020 16:23:07 -0400 Subject: [PATCH 03/33] Add underfoot and quantity to hidden items --- src/core/event.cpp | 38 ++++++++++++++++++++------ src/mainwindow.cpp | 67 +++++++++++++++++++++++++++++++++++++++------- src/project.cpp | 4 +++ 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/src/core/event.cpp b/src/core/event.cpp index 1015cc5e..e8750971 100644 --- a/src/core/event.cpp +++ b/src/core/event.cpp @@ -1,6 +1,7 @@ #include "event.h" #include "map.h" #include "project.h" +#include "config.h" QString EventType::Object = "event_object"; QString EventType::Warp = "event_warp"; @@ -131,6 +132,10 @@ Event* Event::createNewHiddenItemEvent(Project *project) event->put("item", project->itemNames->first()); event->put("flag", project->flagNames->first()); event->put("elevation", 3); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + event->put("quantity", 1); + event->put("underfoot", false); + } return event; } @@ -207,14 +212,27 @@ QMap<QString, bool> Event::getExpectedFields() {"script", true}, }; } else if (type == EventType::HiddenItem) { - return QMap<QString, bool> { - {"type", true}, - {"x", true}, - {"y", true}, - {"elevation", true}, - {"item", true}, - {"flag", true}, - }; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + return QMap<QString, bool> { + {"type", true}, + {"x", true}, + {"y", true}, + {"elevation", true}, + {"item", true}, + {"flag", true}, + {"quantity", true}, + {"underfoot", true}, + }; + } else { + return QMap<QString, bool> { + {"type", true}, + {"x", true}, + {"y", true}, + {"elevation", true}, + {"item", true}, + {"flag", true}, + }; + } } else if (type == EventType::SecretBase) { return QMap<QString, bool> { {"type", true}, @@ -331,6 +349,10 @@ QJsonObject Event::buildHiddenItemEventJSON() hiddenItemObj["elevation"] = this->getInt("elevation"); hiddenItemObj["item"] = this->get("item"); hiddenItemObj["flag"] = this->get("flag"); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + hiddenItemObj["quantity"] = this->getInt("quantity"); + hiddenItemObj["underfoot"] = this->getInt("underfoot") > 0 || this->get("underfoot") == "TRUE"; + } this->addCustomValuesTo(&hiddenItemObj); return hiddenItemObj; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4fe9f98b..15f74808 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1407,8 +1407,8 @@ void MainWindow::updateSelectedObjects() { field_labels["script_var_value"] = "Var Value"; field_labels["player_facing_direction"] = "Player Facing Direction"; field_labels["item"] = "Item"; - field_labels["item_unknown5"] = "Unknown 5"; - field_labels["item_unknown6"] = "Unknown 6"; + field_labels["quantity"] = "Quantity"; + field_labels["underfoot"] = "Requires Itemfinder"; field_labels["weather"] = "Weather"; field_labels["flag"] = "Flag"; field_labels["secret_base_id"] = "Secret Base Id"; @@ -1459,6 +1459,10 @@ void MainWindow::updateSelectedObjects() { else if (event_type == EventType::HiddenItem) { fields << "item"; fields << "flag"; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + fields << "quantity"; + fields << "underfoot"; + } } else if (event_type == EventType::SecretBase) { fields << "secret_base_id"; @@ -1476,8 +1480,19 @@ void MainWindow::updateSelectedObjects() { fl->setContentsMargins(9, 0, 9, 0); fl->setRowWrapPolicy(QFormLayout::WrapLongRows); - NoScrollComboBox *combo = new NoScrollComboBox(widget); - combo->setEditable(true); + NoScrollSpinBox *spin; + NoScrollComboBox *combo; + QCheckBox *check; + + // Some keys shouldn't use a combobox. This isn't very scalable + if (key == "quantity") { + spin = new NoScrollSpinBox(widget); + } else if (key == "underfoot") { + check = new QCheckBox(widget); + } else { + combo = new NoScrollComboBox(widget); + combo->setEditable(true); + } // trainer_type has custom values, so it has special signal logic. if (key == "trainer_type") { @@ -1515,6 +1530,25 @@ void MainWindow::updateSelectedObjects() { combo->addItem(value); } combo->addItems(*editor->project->itemNames); + } else if (key == "quantity") { + spin->setToolTip("The number of items received when the hidden item is picked up."); + spin->setMaximum(127); + connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, key](int value) { + item->event->put(key, value); + }); + } else if (key == "underfoot") { + check->setToolTip("If checked, hidden item can only be picked up using the Itemfinder"); + connect(check, &QCheckBox::stateChanged, [item, key](int state) { + switch (state) + { + case Qt::Checked: + item->event->put(key, true); + break; + case Qt::Unchecked: + item->event->put(key, false); + break; + } + }); } else if (key == "flag" || key == "event_flag") { if (!editor->project->flagNames->contains(value)) { combo->addItem(value); @@ -1585,13 +1619,28 @@ void MainWindow::updateSelectedObjects() { } else { combo->addItem(value); } - combo->setCurrentText(value); - fl->addRow(new QLabel(field_labels[key], widget), combo); - widget->setLayout(fl); - frame->layout()->addWidget(widget); + if (key == "quantity") { + spin->setValue(value.toInt()); - item->bind(combo, key); + fl->addRow(new QLabel(field_labels[key], widget), spin); + widget->setLayout(fl); + frame->layout()->addWidget(widget); + } else if (key == "underfoot") { + check->setChecked(value.toInt()); + + fl->addRow(new QLabel(field_labels[key], widget), check); + widget->setLayout(fl); + frame->layout()->addWidget(widget); + } else { + combo->setCurrentText(value); + + fl->addRow(new QLabel(field_labels[key], widget), combo); + widget->setLayout(fl); + frame->layout()->addWidget(widget); + + item->bind(combo, key); + } } // Custom fields table. diff --git a/src/project.cpp b/src/project.cpp index 83de74f1..3906f0a6 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -325,6 +325,10 @@ bool Project::loadMapData(Map* map) { bg->put("elevation", QString::number(event["elevation"].toInt())); bg->put("item", event["item"].toString()); bg->put("flag", event["flag"].toString()); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + bg->put("quantity", event["quantity"].toInt()); + bg->put("underfoot", event["underfoot"].toBool()); + } bg->put("event_group_type", "bg_event_group"); map->events["bg_event_group"].append(bg); } else if (type == "secret_base") { From 8d89b370b46cf43ff260010218881f1c65251532 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 11 Mar 2020 16:45:52 -0400 Subject: [PATCH 04/33] Add in_connection to object events --- src/core/event.cpp | 49 ++++++++++++++++++++++++++++++++++------------ src/mainwindow.cpp | 41 +++++++++++++++++++++++--------------- src/project.cpp | 3 +++ 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/core/event.cpp b/src/core/event.cpp index e8750971..a13ed790 100644 --- a/src/core/event.cpp +++ b/src/core/event.cpp @@ -59,6 +59,9 @@ Event* Event::createNewObjectEvent(Project *project) event->put("event_type", EventType::Object); event->put("sprite", project->getEventObjGfxConstants().keys().first()); event->put("movement_type", project->movementTypes->first()); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + event->put("in_connection", false); + } event->put("radius_x", 0); event->put("radius_y", 0); event->put("script_label", "NULL"); @@ -163,19 +166,36 @@ QMap<QString, bool> Event::getExpectedFields() { QString type = this->get("event_type"); if (type == EventType::Object) { - return QMap<QString, bool> { - {"graphics_id", true}, - {"x", true}, - {"y", true}, - {"elevation", true}, - {"movement_type", true}, - {"movement_range_x", true}, - {"movement_range_y", true}, - {"trainer_type", true}, - {"trainer_sight_or_berry_tree_id", true}, - {"script", true}, - {"flag", true}, - }; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + return QMap<QString, bool> { + {"graphics_id", true}, + {"in_connection", true}, + {"x", true}, + {"y", true}, + {"elevation", true}, + {"movement_type", true}, + {"movement_range_x", true}, + {"movement_range_y", true}, + {"trainer_type", true}, + {"trainer_sight_or_berry_tree_id", true}, + {"script", true}, + {"flag", true}, + }; + } else { + return QMap<QString, bool> { + {"graphics_id", true}, + {"x", true}, + {"y", true}, + {"elevation", true}, + {"movement_type", true}, + {"movement_range_x", true}, + {"movement_range_y", true}, + {"trainer_type", true}, + {"trainer_sight_or_berry_tree_id", true}, + {"script", true}, + {"flag", true}, + }; + } } else if (type == EventType::Warp) { return QMap<QString, bool> { {"x", true}, @@ -270,6 +290,9 @@ QJsonObject Event::buildObjectEventJSON() { QJsonObject eventObj; eventObj["graphics_id"] = this->get("sprite"); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + eventObj["in_connection"] = this->getInt("in_connection") > 0 || this->get("in_connection") == "TRUE"; + } eventObj["x"] = this->getU16("x"); eventObj["y"] = this->getU16("y"); eventObj["elevation"] = this->getInt("elevation"); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 15f74808..590c8f88 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1401,6 +1401,7 @@ void MainWindow::updateSelectedObjects() { field_labels["radius_y"] = "Movement Radius Y"; field_labels["trainer_type"] = "Trainer Type"; field_labels["sight_radius_tree_id"] = "Sight Radius / Berry Tree ID"; + field_labels["in_connection"] = "In Connection"; field_labels["destination_warp"] = "Destination Warp"; field_labels["destination_map_name"] = "Destination Map"; field_labels["script_var"] = "Var"; @@ -1439,6 +1440,9 @@ void MainWindow::updateSelectedObjects() { fields << "event_flag"; fields << "trainer_type"; fields << "sight_radius_tree_id"; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + fields << "in_connection"; + } } else if (event_type == EventType::Warp) { fields << "destination_map_name"; @@ -1487,7 +1491,7 @@ void MainWindow::updateSelectedObjects() { // Some keys shouldn't use a combobox. This isn't very scalable if (key == "quantity") { spin = new NoScrollSpinBox(widget); - } else if (key == "underfoot") { + } else if (key == "underfoot" || key == "in_connection") { check = new QCheckBox(widget); } else { combo = new NoScrollComboBox(widget); @@ -1533,22 +1537,8 @@ void MainWindow::updateSelectedObjects() { } else if (key == "quantity") { spin->setToolTip("The number of items received when the hidden item is picked up."); spin->setMaximum(127); - connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, key](int value) { - item->event->put(key, value); - }); } else if (key == "underfoot") { check->setToolTip("If checked, hidden item can only be picked up using the Itemfinder"); - connect(check, &QCheckBox::stateChanged, [item, key](int state) { - switch (state) - { - case Qt::Checked: - item->event->put(key, true); - break; - case Qt::Unchecked: - item->event->put(key, false); - break; - } - }); } else if (key == "flag" || key == "event_flag") { if (!editor->project->flagNames->contains(value)) { combo->addItem(value); @@ -1616,6 +1606,8 @@ void MainWindow::updateSelectedObjects() { combo->setToolTip("The maximum sight range of a trainer,\n" "OR the unique id of the berry tree."); combo->setMinimumContentsLength(4); + } else if (key == "in_connection") { + check->setToolTip("Check if object is positioned in the connection to another map."); } else { combo->addItem(value); } @@ -1626,12 +1618,29 @@ void MainWindow::updateSelectedObjects() { fl->addRow(new QLabel(field_labels[key], widget), spin); widget->setLayout(fl); frame->layout()->addWidget(widget); - } else if (key == "underfoot") { + + connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, key](int value) { + item->event->put(key, value); + }); + + } else if (key == "underfoot" || key == "in_connection") { check->setChecked(value.toInt()); fl->addRow(new QLabel(field_labels[key], widget), check); widget->setLayout(fl); frame->layout()->addWidget(widget); + + connect(check, &QCheckBox::stateChanged, [item, key](int state) { + switch (state) + { + case Qt::Checked: + item->event->put(key, true); + break; + case Qt::Unchecked: + item->event->put(key, false); + break; + } + }); } else { combo->setCurrentText(value); diff --git a/src/project.cpp b/src/project.cpp index 3906f0a6..f2a2ee6e 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -209,6 +209,9 @@ bool Project::loadMapData(Map* map) { Event *object = new Event(event, EventType::Object); object->put("map_name", map->name); object->put("sprite", event["graphics_id"].toString()); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + object->put("in_connection", event["in_connection"].toBool()); + } object->put("x", QString::number(event["x"].toInt())); object->put("y", QString::number(event["y"].toInt())); object->put("elevation", QString::number(event["elevation"].toInt())); From a2f38341f52e68981414134b8e899428f11a2392 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 11 Mar 2020 17:06:26 -0400 Subject: [PATCH 05/33] Save changes to floor_number --- include/mainwindow.h | 1 + src/mainwindow.cpp | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index 8d5d3e20..48df4608 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -68,6 +68,7 @@ private slots: void on_checkBox_AllowRunning_clicked(bool checked); void on_checkBox_AllowBiking_clicked(bool checked); void on_checkBox_AllowEscapeRope_clicked(bool checked); + void on_spinBox_FloorNumber_valueChanged(int offset); void on_tabWidget_currentChanged(int index); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 590c8f88..2a1ed2d4 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -620,6 +620,13 @@ void MainWindow::on_checkBox_AllowEscapeRope_clicked(bool checked) } } +void MainWindow::on_spinBox_FloorNumber_valueChanged(int offset) +{ + if (editor && editor->map) { + editor->map->floorNumber = offset; + } +} + bool MainWindow::loadDataStructures() { Project *project = editor->project; bool success = project->readMapLayouts() @@ -1612,6 +1619,7 @@ void MainWindow::updateSelectedObjects() { combo->addItem(value); } + // Keys using spin boxes if (key == "quantity") { spin->setValue(value.toInt()); @@ -1622,7 +1630,7 @@ void MainWindow::updateSelectedObjects() { connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, key](int value) { item->event->put(key, value); }); - + // Keys using check boxes } else if (key == "underfoot" || key == "in_connection") { check->setChecked(value.toInt()); @@ -1641,6 +1649,7 @@ void MainWindow::updateSelectedObjects() { break; } }); + // Keys using combo boxes } else { combo->setCurrentText(value); From a8b381a0b5024d559a5216f77021bb1af6c068f2 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 11 Mar 2020 19:33:22 -0400 Subject: [PATCH 06/33] Match tileset names with underscores and unknown paths --- src/project.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/project.cpp b/src/project.cpp index f2a2ee6e..3783f4b2 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1291,8 +1291,9 @@ void Project::loadTilesetAssets(Tileset* tileset) { if (tileset->name.isNull()) { return; } + QRegularExpression re("([a-z])([A-Z])"); QString tilesetName = tileset->name; - QString dir_path = root + "/data/tilesets/" + category + "/" + tilesetName.replace("gTileset_", "").toLower(); + QString dir_path = root + "/data/tilesets/" + category + "/" + tilesetName.replace("gTileset_", "").replace(re, "\\1_\\2").toLower(); QList<QStringList> *graphics = parser.parseAsm("data/tilesets/graphics.inc"); QStringList *tiles_values = parser.getLabelValues(graphics, tileset->tiles_label); From a5c47b6333a5036271658edc5506ad940be4f8d7 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Thu, 12 Mar 2020 12:30:37 -0400 Subject: [PATCH 07/33] Disable RME(temporarily), secret bases, and weather triggers for pokefirered --- include/ui/neweventtoolbutton.h | 16 ++++++++-------- src/mainwindow.cpp | 11 ++++++++--- src/project.cpp | 2 -- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/ui/neweventtoolbutton.h b/include/ui/neweventtoolbutton.h index 007dcd51..1168d447 100644 --- a/include/ui/neweventtoolbutton.h +++ b/include/ui/neweventtoolbutton.h @@ -10,6 +10,14 @@ class NewEventToolButton : public QToolButton public: explicit NewEventToolButton(QWidget *parent = nullptr); QString getSelectedEventType(); + QAction *newObjectAction; + QAction *newWarpAction; + QAction *newHealLocationAction; + QAction *newTriggerAction; + QAction *newWeatherTriggerAction; + QAction *newSignAction; + QAction *newHiddenItemAction; + QAction *newSecretBaseAction; public slots: void newObject(); void newWarp(); @@ -23,14 +31,6 @@ signals: void newEventAdded(QString); private: QString selectedEventType; - QAction *newObjectAction; - QAction *newWarpAction; - QAction *newHealLocationAction; - QAction *newTriggerAction; - QAction *newWeatherTriggerAction; - QAction *newSignAction; - QAction *newHiddenItemAction; - QAction *newSecretBaseAction; void init(); }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2a1ed2d4..510ff4e9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -50,7 +50,6 @@ MainWindow::MainWindow(QWidget *parent) : // Re-initialize everything to a blank slate if opening the recent project failed. this->initWindow(); } - on_toolButton_Paint_clicked(); } @@ -185,6 +184,11 @@ void MainWindow::setProjectSpecificUIVisibility() ui->label_AllowBiking->setVisible(true); ui->label_AllowEscapeRope->setVisible(true); ui->label_FloorNumber->setVisible(true); + ui->newEventToolButton->newWeatherTriggerAction->setVisible(false); + ui->newEventToolButton->newSecretBaseAction->setVisible(false); + // TODO: pokefirered is not set up for the Region Map Editor and vice versa. + // porymap will crash on attempt. Remove below once resolved + ui->actionRegion_Map_Editor->setVisible(false); break; } } @@ -639,7 +643,6 @@ bool MainWindow::loadDataStructures() { && project->readMapTypes() && project->readMapBattleScenes() && project->readWeatherNames() - && project->readCoordEventWeatherNames() && project->readBgEventFacingDirections() && project->readMetatileBehaviors() && project->readTilesetProperties() @@ -648,7 +651,9 @@ bool MainWindow::loadDataStructures() { && project->readSpeciesIconPaths() && project->readWildMonData(); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald || projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) - success = success && project->readSecretBaseIds(); + success = success + && project->readSecretBaseIds() + && project->readCoordEventWeatherNames(); if (!success) { return false; } diff --git a/src/project.cpp b/src/project.cpp index 3783f4b2..a7a2ccfe 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1961,8 +1961,6 @@ bool Project::readWeatherNames() { } bool Project::readCoordEventWeatherNames() { - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) - return true; coordEventWeatherNames->clear(); QStringList prefixes = (QStringList() << "COORD_EVENT_WEATHER_"); QString filename = "include/constants/weather.h"; From 629abd3c06922097f44a0672f490f39e2617956e Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 13 Mar 2020 02:23:47 -0400 Subject: [PATCH 08/33] Support reading/displaying custom border sizes --- include/config.h | 3 ++ include/core/map.h | 5 +++ include/core/maplayout.h | 2 ++ src/config.cpp | 21 ++++++++++-- src/core/map.cpp | 12 +++++-- src/editor.cpp | 4 +-- src/project.cpp | 51 ++++++++++++++++++++++++---- src/ui/bordermetatilespixmapitem.cpp | 14 ++++---- src/ui/newmappopup.cpp | 2 ++ 9 files changed, 95 insertions(+), 19 deletions(-) diff --git a/include/config.h b/include/config.h index 2a14c399..e265df28 100644 --- a/include/config.h +++ b/include/config.h @@ -109,6 +109,8 @@ public: void setUsePoryScript(bool usePoryScript); bool getUsePoryScript(); void setProjectDir(QString projectDir); + void setUseCustomBorderSize(bool enable); + bool getUseCustomBorderSize(); protected: QString getConfigFilepath(); void parseConfigKeyValue(QString key, QString value); @@ -119,6 +121,7 @@ private: QString projectDir; bool useEncounterJson; bool usePoryScript; + bool useCustomBorderSize; }; extern ProjectConfig projectConfig; diff --git a/include/core/map.h b/include/core/map.h index 7f9ff989..8be435a8 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -14,6 +14,9 @@ #include <QGraphicsPixmapItem> #include <math.h> +#define DEFAULT_BORDER_WIDTH 2 +#define DEFAULT_BORDER_HEIGHT 2 + class Map : public QObject { Q_OBJECT @@ -58,6 +61,8 @@ public: static QString bgEventsLabelFromName(QString mapName); int getWidth(); int getHeight(); + int getBorderWidth(); + int getBorderHeight(); QPixmap render(bool ignoreCache, MapLayout * fromLayout = nullptr); QPixmap renderCollision(qreal opacity, bool ignoreCache); bool blockChanged(int, Blockdata*); diff --git a/include/core/maplayout.h b/include/core/maplayout.h index df074785..c2c71d8e 100644 --- a/include/core/maplayout.h +++ b/include/core/maplayout.h @@ -15,6 +15,8 @@ public: QString name; QString width; QString height; + QString border_width; + QString border_height; QString border_path; QString blockdata_path; QString tileset_primary_label; diff --git a/src/config.cpp b/src/config.cpp index 50e5ca83..da684887 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -356,12 +356,18 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { if (!ok) { logWarn(QString("Invalid config value for use_encounter_json: '%1'. Must be 0 or 1.").arg(value)); } - } else if(key == "use_poryscript") { + } else if (key == "use_poryscript") { bool ok; this->usePoryScript = value.toInt(&ok); - if(!ok) { + if (!ok) { logWarn(QString("Invalid config value for use_poryscript: '%1'. Must be 0 or 1.").arg(value)); } + } else if (key == "use_custom_border_size") { + bool ok; + this->useCustomBorderSize = value.toInt(&ok); + if (!ok) { + logWarn(QString("Invalid config value for use_custom_border_size: '%1'. Must be 0 or 1.").arg(value)); + } } else { logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key)); } @@ -372,6 +378,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() { map.insert("base_game_version", baseGameVersionMap.value(this->baseGameVersion)); map.insert("use_encounter_json", QString::number(this->useEncounterJson)); map.insert("use_poryscript", QString::number(this->usePoryScript)); + map.insert("use_custom_border_size", QString::number(this->useCustomBorderSize)); return map; } @@ -401,6 +408,7 @@ void ProjectConfig::onNewConfigFileCreated() { this->baseGameVersion = static_cast<BaseGameVersion>(baseGameVersionComboBox->currentData().toInt()); } } + this->useCustomBorderSize = this->baseGameVersion == BaseGameVersion::pokefirered; this->useEncounterJson = true; this->usePoryScript = false; } @@ -435,3 +443,12 @@ void ProjectConfig::setUsePoryScript(bool usePoryScript) { bool ProjectConfig::getUsePoryScript() { return this->usePoryScript; } + +void ProjectConfig::setUseCustomBorderSize(bool enable) { + this->useCustomBorderSize = enable; + this->save(); +} + +bool ProjectConfig::getUseCustomBorderSize() { + return this->useCustomBorderSize; +} diff --git a/src/core/map.cpp b/src/core/map.cpp index f9df72fd..c4e88dd4 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -59,6 +59,14 @@ int Map::getHeight() { return layout->height.toInt(nullptr, 0); } +int Map::getBorderWidth() { + return layout->border_width.toInt(nullptr, 0); +} + +int Map::getBorderHeight() { + return layout->border_height.toInt(nullptr, 0); +} + bool Map::blockChanged(int i, Blockdata *cache) { if (!cache) return true; @@ -197,8 +205,8 @@ QPixmap Map::render(bool ignoreCache = false, MapLayout * fromLayout) { QPixmap Map::renderBorder() { bool changed_any = false; - int width_ = 2; - int height_ = 2; + int width_ = getBorderWidth(); + int height_ = getBorderHeight(); if (layout->border_image.isNull()) { layout->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); changed_any = true; diff --git a/src/editor.cpp b/src/editor.cpp index b52f81b7..d424254f 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1335,8 +1335,8 @@ void Editor::displayMapBorder() { borderItems.clear(); QPixmap pixmap = map->renderBorder(); - for (int y = -6; y < map->getHeight() + 6; y += 2) - for (int x = -6; x < map->getWidth() + 6; x += 2) { + for (int y = -6; y < map->getHeight() + 6; y += map->getBorderHeight()) + for (int x = -6; x < map->getWidth() + 6; x += map->getBorderWidth()) { QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); item->setX(x * 16); item->setY(y * 16); diff --git a/src/project.cpp b/src/project.cpp index a7a2ccfe..ab840edb 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -8,6 +8,7 @@ #include "tile.h" #include "tileset.h" #include "imageexport.h" +#include "map.h" #include <QDir> #include <QJsonArray> @@ -489,6 +490,11 @@ bool Project::readMapLayouts() { "border_filepath", "blockdata_filepath", }; + bool useCustomBorderSize = projectConfig.getUseCustomBorderSize(); + if (useCustomBorderSize) { + requiredFields.append("border_width"); + requiredFields.append("border_height"); + } for (int i = 0; i < layouts.size(); i++) { QJsonObject layoutObj = layouts[i].toObject(); if (layoutObj.isEmpty()) @@ -520,6 +526,23 @@ bool Project::readMapLayouts() { return false; } layout->height = QString::number(lheight); + if (useCustomBorderSize) { + int bwidth = layoutObj["border_width"].toInt(); + if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG + logWarn(QString("Invalid layout 'border_width' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bwidth).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_WIDTH)); + bwidth = DEFAULT_BORDER_WIDTH; + } + layout->border_width = QString::number(bwidth); + int bheight = layoutObj["border_height"].toInt(); + if (bheight <= 0) { + logWarn(QString("Invalid layout 'border_height value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT)); + bheight = DEFAULT_BORDER_HEIGHT; + } + layout->border_height = QString::number(bheight); + } else { + layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); + layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); + } layout->tileset_primary_label = layoutObj["primary_tileset"].toString(); if (layout->tileset_primary_label.isEmpty()) { logError(QString("Missing 'primary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); @@ -536,7 +559,7 @@ bool Project::readMapLayouts() { return false; } layout->blockdata_path = layoutObj["blockdata_filepath"].toString(); - if (layout->border_path.isEmpty()) { + if (layout->blockdata_path.isEmpty()) { logError(QString("Missing 'blockdata_filepath' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); return false; } @@ -563,6 +586,7 @@ void Project::saveMapLayouts() { QJsonObject layoutsObj; layoutsObj["layouts_table_label"] = layoutsLabel; + bool useCustomBorderSize = projectConfig.getUseCustomBorderSize(); QJsonArray layoutsArr; for (QString layoutId : mapLayoutsTableMaster) { MapLayout *layout = mapLayouts.value(layoutId); @@ -571,6 +595,10 @@ void Project::saveMapLayouts() { layoutObj["name"] = layout->name; layoutObj["width"] = layout->width.toInt(nullptr, 0); layoutObj["height"] = layout->height.toInt(nullptr, 0); + if (useCustomBorderSize) { + layoutObj["border_width"] = layout->border_width.toInt(nullptr, 0); + layoutObj["border_height"] = layout->border_height.toInt(nullptr, 0); + } layoutObj["primary_tileset"] = layout->tileset_primary_label; layoutObj["secondary_tileset"] = layout->tileset_secondary_label; layoutObj["border_filepath"] = layout->border_path; @@ -1034,7 +1062,7 @@ bool Project::loadMapBorder(Map *map) { QString path = QString("%1/%2").arg(root).arg(map->layout->border_path); map->layout->border = readBlockdata(path); - int borderLength = 4; + int borderLength = map->getBorderWidth() * map->getBorderHeight(); if (map->layout->border->blocks->count() != borderLength) { logWarn(QString("Layout border blockdata length %1 must be %2. Resizing border blockdata.") .arg(map->layout->border->blocks->count()) @@ -1046,10 +1074,17 @@ bool Project::loadMapBorder(Map *map) { void Project::setNewMapBorder(Map *map) { Blockdata *blockdata = new Blockdata; - blockdata->addBlock(qint16(0x01D4)); - blockdata->addBlock(qint16(0x01D5)); - blockdata->addBlock(qint16(0x01DC)); - blockdata->addBlock(qint16(0x01DD)); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + blockdata->addBlock(qint16(0x0014)); + blockdata->addBlock(qint16(0x0015)); + blockdata->addBlock(qint16(0x001C)); + blockdata->addBlock(qint16(0x001D)); + } else { + blockdata->addBlock(qint16(0x01D4)); + blockdata->addBlock(qint16(0x01D5)); + blockdata->addBlock(qint16(0x01DC)); + blockdata->addBlock(qint16(0x01DD)); + } map->layout->border = blockdata; } @@ -1136,6 +1171,10 @@ void Project::saveMap(Map *map) { newLayoutObj["name"] = map->layout->name; newLayoutObj["width"] = map->layout->width.toInt(); newLayoutObj["height"] = map->layout->height.toInt(); + if (projectConfig.getUseCustomBorderSize()) { + newLayoutObj["border_width"] = map->layout->border_width.toInt(); + newLayoutObj["border_height"] = map->layout->border_height.toInt(); + } newLayoutObj["primary_tileset"] = map->layout->tileset_primary_label; newLayoutObj["secondary_tileset"] = map->layout->tileset_secondary_label; newLayoutObj["border_filepath"] = map->layout->border_path; diff --git a/src/ui/bordermetatilespixmapitem.cpp b/src/ui/bordermetatilespixmapitem.cpp index 2093eabe..f5f4d2c4 100644 --- a/src/ui/bordermetatilespixmapitem.cpp +++ b/src/ui/bordermetatilespixmapitem.cpp @@ -9,9 +9,9 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) int x = static_cast<int>(pos.x()) / 16; int y = static_cast<int>(pos.y()) / 16; - for (int i = 0; i < selectionDimensions.x() && (i + x) < 2; i++) { - for (int j = 0; j < selectionDimensions.y() && (j + y) < 2; j++) { - int blockIndex = (j + y) * 2 + (i + x); + for (int i = 0; i < selectionDimensions.x() && (i + x) < map->getBorderWidth(); i++) { + for (int j = 0; j < selectionDimensions.y() && (j + y) < map->getBorderHeight(); j++) { + int blockIndex = (j + y) * map->getBorderWidth() + (i + x); uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i); (*map->layout->border->blocks)[blockIndex].tile = tile; } @@ -22,15 +22,15 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) } void BorderMetatilesPixmapItem::draw() { - QImage image(32, 32, QImage::Format_RGBA8888); + QImage image(16 * map->getBorderWidth(), 16 * map->getBorderHeight(), QImage::Format_RGBA8888); QPainter painter(&image); QVector<Block> *blocks = map->layout->border->blocks; - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { + for (int i = 0; i < map->getBorderWidth(); i++) { + for (int j = 0; j < map->getBorderHeight(); j++) { int x = i * 16; int y = j * 16; - int index = j * 2 + i; + int index = j * map->getBorderWidth() + i; QImage metatile_image = getMetatileImage(blocks->value(index).tile, map->layout->tileset_primary, map->layout->tileset_secondary); QPoint metatile_origin = QPoint(x, y); painter.drawImage(metatile_origin, metatile_image); diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 9191a73f..8323278a 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -154,6 +154,8 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { layout->name = QString("%1_Layout").arg(newMap->name); layout->width = QString::number(this->ui->spinBox_NewMap_Width->value()); layout->height = QString::number(this->ui->spinBox_NewMap_Height->value()); + layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); + layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText(); layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText(); layout->border_path = QString("data/layouts/%1/border.bin").arg(newMapName); From c0a512803effdddeb7dd2b81f425eb71fdfedba2 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sat, 14 Mar 2020 03:44:55 -0400 Subject: [PATCH 09/33] Allow editing border dimensions --- forms/mainwindow.ui | 720 +++++++++++++++------------ forms/newmappopup.ui | 72 ++- include/core/historyitem.h | 5 +- include/core/map.h | 11 +- include/mainwindow.h | 2 +- src/core/historyitem.cpp | 6 +- src/core/map.cpp | 136 ++++- src/editor.cpp | 12 +- src/mainwindow.cpp | 29 +- src/project.cpp | 8 +- src/ui/bordermetatilespixmapitem.cpp | 18 +- src/ui/newmappopup.cpp | 24 +- 12 files changed, 645 insertions(+), 398 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 676b8174..c65e6cde 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -7,15 +7,15 @@ <x>0</x> <y>0</y> <width>1117</width> - <height>747</height> + <height>788</height> </rect> </property> <property name="windowTitle"> <string>porymap</string> </property> <widget class="QWidget" name="centralWidget"> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> + <layout class="QGridLayout" name="gridLayout_15"> + <item row="0" column="0"> <widget class="QSplitter" name="splitter_main"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -512,7 +512,7 @@ </spacer> </item> <item> - <widget class="QPushButton" name="pushButton"> + <widget class="QPushButton" name="pushButton_ChangeDimensions"> <property name="toolTip"> <string><html><head/><body><p>Change a map layout's width and height.</p></body></html></string> </property> @@ -561,8 +561,8 @@ <rect> <x>0</x> <y>0</y> - <width>469</width> - <height>608</height> + <width>545</width> + <height>628</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_8"> @@ -736,305 +736,6 @@ <property name="spacing"> <number>3</number> </property> - <item row="0" column="0"> - <widget class="QFrame" name="frame_Tilesets"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label_PrimaryTileset"> - <property name="text"> - <string>Primary Tileset</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="NoScrollComboBox" name="comboBox_PrimaryTileset"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Primary Tileset</p><p>Defines the first 0x200 metatiles available for the map.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_SecondaryTileset"> - <property name="text"> - <string>Secondary Tileset</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="NoScrollComboBox" name="comboBox_SecondaryTileset"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="toolTip"> - <string><html><head/><body><p>Secondary Tileset</p><p>Defines the second 0x200 metatiles available for the map.</p></body></html></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="2" column="0"> - <widget class="QFrame" name="frame_currentMetatileSelection"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>92</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>92</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <property name="spacing"> - <number>0</number> - </property> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Selection</string> - </property> - <layout class="QGridLayout" name="gridLayout_17"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QScrollArea" name="scrollArea_6"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_6"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>324</width> - <height>77</height> - </rect> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_7"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <spacer name="horizontalSpacer_16"> - <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> - <widget class="QGraphicsView" name="graphicsView_currentMetatileSelection"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="interactive"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_17"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Border</string> - </property> - <layout class="QGridLayout" name="gridLayout_16"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="1"> - <widget class="QGraphicsView" name="graphicsView_BorderMetatile"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>48</height> - </size> - </property> - <property name="toolTip"> - <string><html><head/><body><p>The border is a 2x2 metatile which is repeated outside of the map layout's boundary. Draw on this border area to modify it.</p></body></html></string> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Sunken</enum> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - </widget> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_12"> - <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="2"> - <spacer name="horizontalSpacer_13"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> <item row="3" column="0"> <widget class="QScrollArea" name="scrollArea_2"> <property name="sizePolicy"> @@ -1064,10 +765,10 @@ </property> <property name="geometry"> <rect> - <x>0</x> + <x>8</x> <y>0</y> - <width>307</width> - <height>362</height> + <width>221</width> + <height>324</height> </rect> </property> <property name="sizePolicy"> @@ -1160,6 +861,309 @@ </widget> </widget> </item> + <item row="2" column="0"> + <widget class="QFrame" name="frame_currentMetatileSelection"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>92</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>92</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <property name="spacing"> + <number>0</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Selection</string> + </property> + <layout class="QGridLayout" name="gridLayout_17"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QScrollArea" name="scrollArea_6"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_6"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>256</width> + <height>74</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="horizontalSpacer_16"> + <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> + <widget class="QGraphicsView" name="graphicsView_currentMetatileSelection"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="interactive"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_17"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>110</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>110</height> + </size> + </property> + <property name="title"> + <string>Border</string> + </property> + <layout class="QGridLayout" name="gridLayout_16"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QWidget" name="widget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinAndMaxSize</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QScrollArea" name="scrollArea_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>231</width> + <height>83</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout_18"> + <item row="0" column="0"> + <widget class="QGraphicsView" name="graphicsView_BorderMetatile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>1</width> + <height>1</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>The border is a group of metatiles which are repeated outside of the map layout's boundary. Draw on this border area to modify it.</p></body></html></string> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> <item row="4" column="0"> <widget class="QSlider" name="horizontalSlider_MetatileZoom"> <property name="minimum"> @@ -1176,6 +1180,64 @@ </property> </widget> </item> + <item row="0" column="0"> + <widget class="QFrame" name="frame_Tilesets"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_PrimaryTileset"> + <property name="text"> + <string>Primary Tileset</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="NoScrollComboBox" name="comboBox_PrimaryTileset"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Primary Tileset</p><p>Defines the first 0x200 metatiles available for the map.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_SecondaryTileset"> + <property name="text"> + <string>Secondary Tileset</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="NoScrollComboBox" name="comboBox_SecondaryTileset"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Secondary Tileset</p><p>Defines the second 0x200 metatiles available for the map.</p></body></html></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> </layout> </widget> <widget class="QWidget" name="tab_collision"> @@ -1344,8 +1406,8 @@ <rect> <x>0</x> <y>0</y> - <width>381</width> - <height>657</height> + <width>371</width> + <height>684</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_7"> @@ -1618,7 +1680,7 @@ <x>0</x> <y>0</y> <width>430</width> - <height>568</height> + <height>575</height> </rect> </property> <property name="sizePolicy"> @@ -2095,21 +2157,21 @@ </widget> </item> <item row="11" column="0"> - <widget class="QLabel" name="label_FloorNumber"> - <property name="text"> - <string>Floor Number</string> - </property> - </widget> - </item> - <item row="11" column="1"> - <widget class="QSpinBox" name="spinBox_FloorNumber"> - <property name="toolTip"> - <string><html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html></string> - </property> - <property name="maximum"> - <number>127</number> - </property> - </widget> + <widget class="QLabel" name="label_FloorNumber"> + <property name="text"> + <string>Floor Number</string> + </property> + </widget> + </item> + <item row="11" column="1"> + <widget class="QSpinBox" name="spinBox_FloorNumber"> + <property name="toolTip"> + <string><html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html></string> + </property> + <property name="maximum"> + <number>127</number> + </property> + </widget> </item> </layout> </widget> @@ -2548,8 +2610,8 @@ <rect> <x>0</x> <y>0</y> - <width>826</width> - <height>557</height> + <width>818</width> + <height>574</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_14"> @@ -2813,7 +2875,7 @@ <x>0</x> <y>0</y> <width>1117</width> - <height>21</height> + <height>22</height> </rect> </property> <widget class="QMenu" name="menuFile"> diff --git a/forms/newmappopup.ui b/forms/newmappopup.ui index 41aaaf77..b9595ec8 100644 --- a/forms/newmappopup.ui +++ b/forms/newmappopup.ui @@ -73,7 +73,7 @@ <item row="2" column="0"> <widget class="QLabel" name="label_NewMap_Width"> <property name="text"> - <string>Width</string> + <string>Map Width</string> </property> </widget> </item> @@ -90,7 +90,7 @@ <item row="3" column="0"> <widget class="QLabel" name="label_NewMap_Height"> <property name="text"> - <string>Height</string> + <string>Map Height</string> </property> </widget> </item> @@ -105,13 +105,47 @@ </widget> </item> <item row="4" column="0"> + <widget class="QLabel" name="label_NewMap_BorderWidth"> + <property name="text"> + <string>Border Width</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QSpinBox" name="spinBox_NewMap_BorderWidth"> + <property name="toolTip"> + <string><html><head/><body><p>Width (in blocks) of the new map's border.</p></body></html></string> + </property> + <property name="maximum"> + <number>255</number> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_NewMap_BorderHeight"> + <property name="text"> + <string>Border Height</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QSpinBox" name="spinBox_NewMap_BorderHeight"> + <property name="toolTip"> + <string><html><head/><body><p>Height (in blocks) of the new map's border.</p></body></html></string> + </property> + <property name="maximum"> + <number>255</number> + </property> + </widget> + </item> + <item row="6" column="0"> <widget class="QLabel" name="label_NewMap_Primary_Tileset"> <property name="text"> <string>Primary Tileset</string> </property> </widget> </item> - <item row="4" column="1"> + <item row="6" column="1"> <widget class="NoScrollComboBox" name="comboBox_NewMap_Primary_Tileset"> <property name="toolTip"> <string><html><head/><body><p>The primary tileset for the new map.</p></body></html></string> @@ -121,14 +155,14 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="label_NewMap_Secondary_Tileset"> <property name="text"> <string>Secondary Tileset</string> </property> </widget> </item> - <item row="5" column="1"> + <item row="7" column="1"> <widget class="NoScrollComboBox" name="comboBox_NewMap_Secondary_Tileset"> <property name="toolTip"> <string><html><head/><body><p>The secondary tileset for the new map.</p></body></html></string> @@ -138,14 +172,14 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="8" column="0"> <widget class="QLabel" name="label_NewMap_Type"> <property name="text"> <string>Type</string> </property> </widget> </item> - <item row="6" column="1"> + <item row="8" column="1"> <widget class="NoScrollComboBox" name="comboBox_NewMap_Type"> <property name="toolTip"> <string><html><head/><body><p>The map type is a general attribute, which is used for many different things. For example. it determines whether biking or running is allowed.</p></body></html></string> @@ -155,14 +189,14 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_NewMap_Location"> <property name="text"> <string>Location</string> </property> </widget> </item> - <item row="7" column="1"> + <item row="9" column="1"> <widget class="NoScrollComboBox" name="comboBox_NewMap_Location"> <property name="toolTip"> <string><html><head/><body><p>The section of the region map which the map is grouped under. This also determines the name of the map that is displayed when the player enters it.</p></body></html></string> @@ -172,14 +206,14 @@ </property> </widget> </item> - <item row="8" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_NewMap_Flyable"> <property name="text"> <string>Can Fly To</string> </property> </widget> </item> - <item row="8" column="1"> + <item row="10" column="1"> <widget class="QCheckBox" name="checkBox_NewMap_Flyable"> <property name="toolTip"> <string><html><head/><body><p>Whether to add a heal location to the new map.</p></body></html></string> @@ -189,56 +223,56 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_NewMap_Allow_Running"> <property name="text"> <string>Allow Running</string> </property> </widget> </item> - <item row="10" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="label_NewMap_Allow_Biking"> <property name="text"> <string>Allow Biking</string> </property> </widget> </item> - <item row="11" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="label_NewMap_Allow_Escape_Rope"> <property name="text"> <string>Allow Escape Rope</string> </property> </widget> </item> - <item row="9" column="1"> + <item row="11" column="1"> <widget class="QCheckBox" name="checkBox_NewMap_Allow_Running"> <property name="text"> <string/> </property> </widget> </item> - <item row="10" column="1"> + <item row="12" column="1"> <widget class="QCheckBox" name="checkBox_NewMap_Allow_Biking"> <property name="text"> <string/> </property> </widget> </item> - <item row="11" column="1"> + <item row="13" column="1"> <widget class="QCheckBox" name="checkBox_NewMap_Allow_Escape_Rope"> <property name="text"> <string/> </property> </widget> </item> - <item row="12" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="label_NewMap_Floor_Number"> <property name="text"> <string>Floor Number</string> </property> </widget> </item> - <item row="12" column="1"> + <item row="14" column="1"> <widget class="QSpinBox" name="spinBox_NewMap_Floor_Number"> <property name="toolTip"> <string><html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html></string> diff --git a/include/core/historyitem.h b/include/core/historyitem.h index 92675055..693d733c 100644 --- a/include/core/historyitem.h +++ b/include/core/historyitem.h @@ -6,9 +6,12 @@ class HistoryItem { public: Blockdata *metatiles; + Blockdata *border; int layoutWidth; int layoutHeight; - HistoryItem(Blockdata *metatiles, int layoutWidth, int layoutHeight); + int borderWidth; + int borderHeight; + HistoryItem(Blockdata *metatiles, Blockdata *border, int layoutWidth, int layoutHeight, int borderWidth, int borderHeight); ~HistoryItem(); }; diff --git a/include/core/map.h b/include/core/map.h index 8be435a8..2873844f 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -17,6 +17,10 @@ #define DEFAULT_BORDER_WIDTH 2 #define DEFAULT_BORDER_HEIGHT 2 +// Number of metatiles to draw out from edge of map. Could allow modification of this in the future. +// porymap will reflect changes to it, but the value is hard-coded in the projects at the moment +#define BORDER_DISTANCE 6 + class Map : public QObject { Q_OBJECT @@ -65,7 +69,8 @@ public: int getBorderHeight(); QPixmap render(bool ignoreCache, MapLayout * fromLayout = nullptr); QPixmap renderCollision(qreal opacity, bool ignoreCache); - bool blockChanged(int, Blockdata*); + bool mapBlockChanged(int i, Blockdata * cache); + bool borderBlockChanged(int i, Blockdata * cache); void cacheBlockdata(); void cacheCollision(); Block *getBlock(int x, int y); @@ -82,12 +87,14 @@ public: void addEvent(Event*); QPixmap renderConnection(MapConnection, MapLayout *); QPixmap renderBorder(); - void setDimensions(int newWidth, int newHeight, bool setNewBlockData = true); + void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true); + void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true); void cacheBorder(); bool hasUnsavedChanges(); private: void setNewDimensionsBlockdata(int newWidth, int newHeight); + void setNewBorderDimensionsBlockdata(int newWidth, int newHeight); signals: void mapChanged(Map *map); diff --git a/include/mainwindow.h b/include/mainwindow.h index 48df4608..9113e227 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -119,7 +119,7 @@ private slots: void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName); void on_comboBox_PrimaryTileset_currentTextChanged(const QString &arg1); void on_comboBox_SecondaryTileset_currentTextChanged(const QString &arg1); - void on_pushButton_clicked(); + void on_pushButton_ChangeDimensions_clicked(); void on_checkBox_smartPaths_stateChanged(int selected); void on_checkBox_Visibility_clicked(bool checked); void on_checkBox_ToggleBorder_stateChanged(int arg1); diff --git a/src/core/historyitem.cpp b/src/core/historyitem.cpp index 1b0f3888..6eb66fa3 100644 --- a/src/core/historyitem.cpp +++ b/src/core/historyitem.cpp @@ -1,13 +1,17 @@ #include "historyitem.h" -HistoryItem::HistoryItem(Blockdata *metatiles, int layoutWidth, int layoutHeight) { +HistoryItem::HistoryItem(Blockdata *metatiles, Blockdata *border, int layoutWidth, int layoutHeight, int borderWidth, int borderHeight) { this->metatiles = metatiles; + this->border = border; this->layoutWidth = layoutWidth; this->layoutHeight = layoutHeight; + this->borderWidth = borderWidth; + this->borderHeight = borderHeight; } HistoryItem::~HistoryItem() { if (this->metatiles) delete this->metatiles; + if (this->border) delete this->border; } RegionMapHistoryItem::RegionMapHistoryItem(int which, QVector<uint8_t> tiles, QString cityMap) { diff --git a/src/core/map.cpp b/src/core/map.cpp index c4e88dd4..4f89c6c6 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -67,7 +67,7 @@ int Map::getBorderHeight() { return layout->border_height.toInt(nullptr, 0); } -bool Map::blockChanged(int i, Blockdata *cache) { +bool Map::mapBlockChanged(int i, Blockdata *cache) { if (!cache) return true; if (!layout->blockdata) @@ -84,6 +84,23 @@ bool Map::blockChanged(int i, Blockdata *cache) { return layout->blockdata->blocks->value(i) != cache->blocks->value(i); } +bool Map::borderBlockChanged(int i, Blockdata *cache) { + if (!cache) + return true; + if (!layout->border) + return true; + if (!cache->blocks) + return true; + if (!layout->border->blocks) + return true; + if (cache->blocks->length() <= i) + return true; + if (layout->border->blocks->length() <= i) + return true; + + return layout->border->blocks->value(i) != cache->blocks->value(i); +} + void Map::cacheBorder() { if (layout->cached_border) delete layout->cached_border; layout->cached_border = new Blockdata; @@ -135,7 +152,7 @@ QPixmap Map::renderCollision(qreal opacity, bool ignoreCache) { } QPainter painter(&collision_image); for (int i = 0; i < layout->blockdata->blocks->length(); i++) { - if (!ignoreCache && layout->cached_collision && !blockChanged(i, layout->cached_collision)) { + if (!ignoreCache && layout->cached_collision && !mapBlockChanged(i, layout->cached_collision)) { continue; } changed_any = true; @@ -179,7 +196,7 @@ QPixmap Map::render(bool ignoreCache = false, MapLayout * fromLayout) { QPainter painter(&image); for (int i = 0; i < layout->blockdata->blocks->length(); i++) { - if (!ignoreCache && !blockChanged(i, layout->cached_blockdata)) { + if (!ignoreCache && !mapBlockChanged(i, layout->cached_blockdata)) { continue; } changed_any = true; @@ -204,27 +221,33 @@ QPixmap Map::render(bool ignoreCache = false, MapLayout * fromLayout) { } QPixmap Map::renderBorder() { - bool changed_any = false; + bool changed_any = false, border_resized = false; int width_ = getBorderWidth(); int height_ = getBorderHeight(); if (layout->border_image.isNull()) { layout->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); changed_any = true; } + if (layout->border_image.width() != width_ * 16 || layout->border_image.height() != height_ * 16) { + layout->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + border_resized = true; + } if (!(layout->border && layout->border->blocks)) { layout->border_pixmap = layout->border_pixmap.fromImage(layout->border_image); return layout->border_pixmap; } QPainter painter(&layout->border_image); for (int i = 0; i < layout->border->blocks->length(); i++) { - if (!blockChanged(i, layout->cached_border)) { + if (!border_resized && !borderBlockChanged(i, layout->cached_border)) { continue; } + changed_any = true; Block block = layout->border->blocks->value(i); - QImage metatile_image = getMetatileImage(block.tile, layout->tileset_primary, layout->tileset_secondary); - int map_y = i / width_; - int map_x = i % width_; + uint16_t tile = block.tile; + QImage metatile_image = getMetatileImage(tile, layout->tileset_primary, layout->tileset_secondary); + int map_y = width_ ? i / width_ : 0; + int map_x = width_ ? i % width_ : 0; painter.drawImage(QPoint(map_x * 16, map_y * 16), metatile_image); } painter.end(); @@ -240,23 +263,23 @@ QPixmap Map::renderConnection(MapConnection connection, MapLayout * fromLayout) int x, y, w, h; if (connection.direction == "up") { x = 0; - y = getHeight() - 6; + y = getHeight() - BORDER_DISTANCE; w = getWidth(); - h = 6; + h = BORDER_DISTANCE; } else if (connection.direction == "down") { x = 0; y = 0; w = getWidth(); - h = 6; + h = BORDER_DISTANCE; } else if (connection.direction == "left") { - x = getWidth() - 6; + x = getWidth() - BORDER_DISTANCE; y = 0; - w = 6; + w = BORDER_DISTANCE; h = getHeight(); } else if (connection.direction == "right") { x = 0; y = 0; - w = 6; + w = BORDER_DISTANCE; h = getHeight(); } else { // this should not happen @@ -289,6 +312,25 @@ void Map::setNewDimensionsBlockdata(int newWidth, int newHeight) { layout->blockdata->copyFrom(newBlockData); } +void Map::setNewBorderDimensionsBlockdata(int newWidth, int newHeight) { + int oldWidth = getBorderWidth(); + int oldHeight = getBorderHeight(); + + Blockdata* newBlockData = new Blockdata; + + for (int y = 0; y < newHeight; y++) + for (int x = 0; x < newWidth; x++) { + if (x < oldWidth && y < oldHeight) { + int index = y * oldWidth + x; + newBlockData->addBlock(layout->border->blocks->value(index)); + } else { + newBlockData->addBlock(0); + } + } + + layout->border->copyFrom(newBlockData); +} + void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata) { if (setNewBlockdata) { setNewDimensionsBlockdata(newWidth, newHeight); @@ -300,6 +342,17 @@ void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata) { emit mapChanged(this); } +void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata) { + if (setNewBlockdata) { + setNewBorderDimensionsBlockdata(newWidth, newHeight); + } + + layout->border_width = QString::number(newWidth); + layout->border_height = QString::number(newHeight); + + emit mapChanged(this); +} + Block* Map::getBlock(int x, int y) { if (layout->blockdata && layout->blockdata->blocks) { if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { @@ -354,35 +407,64 @@ void Map::_floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_ } void Map::undo() { + bool redraw = false, changed = false; HistoryItem *commit = metatileHistory.back(); if (!commit) return; + if (layout->blockdata) { layout->blockdata->copyFrom(commit->metatiles); - if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) - { + if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) { this->setDimensions(commit->layoutWidth, commit->layoutHeight, false); - emit mapNeedsRedrawing(); + redraw = true; } + changed = true; + } + if (layout->border) { + layout->border->copyFrom(commit->border); + if (commit->borderWidth != this->getBorderWidth() || commit->borderHeight != this->getBorderHeight()) { + this->setBorderDimensions(commit->borderWidth, commit->borderHeight, false); + redraw = true; + } + changed = true; + } + if (redraw) { + emit mapNeedsRedrawing(); + } + if (changed) { emit mapChanged(this); } } void Map::redo() { + bool redraw = false, changed = false; HistoryItem *commit = metatileHistory.next(); if (!commit) return; if (layout->blockdata) { layout->blockdata->copyFrom(commit->metatiles); - if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) - { + if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) { this->setDimensions(commit->layoutWidth, commit->layoutHeight, false); - emit mapNeedsRedrawing(); + redraw = true; } + changed = true; + } + if (layout->border) { + layout->border->copyFrom(commit->border); + if (commit->borderWidth != this->getBorderWidth() || commit->borderHeight != this->getBorderHeight()) { + this->setBorderDimensions(commit->borderWidth, commit->borderHeight, false); + redraw = true; + } + changed = true; + } + if (redraw) { + emit mapNeedsRedrawing(); + } + if (changed) { emit mapChanged(this); } } @@ -392,14 +474,22 @@ void Map::commit() { return; } + int layoutWidth = this->getWidth(); + int layoutHeight = this->getHeight(); + int borderWidth = this->getBorderWidth(); + int borderHeight = this->getBorderHeight(); + if (layout->blockdata) { HistoryItem *item = metatileHistory.current(); bool atCurrentHistory = item && layout->blockdata->equals(item->metatiles) - && this->getWidth() == item->layoutWidth - && this->getHeight() == item->layoutHeight; + && layout->border->equals(item->border) + && layoutWidth == item->layoutWidth + && layoutHeight == item->layoutHeight + && borderWidth == item->borderWidth + && borderHeight == item->borderHeight; if (!atCurrentHistory) { - HistoryItem *commit = new HistoryItem(layout->blockdata->copy(), this->getWidth(), this->getHeight()); + HistoryItem *commit = new HistoryItem(layout->blockdata->copy(), layout->border->copy(), layoutWidth, layoutHeight, borderWidth, borderHeight); metatileHistory.push(commit); emit mapChanged(this); } diff --git a/src/editor.cpp b/src/editor.cpp index d424254f..ff0b6d8b 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1136,10 +1136,10 @@ void Editor::displayMapMetatiles() { int tw = 16; int th = 16; scene->setSceneRect( - -6 * tw, - -6 * th, - map_item->pixmap().width() + 12 * tw, - map_item->pixmap().height() + 12 * th + -BORDER_DISTANCE * tw, + -BORDER_DISTANCE * th, + map_item->pixmap().width() + (BORDER_DISTANCE * 2) * tw, + map_item->pixmap().height() + (BORDER_DISTANCE * 2) * th ); } @@ -1335,8 +1335,8 @@ void Editor::displayMapBorder() { borderItems.clear(); QPixmap pixmap = map->renderBorder(); - for (int y = -6; y < map->getHeight() + 6; y += map->getBorderHeight()) - for (int x = -6; x < map->getWidth() + 6; x += map->getBorderWidth()) { + for (int y = -BORDER_DISTANCE; y < map->getHeight() + BORDER_DISTANCE; y += map->getBorderHeight()) + for (int x = -BORDER_DISTANCE; x < map->getWidth() + BORDER_DISTANCE; x += map->getBorderWidth()) { QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); item->setX(x * 16); item->setY(y * 16); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 510ff4e9..89bc9bc5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2150,7 +2150,7 @@ void MainWindow::on_comboBox_SecondaryTileset_currentTextChanged(const QString & } } -void MainWindow::on_pushButton_clicked() +void MainWindow::on_pushButton_ChangeDimensions_clicked() { QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint); dialog.setWindowTitle("Change Map Dimensions"); @@ -2160,15 +2160,31 @@ void MainWindow::on_pushButton_clicked() QSpinBox *widthSpinBox = new QSpinBox(); QSpinBox *heightSpinBox = new QSpinBox(); + QSpinBox *bwidthSpinBox = new QSpinBox(); + QSpinBox *bheightSpinBox = new QSpinBox(); widthSpinBox->setMinimum(1); heightSpinBox->setMinimum(1); + bwidthSpinBox->setMinimum(1); + bheightSpinBox->setMinimum(1); // See below for explanation of maximum map dimensions widthSpinBox->setMaximum(0x1E7); heightSpinBox->setMaximum(0x1D1); + // Maximum based only on data type (u8) of map border width/height + bwidthSpinBox->setMaximum(255); + bheightSpinBox->setMaximum(255); widthSpinBox->setValue(editor->map->getWidth()); heightSpinBox->setValue(editor->map->getHeight()); - form.addRow(new QLabel("Width"), widthSpinBox); - form.addRow(new QLabel("Height"), heightSpinBox); + bwidthSpinBox->setValue(editor->map->getBorderWidth()); + bheightSpinBox->setValue(editor->map->getBorderHeight()); + if (projectConfig.getUseCustomBorderSize()) { + form.addRow(new QLabel("Map Width"), widthSpinBox); + form.addRow(new QLabel("Map Height"), heightSpinBox); + form.addRow(new QLabel("Border Width"), bwidthSpinBox); + form.addRow(new QLabel("Border Height"), bheightSpinBox); + } else { + form.addRow(new QLabel("Width"), widthSpinBox); + form.addRow(new QLabel("Height"), heightSpinBox); + } QLabel *errorLabel = new QLabel(); QPalette errorPalette; @@ -2178,7 +2194,7 @@ void MainWindow::on_pushButton_clicked() QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); form.addRow(&buttonBox); - connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &errorLabel](){ + connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &bwidthSpinBox, &bheightSpinBox, &errorLabel](){ // Ensure width and height are an acceptable size. // The maximum number of metatiles in a map is the following: // max = (width + 15) * (height + 14) @@ -2190,8 +2206,8 @@ void MainWindow::on_pushButton_clicked() dialog.accept(); } else { QString errorText = QString("Error: The specified width and height are too large.\n" - "The maximum width and height is the following: (width + 15) * (height + 14) <= 10240\n" - "The specified width and height was: (%1 + 15) * (%2 + 14) = %3") + "The maximum map width and height is the following: (width + 15) * (height + 14) <= 10240\n" + "The specified map width and height was: (%1 + 15) * (%2 + 14) = %3") .arg(widthSpinBox->value()) .arg(heightSpinBox->value()) .arg(numMetatiles); @@ -2205,6 +2221,7 @@ void MainWindow::on_pushButton_clicked() if (dialog.exec() == QDialog::Accepted) { editor->map->setDimensions(widthSpinBox->value(), heightSpinBox->value()); + editor->map->setBorderDimensions(bwidthSpinBox->value(), bheightSpinBox->value()); editor->map->commit(); onMapNeedsRedrawing(); } diff --git a/src/project.cpp b/src/project.cpp index ab840edb..55db6cd3 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -617,6 +617,8 @@ void Project::setNewMapLayout(Map* map) { layout->name = QString("%1_Layout").arg(map->name); layout->width = "20"; layout->height = "20"; + layout->border_width = DEFAULT_BORDER_WIDTH; + layout->border_height = DEFAULT_BORDER_HEIGHT; layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name); layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name); layout->tileset_primary_label = "gTileset_General"; @@ -1074,7 +1076,11 @@ bool Project::loadMapBorder(Map *map) { void Project::setNewMapBorder(Map *map) { Blockdata *blockdata = new Blockdata; - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + if (map->getBorderWidth() != DEFAULT_BORDER_WIDTH || map->getBorderHeight() != DEFAULT_BORDER_HEIGHT) { + for (int i = 0; i < map->getBorderWidth() * map->getBorderHeight(); i++) { + blockdata->addBlock(0); + } + } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { blockdata->addBlock(qint16(0x0014)); blockdata->addBlock(qint16(0x0015)); blockdata->addBlock(qint16(0x001C)); diff --git a/src/ui/bordermetatilespixmapitem.cpp b/src/ui/bordermetatilespixmapitem.cpp index f5f4d2c4..ad31a7ca 100644 --- a/src/ui/bordermetatilespixmapitem.cpp +++ b/src/ui/bordermetatilespixmapitem.cpp @@ -8,10 +8,12 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) QPointF pos = event->pos(); int x = static_cast<int>(pos.x()) / 16; int y = static_cast<int>(pos.y()) / 16; + int width = map->getBorderWidth(); + int height = map->getBorderHeight(); - for (int i = 0; i < selectionDimensions.x() && (i + x) < map->getBorderWidth(); i++) { - for (int j = 0; j < selectionDimensions.y() && (j + y) < map->getBorderHeight(); j++) { - int blockIndex = (j + y) * map->getBorderWidth() + (i + x); + for (int i = 0; i < selectionDimensions.x() && (i + x) < width; i++) { + for (int j = 0; j < selectionDimensions.y() && (j + y) < height; j++) { + int blockIndex = (j + y) * width + (i + x); uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i); (*map->layout->border->blocks)[blockIndex].tile = tile; } @@ -22,15 +24,17 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) } void BorderMetatilesPixmapItem::draw() { - QImage image(16 * map->getBorderWidth(), 16 * map->getBorderHeight(), QImage::Format_RGBA8888); + int width = map->getBorderWidth(); + int height = map->getBorderHeight(); + QImage image(16 * width, 16 * height, QImage::Format_RGBA8888); QPainter painter(&image); QVector<Block> *blocks = map->layout->border->blocks; - for (int i = 0; i < map->getBorderWidth(); i++) { - for (int j = 0; j < map->getBorderHeight(); j++) { + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { int x = i * 16; int y = j * 16; - int index = j * map->getBorderWidth() + i; + int index = j * width + i; QImage metatile_image = getMetatileImage(blocks->value(index).tile, map->layout->tileset_primary, map->layout->tileset_secondary); QPoint metatile_origin = QPoint(x, y); painter.drawImage(metatile_origin, metatile_image); diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 8323278a..833d35a0 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -62,11 +62,15 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) { ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_secondary_label); ui->spinBox_NewMap_Width->setDisabled(true); ui->spinBox_NewMap_Height->setDisabled(true); + ui->spinBox_NewMap_BorderWidth->setDisabled(true); + ui->spinBox_NewMap_BorderHeight->setDisabled(true); ui->comboBox_NewMap_Primary_Tileset->setDisabled(true); ui->comboBox_NewMap_Secondary_Tileset->setDisabled(true); } else { ui->spinBox_NewMap_Width->setValue(20); ui->spinBox_NewMap_Height->setValue(20); + ui->spinBox_NewMap_BorderWidth->setValue(DEFAULT_BORDER_WIDTH); + ui->spinBox_NewMap_BorderHeight->setValue(DEFAULT_BORDER_HEIGHT); } ui->comboBox_NewMap_Type->addItems(*project->mapTypes); @@ -108,6 +112,17 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) { ui->label_NewMap_Floor_Number->setVisible(true); break; } + if (projectConfig.getUseCustomBorderSize()) { + ui->spinBox_NewMap_BorderWidth->setVisible(true); + ui->spinBox_NewMap_BorderHeight->setVisible(true); + ui->label_NewMap_BorderWidth->setVisible(true); + ui->label_NewMap_BorderHeight->setVisible(true); + } else { + ui->spinBox_NewMap_BorderWidth->setVisible(false); + ui->spinBox_NewMap_BorderHeight->setVisible(false); + ui->label_NewMap_BorderWidth->setVisible(false); + ui->label_NewMap_BorderHeight->setVisible(false); + } } void NewMapPopup::on_lineEdit_NewMap_Name_textChanged(const QString &text) { @@ -154,8 +169,13 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { layout->name = QString("%1_Layout").arg(newMap->name); layout->width = QString::number(this->ui->spinBox_NewMap_Width->value()); layout->height = QString::number(this->ui->spinBox_NewMap_Height->value()); - layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); - layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); + if (projectConfig.getUseCustomBorderSize()) { + layout->border_width = QString::number(this->ui->spinBox_NewMap_BorderWidth->value()); + layout->border_height = QString::number(this->ui->spinBox_NewMap_BorderHeight->value()); + } else { + layout->border_width = QString::number(DEFAULT_BORDER_WIDTH); + layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT); + } layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText(); layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText(); layout->border_path = QString("data/layouts/%1/border.bin").arg(newMapName); From ffddc35b607f4f7dbb8e95b5bd9dcc5defa96d86 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sun, 15 Mar 2020 03:03:12 -0400 Subject: [PATCH 10/33] Parse pokefirered metatile behaviors/layer types --- src/project.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index 55db6cd3..e9677e37 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1477,16 +1477,35 @@ void Project::loadTilesetMetatiles(Tileset* tileset) { if (attrs_file.open(QIODevice::ReadOnly)) { QByteArray data = attrs_file.readAll(); int num_metatiles = tileset->metatiles->count(); - int num_metatileAttrs = data.length() / 2; - if (num_metatiles != num_metatileAttrs) { - logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name)); - if (num_metatileAttrs > num_metatiles) - num_metatileAttrs = num_metatiles; - } - for (int i = 0; i < num_metatileAttrs; i++) { - 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; + + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + int num_metatileAttrs = data.length() / 4; + if (num_metatiles != num_metatileAttrs) { + logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name)); + if (num_metatileAttrs > num_metatiles) + num_metatileAttrs = num_metatiles; + } + 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)->layerType = (value & 0x60000000) >> 29; + } + } else { + int num_metatileAttrs = data.length() / 2; + if (num_metatiles != num_metatileAttrs) { + logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name)); + if (num_metatileAttrs > num_metatiles) + num_metatileAttrs = num_metatiles; + } + for (int i = 0; i < num_metatileAttrs; i++) { + 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; + } } } else { logError(QString("Could not open tileset metatile attributes file '%1'").arg(tileset->metatile_attrs_path)); From 3fa77609c684f92ac1a279a98da361a5569e3fae Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Mon, 16 Mar 2020 03:57:39 -0400 Subject: [PATCH 11/33] Remove hard-coded new map constants --- include/project.h | 1 + src/project.cpp | 13 ++++++------- src/ui/newmappopup.cpp | 10 +++------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/project.h b/include/project.h index 4948b7e0..1c01b07a 100644 --- a/include/project.h +++ b/include/project.h @@ -126,6 +126,7 @@ public: void saveTilesetTilesImage(Tileset*); void saveTilesetPalettes(Tileset*, bool); + QString defaultSong; QStringList getSongNames(); QStringList getVisibilities(); QMap<QString, QStringList> getTilesetLabels(); diff --git a/src/project.cpp b/src/project.cpp index e9677e37..d48616b7 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -412,21 +412,19 @@ QString Project::readMapLocation(QString map_name) { void Project::setNewMapHeader(Map* map, int mapIndex) { map->layoutId = QString("%1").arg(mapIndex); - map->location = "MAPSEC_LITTLEROOT_TOWN"; + map->location = mapSectionValueToName.value(0); map->requiresFlash = "FALSE"; - map->weather = "WEATHER_SUNNY"; - map->type = "MAP_TYPE_TOWN"; + map->weather = weatherNames->at(0); + map->type = mapTypes->at(0); + map->song = defaultSong; if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { - map->song = "MUS_DAN02"; map->show_location = "TRUE"; } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald) { - map->song = "MUS_DAN02"; map->allowBiking = "1"; map->allowEscapeRope = "0"; map->allowRunning = "1"; map->show_location = "1"; } else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { - map->song = "MUS_MASARA"; map->allowBiking = "1"; map->allowEscapeRope = "0"; map->allowRunning = "1"; @@ -434,7 +432,7 @@ void Project::setNewMapHeader(Map* map, int mapIndex) { map->floorNumber = 0; } - map->battle_scene = "MAP_BATTLE_SCENE_NORMAL"; + map->battle_scene = mapBattleScenes->at(0); } bool Project::loadMapLayout(Map* map) { @@ -2083,6 +2081,7 @@ QStringList Project::getSongNames() { songDefinePrefixes << "SE_" << "MUS_"; QMap<QString, int> songDefines = parser.readCDefines("include/constants/songs.h", songDefinePrefixes); QStringList names = songDefines.keys(); + this->defaultSong = names.at(0); return names; } diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 833d35a0..18767135 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -150,15 +150,11 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->name = newMapName; newMap->type = this->ui->comboBox_NewMap_Type->currentText(); newMap->location = this->ui->comboBox_NewMap_Location->currentText(); - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { - newMap->song = "MUS_MASARA"; - } else { - newMap->song = "MUS_DAN02"; - } + newMap->song = this->project->defaultSong; newMap->requiresFlash = "0"; - newMap->weather = "WEATHER_SUNNY"; + newMap->weather = this->project->weatherNames->at(0); newMap->show_location = "1"; - newMap->battle_scene = "MAP_BATTLE_SCENE_NORMAL"; + newMap->battle_scene = this->project->mapBattleScenes->at(0); if (this->existingLayout) { layout = this->project->mapLayouts.value(this->layoutId); From bf72ecede9d7d773499873b59f6274eb88fcddda Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Mon, 16 Mar 2020 16:31:08 -0400 Subject: [PATCH 12/33] Parse remaining pokefirered metatile attributes, allow editing/saving them --- forms/tileseteditor.ui | 132 ++++++++++++++++++++++++------------- include/core/metatile.h | 4 +- include/ui/tileseteditor.h | 4 ++ src/core/map.cpp | 1 - src/core/metatile.cpp | 4 ++ src/mainwindow.cpp | 2 + src/project.cpp | 31 +++++++-- src/ui/tileseteditor.cpp | 48 ++++++++++++++ 8 files changed, 173 insertions(+), 53 deletions(-) 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 @@ <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> 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<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(); 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<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); 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<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"; 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 <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); } From f15d7102fc7ca74ada6d729eae54910838473018 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Mon, 16 Mar 2020 16:34:08 -0400 Subject: [PATCH 13/33] Remove dummied logInfo --- src/project.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/project.cpp b/src/project.cpp index 85640f2b..98e5daab 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1507,7 +1507,6 @@ void Project::loadTilesetMetatiles(Tileset* tileset) { 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)); From 2a3b222e3e053a05636f1926e60638bd13600ee2 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Tue, 17 Mar 2020 00:29:54 -0400 Subject: [PATCH 14/33] Locate tileset folders with _[0-9]* --- src/project.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.cpp b/src/project.cpp index 98e5daab..c9822afa 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1346,7 +1346,7 @@ void Project::loadTilesetAssets(Tileset* tileset) { if (tileset->name.isNull()) { return; } - QRegularExpression re("([a-z])([A-Z])"); + QRegularExpression re("([a-z])([A-Z0-9])"); QString tilesetName = tileset->name; QString dir_path = root + "/data/tilesets/" + category + "/" + tilesetName.replace("gTileset_", "").replace(re, "\\1_\\2").toLower(); From 083874ce9e56f91f0f698514a7bcc492313a4900 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Wed, 18 Mar 2020 03:12:43 -0400 Subject: [PATCH 15/33] Minor fixes --- src/core/metatileparser.cpp | 2 ++ src/mainwindow.cpp | 2 ++ src/project.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core/metatileparser.cpp b/src/core/metatileparser.cpp index da7de6b1..d1b936ff 100644 --- a/src/core/metatileparser.cpp +++ b/src/core/metatileparser.cpp @@ -84,6 +84,8 @@ QList<Metatile*> *MetatileParser::parse(QString filepath, bool *error, bool prim (static_cast<unsigned char>(in.at(attrOffset + 1)) << 8); metatile->behavior = value & 0xFF; metatile->layerType = (value & 0xF000) >> 12; + metatile->encounterType = 0; + metatile->terrainType = 0; metatile->tiles = tiles; metatiles->append(metatile); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c5130f2e..436a1702 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -164,6 +164,7 @@ void MainWindow::setProjectSpecificUIVisibility() ui->label_AllowBiking->setVisible(false); ui->label_AllowEscapeRope->setVisible(false); ui->label_FloorNumber->setVisible(false); + ui->actionRegion_Map_Editor->setVisible(true); break; case BaseGameVersion::pokeemerald: ui->checkBox_AllowRunning->setVisible(true); @@ -174,6 +175,7 @@ void MainWindow::setProjectSpecificUIVisibility() ui->label_AllowBiking->setVisible(true); ui->label_AllowEscapeRope->setVisible(true); ui->label_FloorNumber->setVisible(false); + ui->actionRegion_Map_Editor->setVisible(true); break; case BaseGameVersion::pokefirered: ui->checkBox_AllowRunning->setVisible(true); diff --git a/src/project.cpp b/src/project.cpp index c9822afa..00f6a894 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -533,7 +533,7 @@ bool Project::readMapLayouts() { layout->border_width = QString::number(bwidth); int bheight = layoutObj["border_height"].toInt(); if (bheight <= 0) { - logWarn(QString("Invalid layout 'border_height value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT)); + logWarn(QString("Invalid layout 'border_height' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT)); bheight = DEFAULT_BORDER_HEIGHT; } layout->border_height = QString::number(bheight); @@ -1221,7 +1221,9 @@ void Project::saveMap(Map *map) { mapObj["allow_escaping"] = map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE"; mapObj["allow_running"] = map->allowRunning.toInt() > 0 || map->allowRunning == "TRUE"; mapObj["show_map_name"] = map->show_location.toInt() > 0 || map->show_location == "TRUE"; - mapObj["floor_number"] = map->floorNumber; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + mapObj["floor_number"] = map->floorNumber; + } mapObj["battle_scene"] = map->battle_scene; // Connections From d365ebb66418e77ccb6e8f582f059b4734aa9caa Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 20 Mar 2020 03:09:48 -0400 Subject: [PATCH 16/33] Support reading/saving pokefirered heal locations --- include/core/heallocation.h | 8 ++- src/core/event.cpp | 8 ++- src/core/heallocation.cpp | 28 ++++++-- src/project.cpp | 129 +++++++++++++++++++++++++++--------- 4 files changed, 134 insertions(+), 39 deletions(-) diff --git a/include/core/heallocation.h b/include/core/heallocation.h index 15790dff..8867b100 100644 --- a/include/core/heallocation.h +++ b/include/core/heallocation.h @@ -9,14 +9,18 @@ class HealLocation { public: HealLocation()=default; - HealLocation(QString, int, uint16_t, uint16_t); + HealLocation(QString, QString, int, uint16_t, uint16_t); + HealLocation(QString, QString, int, uint16_t, uint16_t, QString, uint16_t); friend QDebug operator<<(QDebug debug, const HealLocation &hl); public: - QString name; + QString idName; + QString mapName; int index; uint16_t x; uint16_t y; + QString respawnMap; + uint16_t respawnNPC; static HealLocation fromEvent(Event*); }; diff --git a/src/core/event.cpp b/src/core/event.cpp index a13ed790..4d08012d 100644 --- a/src/core/event.cpp +++ b/src/core/event.cpp @@ -87,10 +87,16 @@ Event* Event::createNewWarpEvent(QString map_name) Event* Event::createNewHealLocationEvent(QString map_name) { Event *event = new Event; + QString mapConstant = QString(Map::mapConstantFromName(map_name)).remove(0,4); event->put("event_group_type", "heal_event_group"); event->put("event_type", EventType::HealLocation); - event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4)); + event->put("loc_name", mapConstant); + event->put("id_name", map_name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper()); event->put("elevation", 3); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + event->put("respawn_map", mapConstant); + event->put("respawn_npc", 1); + } return event; } diff --git a/src/core/heallocation.cpp b/src/core/heallocation.cpp index ba739831..ae4c1e91 100644 --- a/src/core/heallocation.cpp +++ b/src/core/heallocation.cpp @@ -1,17 +1,33 @@ #include "heallocation.h" +#include "config.h" -HealLocation::HealLocation(QString map, int i, uint16_t x, uint16_t y) +HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y) { - this->name = map; + this->idName = id; + this->mapName = map; this->index = i; this->x = x; this->y = y; + this->respawnMap = ""; + this->respawnNPC = 0; +} + +HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y, QString respawnMap, uint16_t respawnNPC) +{ + this->idName = id; + this->mapName = map; + this->index = i; + this->x = x; + this->y = y; + this->respawnMap = respawnMap; + this->respawnNPC = respawnNPC; } HealLocation HealLocation::fromEvent(Event *event) { HealLocation hl; - hl.name = event->get("loc_name"); + hl.idName = event->get("id_name"); + hl.mapName = event->get("loc_name"); try { hl.index = event->get("index").toInt(); } @@ -20,11 +36,15 @@ HealLocation HealLocation::fromEvent(Event *event) } hl.x = event->getU16("x"); hl.y = event->getU16("y"); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + hl.respawnNPC = event->getU16("respawn_npc"); + hl.respawnMap = event->get("respawn_map"); + } return hl; } QDebug operator<<(QDebug debug, const HealLocation &hl) { - debug << "HealLocation_" + hl.name << "(" << hl.x << ',' << hl.y << ")"; + debug << "HealLocation_" + hl.mapName << "(" << hl.x << ',' << hl.y << ")"; return debug; } diff --git a/src/project.cpp b/src/project.cpp index 00f6a894..4b67f068 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -259,17 +259,22 @@ bool Project::loadMapData(Map* map) { HealLocation loc = *it; //if TRUE map is flyable / has healing location - if (loc.name == QString(mapNamesToMapConstants->value(map->name)).remove(0,4)) { + if (loc.mapName == QString(mapNamesToMapConstants->value(map->name)).remove(0,4)) { Event *heal = new Event; heal->put("map_name", map->name); heal->put("x", loc.x); heal->put("y", loc.y); - heal->put("loc_name", loc.name); + heal->put("loc_name", loc.mapName); + heal->put("id_name", loc.idName); heal->put("index", loc.index); heal->put("elevation", 3); // TODO: change this? heal->put("destination_map_name", mapConstantsToMapNames->value(map->name)); heal->put("event_group_type", "heal_event_group"); heal->put("event_type", EventType::HealLocation); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + heal->put("respawn_map", loc.respawnMap); + heal->put("respawn_npc", loc.respawnNPC); + } map->events["heal_event_group"].append(heal); } @@ -781,9 +786,19 @@ void Project::saveMapConstantsHeader() { // saves heal location coords in root + /src/data/heal_locations.h // and indexes as defines in root + /include/constants/heal_locations.h void Project::saveHealLocationStruct(Map *map) { - QString data_text = QString("%1%2struct HealLocation sHealLocations[] =\n{\n") + QString constantPrefix, arrayName; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + constantPrefix = "SPAWN_"; + arrayName = "sSpawnPoints"; + } else { + constantPrefix = "HEAL_LOCATION_"; + arrayName = "sHealLocations"; + } + + QString data_text = QString("%1%2struct HealLocation %3[] =\n{\n") .arg(dataQualifiers.value("heal_locations").isStatic ? "static " : "") - .arg(dataQualifiers.value("heal_locations").isConst ? "const " : ""); + .arg(dataQualifiers.value("heal_locations").isConst ? "const " : "") + .arg(arrayName); QString constants_text = QString("#ifndef GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); constants_text += QString("#define GUARD_CONSTANTS_HEAL_LOCATIONS_H\n\n"); @@ -794,7 +809,7 @@ void Project::saveHealLocationStruct(Map *map) { // set flyableMapsDupes and flyableMapsUnique for (auto it = flyableMaps.begin(); it != flyableMaps.end(); it++) { HealLocation loc = *it; - QString xname = loc.name; + QString xname = loc.idName; if (flyableMapsUnique.contains(xname)) { flyableMapsDupes[xname] = 1; } @@ -810,33 +825,58 @@ void Project::saveHealLocationStruct(Map *map) { } int i = 1; - for (auto map_in : flyableMaps) { - data_text += QString(" {MAP_GROUP(%1), MAP_NUM(%1), %2, %3},\n") - .arg(map_in.name) + // add numbered suffix for duplicate constants + if (flyableMapsDupes.keys().contains(map_in.idName)) { + map_in.idName += QString("_%1").arg(flyableMapsDupes[map_in.idName]); + flyableMapsDupes[map_in.idName]++; + } + + // Save first array (heal location coords), only data array in RSE + data_text += QString(" [%1%2 - 1] = {MAP_GROUP(%3), MAP_NUM(%3), %4, %5},\n") + .arg(constantPrefix) + .arg(map_in.idName) + .arg(map_in.mapName) .arg(map_in.x) .arg(map_in.y); - QString ending = QString(""); - - // must add _1 / _2 for maps that have duplicates - if (flyableMapsDupes.keys().contains(map_in.name)) { - // map contains multiple heal locations - ending += QString("_%1").arg(flyableMapsDupes[map_in.name]); - flyableMapsDupes[map_in.name]++; - } + // Save constants if (map_in.index != 0) { - constants_text += QString("#define HEAL_LOCATION_%1 %2\n") - .arg(map_in.name + ending) + constants_text += QString("#define %1%2 %3\n") + .arg(constantPrefix) + .arg(map_in.idName) .arg(map_in.index); - } - else { - constants_text += QString("#define HEAL_LOCATION_%1 %2\n") - .arg(map_in.name + ending) + } else { + constants_text += QString("#define %1%2 %3\n") + .arg(constantPrefix) + .arg(map_in.idName) .arg(i); } i++; } + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + // Save second array (map where player respawns for each heal location) + data_text += QString("};\n\n%1%2u16 sWhiteoutRespawnHealCenterMapIdxs[][2] =\n{\n") + .arg(dataQualifiers.value("heal_locations").isStatic ? "static " : "") + .arg(dataQualifiers.value("heal_locations").isConst ? "const " : ""); + for (auto map_in : flyableMaps) { + data_text += QString(" [%1%2 - 1] = {MAP_GROUP(%3), MAP_NUM(%3)},\n") + .arg(constantPrefix) + .arg(map_in.idName) + .arg(map_in.respawnMap); + } + + // Save third array (object id of NPC player speaks to upon respawning for each heal location) + data_text += QString("};\n\n%1%2u8 sWhiteoutRespawnHealerNpcIds[] =\n{\n") + .arg(dataQualifiers.value("heal_locations").isStatic ? "static " : "") + .arg(dataQualifiers.value("heal_locations").isConst ? "const " : ""); + for (auto map_in : flyableMaps) { + data_text += QString(" [%1%2 - 1] = %3,\n") + .arg(constantPrefix) + .arg(map_in.idName) + .arg(map_in.respawnNPC); + } + } data_text += QString("};\n"); constants_text += QString("\n#endif // GUARD_CONSTANTS_HEAL_LOCATIONS_H\n"); @@ -1928,21 +1968,46 @@ bool Project::readRegionMapSections() { bool Project::readHealLocations() { dataQualifiers.clear(); flyableMaps.clear(); - QString filename = "src/data/heal_locations.h"; QString text = parser.readTextFile(root + "/" + filename); text.replace(QRegularExpression("//.*?(\r\n?|\n)|/\\*.*?\\*/", QRegularExpression::DotMatchesEverythingOption), ""); - dataQualifiers.insert("heal_locations", getDataQualifiers(text, "sHealLocations")); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + dataQualifiers.insert("heal_locations", getDataQualifiers(text, "sSpawnPoints")); + QRegularExpression spawnRegex("SPAWN_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = \\{MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\2)[\\s\\)]+,\\s*(?<x>[0-9A-Fa-fx]+),\\s*(?<y>[0-9A-Fa-fx]+)"); + QRegularExpression respawnMapRegex("SPAWN_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = \\{MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\2)[\\s\\)]+}"); + QRegularExpression respawnNPCRegex("SPAWN_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = (?<npc>[0-9]+)"); + QRegularExpressionMatchIterator spawns = spawnRegex.globalMatch(text); + QRegularExpressionMatchIterator respawnMaps = respawnMapRegex.globalMatch(text); + QRegularExpressionMatchIterator respawnNPCs = respawnNPCRegex.globalMatch(text); - QRegularExpression regex("MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\1)[\\s\\)]+,\\s*(?<x>[0-9A-Fa-fx]+),\\s*(?<y>[0-9A-Fa-fx]+)"); - QRegularExpressionMatchIterator iter = regex.globalMatch(text); - for (int i = 1; iter.hasNext(); i++) { - QRegularExpressionMatch match = iter.next(); - QString mapName = match.captured("map"); - unsigned x = match.captured("x").toUShort(); - unsigned y = match.captured("y").toUShort(); - flyableMaps.append(HealLocation(mapName, i, x, y)); + // This would be better if idName was used to look up data from the other two arrays + // As it is, element total and order needs to be the same in the 3 arrays to work. This should always be true though + for (int i = 1; spawns.hasNext(); i++) { + QRegularExpressionMatch spawn = spawns.next(); + QRegularExpressionMatch respawnMap = respawnMaps.next(); + QRegularExpressionMatch respawnNPC = respawnNPCs.next(); + QString idName = spawn.captured("id"); + QString mapName = spawn.captured("map"); + QString respawnMapName = respawnMap.captured("map"); + unsigned x = spawn.captured("x").toUShort(); + unsigned y = spawn.captured("y").toUShort(); + unsigned npc = respawnNPC.captured("npc").toUShort(); + flyableMaps.append(HealLocation(idName, mapName, i, x, y, respawnMapName, npc)); + } + } else { + dataQualifiers.insert("heal_locations", getDataQualifiers(text, "sHealLocations")); + + QRegularExpression regex("HEAL_LOCATION_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = \\{MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\2)[\\s\\)]+,\\s*(?<x>[0-9A-Fa-fx]+),\\s*(?<y>[0-9A-Fa-fx]+)"); + QRegularExpressionMatchIterator iter = regex.globalMatch(text); + for (int i = 1; iter.hasNext(); i++) { + QRegularExpressionMatch match = iter.next(); + QString idName = match.captured("id"); + QString mapName = match.captured("map"); + unsigned x = match.captured("x").toUShort(); + unsigned y = match.captured("y").toUShort(); + flyableMaps.append(HealLocation(idName, mapName, i, x, y)); + } } return true; } From 20b112de525d1760694cb52444dac438663ea22e Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 20 Mar 2020 13:41:40 -0400 Subject: [PATCH 17/33] Support editing heal location respawns --- src/core/event.cpp | 5 ++--- src/core/heallocation.cpp | 3 ++- src/mainwindow.cpp | 27 ++++++++++++++++++++++----- src/project.cpp | 2 +- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/core/event.cpp b/src/core/event.cpp index 4d08012d..8a0c4541 100644 --- a/src/core/event.cpp +++ b/src/core/event.cpp @@ -87,14 +87,13 @@ Event* Event::createNewWarpEvent(QString map_name) Event* Event::createNewHealLocationEvent(QString map_name) { Event *event = new Event; - QString mapConstant = QString(Map::mapConstantFromName(map_name)).remove(0,4); event->put("event_group_type", "heal_event_group"); event->put("event_type", EventType::HealLocation); - event->put("loc_name", mapConstant); + event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4)); event->put("id_name", map_name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper()); event->put("elevation", 3); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { - event->put("respawn_map", mapConstant); + event->put("respawn_map", map_name); event->put("respawn_npc", 1); } return event; diff --git a/src/core/heallocation.cpp b/src/core/heallocation.cpp index ae4c1e91..3653443d 100644 --- a/src/core/heallocation.cpp +++ b/src/core/heallocation.cpp @@ -1,5 +1,6 @@ #include "heallocation.h" #include "config.h" +#include "map.h" HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y) { @@ -38,7 +39,7 @@ HealLocation HealLocation::fromEvent(Event *event) hl.y = event->getU16("y"); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { hl.respawnNPC = event->getU16("respawn_npc"); - hl.respawnMap = event->get("respawn_map"); + hl.respawnMap = Map::mapConstantFromName(event->get("respawn_map")).remove(0,4); } return hl; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 436a1702..235ad23e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1429,6 +1429,8 @@ void MainWindow::updateSelectedObjects() { field_labels["weather"] = "Weather"; field_labels["flag"] = "Flag"; field_labels["secret_base_id"] = "Secret Base Id"; + field_labels["respawn_map"] = "Respawn Map"; + field_labels["respawn_npc"] = "Respawn NPC"; QStringList fields; @@ -1491,8 +1493,13 @@ void MainWindow::updateSelectedObjects() { // Hide elevation so users don't get impression that editing it is meaningful. frame->ui->spinBox_z->setVisible(false); frame->ui->label_z->setVisible(false); + fields << "respawn_map"; + fields << "respawn_npc"; } + // Some keys shouldn't use a combobox + QStringList spinKeys = {"quantity", "respawn_npc"}; + QStringList checkKeys = {"underfoot", "in_connection"}; for (QString key : fields) { QString value = item->event->get(key); QWidget *widget = new QWidget(frame); @@ -1504,10 +1511,9 @@ void MainWindow::updateSelectedObjects() { NoScrollComboBox *combo; QCheckBox *check; - // Some keys shouldn't use a combobox. This isn't very scalable - if (key == "quantity") { + if (spinKeys.contains(key)) { spin = new NoScrollSpinBox(widget); - } else if (key == "underfoot" || key == "in_connection") { + } else if (checkKeys.contains(key)) { check = new QCheckBox(widget); } else { combo = new NoScrollComboBox(widget); @@ -1552,6 +1558,7 @@ void MainWindow::updateSelectedObjects() { combo->addItems(*editor->project->itemNames); } else if (key == "quantity") { spin->setToolTip("The number of items received when the hidden item is picked up."); + // Min 1 not needed. 0 is treated as a valid quantity and works as expected in-game. spin->setMaximum(127); } else if (key == "underfoot") { check->setToolTip("If checked, hidden item can only be picked up using the Itemfinder"); @@ -1624,12 +1631,22 @@ void MainWindow::updateSelectedObjects() { combo->setMinimumContentsLength(4); } else if (key == "in_connection") { check->setToolTip("Check if object is positioned in the connection to another map."); + } else if (key == "respawn_map") { + if (!editor->project->mapNames->contains(value)) { + combo->addItem(value); + } + combo->addItems(*editor->project->mapNames); + combo->setToolTip("The map where the player will respawn after whiteout."); + } else if (key == "respawn_npc") { + spin->setToolTip("event_object ID of the NPC the player interacts with upon respawning after whiteout."); + spin->setMinimum(1); + spin->setMaximum(126); } else { combo->addItem(value); } // Keys using spin boxes - if (key == "quantity") { + if (spinKeys.contains(key)) { spin->setValue(value.toInt()); fl->addRow(new QLabel(field_labels[key], widget), spin); @@ -1640,7 +1657,7 @@ void MainWindow::updateSelectedObjects() { item->event->put(key, value); }); // Keys using check boxes - } else if (key == "underfoot" || key == "in_connection") { + } else if (checkKeys.contains(key)) { check->setChecked(value.toInt()); fl->addRow(new QLabel(field_labels[key], widget), check); diff --git a/src/project.cpp b/src/project.cpp index 4b67f068..674850c8 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -272,7 +272,7 @@ bool Project::loadMapData(Map* map) { heal->put("event_group_type", "heal_event_group"); heal->put("event_type", EventType::HealLocation); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { - heal->put("respawn_map", loc.respawnMap); + heal->put("respawn_map", mapConstantsToMapNames->value(QString("MAP_" + loc.respawnMap))); heal->put("respawn_npc", loc.respawnNPC); } map->events["heal_event_group"].append(heal); From 8137abd656031fef9cd7ddeac11bec1c14629f6c Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 20 Mar 2020 13:52:30 -0400 Subject: [PATCH 18/33] Disable respawn editing for pokeemerald/pokeruby --- src/mainwindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 235ad23e..cafb6252 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1493,8 +1493,10 @@ void MainWindow::updateSelectedObjects() { // Hide elevation so users don't get impression that editing it is meaningful. frame->ui->spinBox_z->setVisible(false); frame->ui->label_z->setVisible(false); - fields << "respawn_map"; - fields << "respawn_npc"; + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + fields << "respawn_map"; + fields << "respawn_npc"; + } } // Some keys shouldn't use a combobox From 9924a36950ddf4d254ec28a53576d85af0674da6 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Tue, 24 Mar 2020 00:33:10 -0400 Subject: [PATCH 19/33] Set floor minimum --- forms/mainwindow.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index c65e6cde..d92666d5 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2168,6 +2168,9 @@ <property name="toolTip"> <string><html><head/><body><p>Floor number to be used for maps with elevators.</p></body></html></string> </property> + <property name="minimum"> + <number>-128</number> + </property> <property name="maximum"> <number>127</number> </property> From 8e26f4c3f5397e8ae5f78a01464d3b7fae9246f0 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Thu, 26 Mar 2020 14:59:33 -0400 Subject: [PATCH 20/33] Enable readInitialFacingDirections for pokefirered --- src/project.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index 674850c8..4f6c554d 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -2061,9 +2061,6 @@ bool Project::readMovementTypes() { } bool Project::readInitialFacingDirections() { - // 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"; facingDirections = parser.readNamedIndexCArray(filename, "gInitialMovementTypeFacingDirections"); if (facingDirections.isEmpty()) { From 0fb483b5d3194bb6496030bb7b49b2612eb7085e Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Thu, 26 Mar 2020 15:11:42 -0400 Subject: [PATCH 21/33] Editable trainer type, minor fixes --- src/mainwindow.cpp | 26 ++++++++++++++------------ src/ui/tileseteditor.cpp | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index cafb6252..f0ff4b9e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1364,6 +1364,7 @@ void MainWindow::updateSelectedObjects() { QList<EventPropertiesFrame *> frames; + bool pokefirered = projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered; for (DraggablePixmapItem *item : *events) { EventPropertiesFrame *frame = new EventPropertiesFrame; // frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -1458,7 +1459,7 @@ void MainWindow::updateSelectedObjects() { fields << "event_flag"; fields << "trainer_type"; fields << "sight_radius_tree_id"; - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + if (pokefirered) { fields << "in_connection"; } } @@ -1481,7 +1482,7 @@ void MainWindow::updateSelectedObjects() { else if (event_type == EventType::HiddenItem) { fields << "item"; fields << "flag"; - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + if (pokefirered) { fields << "quantity"; fields << "underfoot"; } @@ -1493,7 +1494,7 @@ void MainWindow::updateSelectedObjects() { // Hide elevation so users don't get impression that editing it is meaningful. frame->ui->spinBox_z->setVisible(false); frame->ui->label_z->setVisible(false); - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + if (pokefirered) { fields << "respawn_map"; fields << "respawn_npc"; } @@ -1521,10 +1522,8 @@ void MainWindow::updateSelectedObjects() { combo = new NoScrollComboBox(widget); combo->setEditable(true); } - // trainer_type has custom values, so it has special signal logic. if (key == "trainer_type") { - combo->setEditable(false); combo->addItem("NONE", "0"); combo->addItem("NORMAL", "1"); combo->addItem("SEE ALL DIRECTIONS", "3"); @@ -1536,6 +1535,8 @@ void MainWindow::updateSelectedObjects() { int index = combo->findData(value); if (index != -1) { combo->setCurrentIndex(index); + } else { + combo->setCurrentText(value); } fl->addRow(new QLabel(field_labels[key], widget), combo); @@ -1640,7 +1641,8 @@ void MainWindow::updateSelectedObjects() { combo->addItems(*editor->project->mapNames); combo->setToolTip("The map where the player will respawn after whiteout."); } else if (key == "respawn_npc") { - spin->setToolTip("event_object ID of the NPC the player interacts with upon respawning after whiteout."); + spin->setToolTip("event_object ID of the NPC the player interacts with\n" + "upon respawning after whiteout."); spin->setMinimum(1); spin->setMaximum(126); } else { @@ -1669,12 +1671,12 @@ void MainWindow::updateSelectedObjects() { connect(check, &QCheckBox::stateChanged, [item, key](int state) { switch (state) { - case Qt::Checked: - item->event->put(key, true); - break; - case Qt::Unchecked: - item->event->put(key, false); - break; + case Qt::Checked: + item->event->put(key, true); + break; + case Qt::Unchecked: + item->event->put(key, false); + break; } }); // Keys using combo boxes diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 1c36e60d..17cdcaf7 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -66,8 +66,8 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString 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_encounterType->addItem("Land", 1); + this->ui->comboBox_encounterType->addItem("Water", 2); this->ui->comboBox_terrainType->setVisible(true); this->ui->label_terrainType->setVisible(true); this->ui->comboBox_terrainType->addItem("Normal", 0); From 1a2e7623efc388b0d71622a56d9ade207cccba95 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 27 Mar 2020 09:22:54 -0400 Subject: [PATCH 22/33] Prefer oamtable name for sprite dimensions --- src/project.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index 4f6c554d..5b79b29f 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -2267,16 +2267,19 @@ void Project::loadEventPixmaps(QList<Event*> objects) { QImage spritesheet(root + "/" + path); if (!spritesheet.isNull()) { // Infer the sprite dimensions from the OAM labels. - int spriteWidth = spritesheet.width(); - int spriteHeight = spritesheet.height(); + int spriteWidth, spriteHeight; QRegularExpression re("\\S+_(\\d+)x(\\d+)"); QRegularExpressionMatch dimensionMatch = re.match(dimensions_label); - if (dimensionMatch.hasMatch()) { - QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label); - if (oamTablesMatch.hasMatch()) { - spriteWidth = dimensionMatch.captured(1).toInt(); - spriteHeight = dimensionMatch.captured(2).toInt(); - } + QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label); + if (oamTablesMatch.hasMatch()) { + spriteWidth = oamTablesMatch.captured(1).toInt(); + spriteHeight = oamTablesMatch.captured(2).toInt(); + } else if (dimensionMatch.hasMatch()) { + spriteWidth = dimensionMatch.captured(1).toInt(); + spriteHeight = dimensionMatch.captured(2).toInt(); + } else { + spriteWidth = spritesheet.width(); + spriteHeight = spritesheet.height(); } object->setPixmapFromSpritesheet(spritesheet, spriteWidth, spriteHeight, object->frame, object->hFlip); } From 76a8c0dc441e4024bb2861a28f091503cd9058a7 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 27 Mar 2020 10:51:57 -0400 Subject: [PATCH 23/33] Read trainer type constants --- include/project.h | 2 ++ src/mainwindow.cpp | 29 ++++++----------------------- src/project.cpp | 15 ++++++++++++++- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/project.h b/include/project.h index 1c01b07a..7cd77693 100644 --- a/include/project.h +++ b/include/project.h @@ -49,6 +49,7 @@ public: QStringList *coordEventWeatherNames = nullptr; QStringList *secretBaseIds = nullptr; QStringList *bgEventFacingDirections = nullptr; + QStringList *trainerTypes = nullptr; QMap<QString, int> metatileBehaviorMap; QMap<int, QString> metatileBehaviorMapInverse; QMap<QString, QString> facingDirections; @@ -143,6 +144,7 @@ public: bool readCoordEventWeatherNames(); bool readSecretBaseIds(); bool readBgEventFacingDirections(); + bool readTrainerTypes(); bool readMetatileBehaviors(); bool readHealLocations(); bool readMiscellaneousConstants(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f0ff4b9e..595f4606 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -646,6 +646,7 @@ bool MainWindow::loadDataStructures() { && project->readMapBattleScenes() && project->readWeatherNames() && project->readBgEventFacingDirections() + && project->readTrainerTypes() && project->readMetatileBehaviors() && project->readTilesetProperties() && project->readHealLocations() @@ -1522,29 +1523,6 @@ void MainWindow::updateSelectedObjects() { combo = new NoScrollComboBox(widget); combo->setEditable(true); } - // trainer_type has custom values, so it has special signal logic. - if (key == "trainer_type") { - combo->addItem("NONE", "0"); - combo->addItem("NORMAL", "1"); - combo->addItem("SEE ALL DIRECTIONS", "3"); - combo->setToolTip("The trainer type of this object event.\n" - "If it is not a trainer, use NONE. SEE ALL DIRECTIONS\n" - "should only be used with a sight radius of 1."); - combo->setMinimumContentsLength(10); - - int index = combo->findData(value); - if (index != -1) { - combo->setCurrentIndex(index); - } else { - combo->setCurrentText(value); - } - - fl->addRow(new QLabel(field_labels[key], widget), combo); - widget->setLayout(fl); - frame->layout()->addWidget(widget); - item->bindToUserData(combo, key); - continue; - } if (key == "destination_map_name") { if (!editor->project->mapNames->contains(value)) { @@ -1628,6 +1606,11 @@ void MainWindow::updateSelectedObjects() { combo->setMinimumContentsLength(4); } else if (key == "script_label") { combo->setToolTip("The script which is executed with this event."); + } else if (key == "trainer_type") { + combo->addItems(*editor->project->trainerTypes); + combo->setToolTip("The trainer type of this object event.\n" + "If it is not a trainer, use NONE. SEE ALL DIRECTIONS\n" + "should only be used with a sight radius of 1."); } else if (key == "sight_radius_tree_id") { combo->setToolTip("The maximum sight range of a trainer,\n" "OR the unique id of the berry tree."); diff --git a/src/project.cpp b/src/project.cpp index 5b79b29f..f0862c5a 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -44,6 +44,7 @@ Project::Project() coordEventWeatherNames = new QStringList; secretBaseIds = new QStringList; bgEventFacingDirections = new QStringList; + trainerTypes = new QStringList; map_cache = new QMap<QString, Map*>; mapConstantsToMapNames = new QMap<QString, QString>; mapNamesToMapConstants = new QMap<QString, QString>; @@ -2142,6 +2143,18 @@ bool Project::readBgEventFacingDirections() { return true; } +bool Project::readTrainerTypes() { + trainerTypes->clear(); + QStringList prefixes = (QStringList() << "TRAINER_TYPE_"); + QString filename = "include/constants/trainer_types.h"; + parser.readCDefinesSorted(filename, prefixes, trainerTypes); + if (trainerTypes->isEmpty()) { + logError(QString("Failed to read trainer type constants from %1").arg(filename)); + return false; + } + return true; +} + bool Project::readMetatileBehaviors() { this->metatileBehaviorMap.clear(); this->metatileBehaviorMapInverse.clear(); @@ -2150,7 +2163,7 @@ bool Project::readMetatileBehaviors() { QString filename = "include/constants/metatile_behaviors.h"; this->metatileBehaviorMap = parser.readCDefines(filename, prefixes); if (this->metatileBehaviorMap.isEmpty()) { - logError(QString("Failed to metatile behaviors from %1.").arg(filename)); + logError(QString("Failed to read metatile behaviors from %1.").arg(filename)); return false; } From c28730e834ff71ccbf5d89eb0dd94e848904489f Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Tue, 31 Mar 2020 12:41:15 -0400 Subject: [PATCH 24/33] Fix crash with open windows when switching projects --- include/mainwindow.h | 1 + src/mainwindow.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/mainwindow.h b/include/mainwindow.h index 9113e227..27fe541c 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -216,6 +216,7 @@ private: bool openRecentProject(); void updateTilesetEditor(); QString getEventGroupFromTabWidget(QWidget *tab); + void closeSupplementaryWindows(); bool isProjectOpen(); }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 595f4606..a0fcd6d0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -293,6 +293,7 @@ bool MainWindow::openProject(QString dir) { projectConfig.setProjectDir(dir); projectConfig.load(); + this->closeSupplementaryWindows(); this->setProjectSpecificUIVisibility(); bool already_open = isProjectOpen() && (editor->project->root == dir); @@ -2410,6 +2411,17 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() { } } +void MainWindow::closeSupplementaryWindows() { + if (this->tilesetEditor) + delete this->tilesetEditor; + if (this->regionMapEditor) + delete this->regionMapEditor; + if (this->mapImageExporter) + delete this->mapImageExporter; + if (this->newmapprompt) + delete this->newmapprompt; +} + void MainWindow::closeEvent(QCloseEvent *event) { if (projectHasUnsavedChanges || editor->map->hasUnsavedChanges()) { QMessageBox::StandardButton result = QMessageBox::question( From e4a41cf201b46dceda6a6a6ff0114ee92816a5a9 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Fri, 3 Apr 2020 16:29:40 -0400 Subject: [PATCH 25/33] Align border blocks --- include/core/map.h | 4 ++-- src/core/map.cpp | 12 ++++++------ src/editor.cpp | 20 ++++++++++++-------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/core/map.h b/include/core/map.h index 2873844f..425ce639 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -17,9 +17,9 @@ #define DEFAULT_BORDER_WIDTH 2 #define DEFAULT_BORDER_HEIGHT 2 -// Number of metatiles to draw out from edge of map. Could allow modification of this in the future. +// Number of border blocks to draw out from edge of map. Could allow modification of this in the future. // porymap will reflect changes to it, but the value is hard-coded in the projects at the moment -#define BORDER_DISTANCE 6 +#define NUM_BORDER_BLOCKS 3 class Map : public QObject { diff --git a/src/core/map.cpp b/src/core/map.cpp index 667c151a..2320152a 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -263,23 +263,23 @@ QPixmap Map::renderConnection(MapConnection connection, MapLayout * fromLayout) int x, y, w, h; if (connection.direction == "up") { x = 0; - y = getHeight() - BORDER_DISTANCE; + y = getHeight() - (getBorderHeight() * NUM_BORDER_BLOCKS); w = getWidth(); - h = BORDER_DISTANCE; + h = getBorderHeight() * NUM_BORDER_BLOCKS; } else if (connection.direction == "down") { x = 0; y = 0; w = getWidth(); - h = BORDER_DISTANCE; + h = getBorderHeight() * NUM_BORDER_BLOCKS; } else if (connection.direction == "left") { - x = getWidth() - BORDER_DISTANCE; + x = getWidth() - (getBorderWidth() * NUM_BORDER_BLOCKS); y = 0; - w = BORDER_DISTANCE; + w = getBorderWidth() * NUM_BORDER_BLOCKS; h = getHeight(); } else if (connection.direction == "right") { x = 0; y = 0; - w = BORDER_DISTANCE; + w = getBorderWidth() * NUM_BORDER_BLOCKS; h = getHeight(); } else { // this should not happen diff --git a/src/editor.cpp b/src/editor.cpp index ff0b6d8b..d87ad832 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1118,6 +1118,8 @@ void Editor::displayMetatileSelector() { } void Editor::displayMapMetatiles() { + int borderHorzDist = map->getBorderWidth() * NUM_BORDER_BLOCKS * 16; + int borderVertDist = map->getBorderHeight() * NUM_BORDER_BLOCKS * 16; map_item = new MapPixmapItem(map, this->metatile_selector_item, this->settings); connect(map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,MapPixmapItem*)), this, SLOT(mouseEvent_map(QGraphicsSceneMouseEvent*,MapPixmapItem*))); @@ -1133,13 +1135,11 @@ void Editor::displayMapMetatiles() { map_item->draw(true); scene->addItem(map_item); - int tw = 16; - int th = 16; scene->setSceneRect( - -BORDER_DISTANCE * tw, - -BORDER_DISTANCE * th, - map_item->pixmap().width() + (BORDER_DISTANCE * 2) * tw, - map_item->pixmap().height() + (BORDER_DISTANCE * 2) * th + -borderHorzDist, + -borderVertDist, + map_item->pixmap().width() + borderHorzDist * 2, + map_item->pixmap().height() + borderVertDist * 2 ); } @@ -1334,9 +1334,13 @@ void Editor::displayMapBorder() { } borderItems.clear(); + int borderWidth = map->getBorderWidth(); + int borderHeight = map->getBorderHeight(); + int borderHorzDist = borderWidth * NUM_BORDER_BLOCKS; + int borderVertDist = borderHeight * NUM_BORDER_BLOCKS; QPixmap pixmap = map->renderBorder(); - for (int y = -BORDER_DISTANCE; y < map->getHeight() + BORDER_DISTANCE; y += map->getBorderHeight()) - for (int x = -BORDER_DISTANCE; x < map->getWidth() + BORDER_DISTANCE; x += map->getBorderWidth()) { + for (int y = -borderVertDist; y < map->getHeight() + borderVertDist; y += borderHeight) + for (int x = -borderHorzDist; x < map->getWidth() + borderHorzDist; x += borderWidth) { QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); item->setX(x * 16); item->setY(y * 16); From d4cf3edfc7c7613b8199fe445637c95f40188540 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sat, 4 Apr 2020 14:14:16 -0400 Subject: [PATCH 26/33] Use default tileset for invalid tilesets, fix segfault caused by loadMapLayout --- src/project.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index f0862c5a..fa6cf593 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -453,9 +453,14 @@ bool Project::loadMapLayout(Map* map) { return false; } - return loadMapTilesets(map) - && loadBlockdata(map) - && loadMapBorder(map); + // Force these to run even if one fails + bool loadedTilesets = loadMapTilesets(map); + bool loadedBlockdata = loadBlockdata(map); + bool loadedBorder = loadMapBorder(map); + + return loadedTilesets + && loadedBlockdata + && loadedBorder; } bool Project::readMapLayouts() { @@ -625,8 +630,8 @@ void Project::setNewMapLayout(Map* map) { layout->border_height = DEFAULT_BORDER_HEIGHT; layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name); layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name); - layout->tileset_primary_label = "gTileset_General"; - layout->tileset_secondary_label = "gTileset_Petalburg"; + layout->tileset_primary_label = tilesetLabels["primary"].at(0); + layout->tileset_secondary_label = tilesetLabels["secondary"].at(0); map->layout = layout; map->layoutId = layout->id; @@ -1045,14 +1050,24 @@ bool Project::loadMapTilesets(Map* map) { map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label); if (!map->layout->tileset_primary) { - logError(QString("Map layout %1 has invalid primary tileset '%2'").arg(map->layout->id).arg(map->layout->tileset_primary_label)); - return false; + logWarn(QString("Map layout %1 has invalid primary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_primary_label).arg(tilesetLabels["primary"].at(0))); + map->layout->tileset_primary_label = tilesetLabels["primary"].at(0); + map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label); + if (!map->layout->tileset_primary) { + logError(QString("Failed to set default primary tileset.")); + return false; + } } map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label); if (!map->layout->tileset_secondary) { - logError(QString("Map layout %1 has invalid secondary tileset '%2'").arg(map->layout->id).arg(map->layout->tileset_secondary_label)); - return false; + logWarn(QString("Map layout %1 has invalid secondary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_secondary_label).arg(tilesetLabels["secondary"].at(0))); + map->layout->tileset_secondary_label = tilesetLabels["secondary"].at(0); + map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label); + if (!map->layout->tileset_secondary) { + logError(QString("Failed to set default secondary tileset.")); + return false; + } } return true; } From d5908c00453259f6fae194a9de532bb240056b1f Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sun, 5 Apr 2020 00:03:36 -0400 Subject: [PATCH 27/33] Draw border up to players view --- include/core/map.h | 4 ++-- include/editor.h | 1 + src/core/map.cpp | 12 ++++++------ src/editor.cpp | 25 +++++++++++++++++-------- src/ui/mapimageexporter.cpp | 2 +- 5 files changed, 27 insertions(+), 17 deletions(-) diff --git a/include/core/map.h b/include/core/map.h index 425ce639..32eb6e70 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -17,9 +17,9 @@ #define DEFAULT_BORDER_WIDTH 2 #define DEFAULT_BORDER_HEIGHT 2 -// Number of border blocks to draw out from edge of map. Could allow modification of this in the future. +// Number of metatiles to draw out from edge of map. Could allow modification of this in the future. // porymap will reflect changes to it, but the value is hard-coded in the projects at the moment -#define NUM_BORDER_BLOCKS 3 +#define BORDER_DISTANCE 7 class Map : public QObject { diff --git a/include/editor.h b/include/editor.h index 45706daf..a0ab0e7e 100644 --- a/include/editor.h +++ b/include/editor.h @@ -147,6 +147,7 @@ private: void updateMirroredConnectionMap(MapConnection*, QString); void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false); void updateEncounterFields(EncounterFields newFields); + int getBorderDrawDistance(int dimension); Event* createNewObjectEvent(); Event* createNewWarpEvent(); Event* createNewHealLocationEvent(); diff --git a/src/core/map.cpp b/src/core/map.cpp index 2320152a..667c151a 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -263,23 +263,23 @@ QPixmap Map::renderConnection(MapConnection connection, MapLayout * fromLayout) int x, y, w, h; if (connection.direction == "up") { x = 0; - y = getHeight() - (getBorderHeight() * NUM_BORDER_BLOCKS); + y = getHeight() - BORDER_DISTANCE; w = getWidth(); - h = getBorderHeight() * NUM_BORDER_BLOCKS; + h = BORDER_DISTANCE; } else if (connection.direction == "down") { x = 0; y = 0; w = getWidth(); - h = getBorderHeight() * NUM_BORDER_BLOCKS; + h = BORDER_DISTANCE; } else if (connection.direction == "left") { - x = getWidth() - (getBorderWidth() * NUM_BORDER_BLOCKS); + x = getWidth() - BORDER_DISTANCE; y = 0; - w = getBorderWidth() * NUM_BORDER_BLOCKS; + w = BORDER_DISTANCE; h = getHeight(); } else if (connection.direction == "right") { x = 0; y = 0; - w = getBorderWidth() * NUM_BORDER_BLOCKS; + w = BORDER_DISTANCE; h = getHeight(); } else { // this should not happen diff --git a/src/editor.cpp b/src/editor.cpp index d87ad832..0cf52cdd 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1118,8 +1118,6 @@ void Editor::displayMetatileSelector() { } void Editor::displayMapMetatiles() { - int borderHorzDist = map->getBorderWidth() * NUM_BORDER_BLOCKS * 16; - int borderVertDist = map->getBorderHeight() * NUM_BORDER_BLOCKS * 16; map_item = new MapPixmapItem(map, this->metatile_selector_item, this->settings); connect(map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,MapPixmapItem*)), this, SLOT(mouseEvent_map(QGraphicsSceneMouseEvent*,MapPixmapItem*))); @@ -1136,10 +1134,10 @@ void Editor::displayMapMetatiles() { scene->addItem(map_item); scene->setSceneRect( - -borderHorzDist, - -borderVertDist, - map_item->pixmap().width() + borderHorzDist * 2, - map_item->pixmap().height() + borderVertDist * 2 + -BORDER_DISTANCE * 16, + -BORDER_DISTANCE * 16, + map_item->pixmap().width() + (BORDER_DISTANCE * 16) * 2, + map_item->pixmap().height() + (BORDER_DISTANCE * 16) * 2 ); } @@ -1336,8 +1334,8 @@ void Editor::displayMapBorder() { int borderWidth = map->getBorderWidth(); int borderHeight = map->getBorderHeight(); - int borderHorzDist = borderWidth * NUM_BORDER_BLOCKS; - int borderVertDist = borderHeight * NUM_BORDER_BLOCKS; + int borderHorzDist = getBorderDrawDistance(borderWidth); + int borderVertDist = getBorderDrawDistance(borderHeight); QPixmap pixmap = map->renderBorder(); for (int y = -borderVertDist; y < map->getHeight() + borderVertDist; y += borderHeight) for (int x = -borderHorzDist; x < map->getWidth() + borderHorzDist; x += borderWidth) { @@ -1350,6 +1348,17 @@ void Editor::displayMapBorder() { } } +int Editor::getBorderDrawDistance(int dimension) { + // Draw sufficient border blocks to fill the player's view (BORDER_DISTANCE) + if (dimension >= BORDER_DISTANCE) { + return dimension; + } else if (dimension) { + return dimension * (BORDER_DISTANCE / dimension + (BORDER_DISTANCE % dimension ? 1 : 0)); + } else { + return BORDER_DISTANCE; + } +} + void Editor::displayMapGrid() { for (QGraphicsLineItem* item : gridLines) { if (item && item->scene()) { diff --git a/src/ui/mapimageexporter.cpp b/src/ui/mapimageexporter.cpp index af7e180c..2cdd45e7 100644 --- a/src/ui/mapimageexporter.cpp +++ b/src/ui/mapimageexporter.cpp @@ -70,7 +70,7 @@ void MapImageExporter::updatePreview() { int borderHeight = 0, borderWidth = 0; bool forceDrawBorder = showUpConnections || showDownConnections || showLeftConnections || showRightConnections; if (showBorder || forceDrawBorder) { - borderHeight = 32 * 3, borderWidth = 32 * 3; + borderHeight = BORDER_DISTANCE * 16, borderWidth = BORDER_DISTANCE * 16; QPixmap newPreview = QPixmap(map->pixmap.width() + borderWidth * 2, map->pixmap.height() + borderHeight * 2); QPainter borderPainter(&newPreview); for (auto borderItem : editor->borderItems) { From c9b6f87e06946c4b1d90088f4accb12f37fe34a7 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sun, 5 Apr 2020 11:56:13 -0400 Subject: [PATCH 28/33] Apply undo/redo to border drawing --- src/editor.cpp | 4 ++++ src/ui/bordermetatilespixmapitem.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/editor.cpp b/src/editor.cpp index 0cf52cdd..aac160a3 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -48,6 +48,8 @@ void Editor::undo() { map->undo(); map_item->draw(); collision_item->draw(); + selected_border_metatiles_item->draw(); + displayMapBorder(); } } @@ -56,6 +58,8 @@ void Editor::redo() { map->redo(); map_item->draw(); collision_item->draw(); + selected_border_metatiles_item->draw(); + displayMapBorder(); } } diff --git a/src/ui/bordermetatilespixmapitem.cpp b/src/ui/bordermetatilespixmapitem.cpp index ad31a7ca..e7a024b7 100644 --- a/src/ui/bordermetatilespixmapitem.cpp +++ b/src/ui/bordermetatilespixmapitem.cpp @@ -42,5 +42,6 @@ void BorderMetatilesPixmapItem::draw() { } painter.end(); + map->commit(); this->setPixmap(QPixmap::fromImage(image)); } From 129db88453bab91840cce27a8db8f9de1016af0d Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Mon, 6 Apr 2020 12:09:45 -0400 Subject: [PATCH 29/33] Minor cleanup --- include/core/heallocation.h | 3 +-- src/core/heallocation.cpp | 11 ----------- src/editor.cpp | 10 ++++++---- src/mainwindow.cpp | 2 +- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/include/core/heallocation.h b/include/core/heallocation.h index 8867b100..fd00a22b 100644 --- a/include/core/heallocation.h +++ b/include/core/heallocation.h @@ -9,8 +9,7 @@ class HealLocation { public: HealLocation()=default; - HealLocation(QString, QString, int, uint16_t, uint16_t); - HealLocation(QString, QString, int, uint16_t, uint16_t, QString, uint16_t); + HealLocation(QString, QString, int, uint16_t, uint16_t, QString = "", uint16_t = 0); friend QDebug operator<<(QDebug debug, const HealLocation &hl); public: diff --git a/src/core/heallocation.cpp b/src/core/heallocation.cpp index 3653443d..e88d99e6 100644 --- a/src/core/heallocation.cpp +++ b/src/core/heallocation.cpp @@ -2,17 +2,6 @@ #include "config.h" #include "map.h" -HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y) -{ - this->idName = id; - this->mapName = map; - this->index = i; - this->x = x; - this->y = y; - this->respawnMap = ""; - this->respawnNPC = 0; -} - HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y, QString respawnMap, uint16_t respawnNPC) { this->idName = id; diff --git a/src/editor.cpp b/src/editor.cpp index aac160a3..2f8e38da 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1137,11 +1137,13 @@ void Editor::displayMapMetatiles() { map_item->draw(true); scene->addItem(map_item); + int tw = 16; + int th = 16; scene->setSceneRect( - -BORDER_DISTANCE * 16, - -BORDER_DISTANCE * 16, - map_item->pixmap().width() + (BORDER_DISTANCE * 16) * 2, - map_item->pixmap().height() + (BORDER_DISTANCE * 16) * 2 + -BORDER_DISTANCE * tw, + -BORDER_DISTANCE * th, + map_item->pixmap().width() + BORDER_DISTANCE * 2 * tw, + map_item->pixmap().height() + BORDER_DISTANCE * 2 * th ); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a0fcd6d0..e0e64da0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2203,7 +2203,7 @@ void MainWindow::on_pushButton_ChangeDimensions_clicked() QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); form.addRow(&buttonBox); - connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &bwidthSpinBox, &bheightSpinBox, &errorLabel](){ + connect(&buttonBox, &QDialogButtonBox::accepted, [&dialog, &widthSpinBox, &heightSpinBox, &errorLabel](){ // Ensure width and height are an acceptable size. // The maximum number of metatiles in a map is the following: // max = (width + 15) * (height + 14) From 5f16ae7dd06bd93ecf5287dee9350feec6740943 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sun, 19 Apr 2020 10:16:49 -0400 Subject: [PATCH 30/33] Use value() instead of at() for defaults --- src/project.cpp | 22 ++++++++++++---------- src/ui/newmappopup.cpp | 4 ++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index eaf12d96..0c7c9651 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -425,8 +425,8 @@ void Project::setNewMapHeader(Map* map, int mapIndex) { map->layoutId = QString("%1").arg(mapIndex); map->location = mapSectionValueToName.value(0); map->requiresFlash = "FALSE"; - map->weather = weatherNames->at(0); - map->type = mapTypes->at(0); + map->weather = weatherNames->value(0, "WEATHER_NONE"); + map->type = mapTypes->value(0, "MAP_TYPE_NONE"); map->song = defaultSong; if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { map->show_location = "TRUE"; @@ -443,7 +443,7 @@ void Project::setNewMapHeader(Map* map, int mapIndex) { map->floorNumber = 0; } - map->battle_scene = mapBattleScenes->at(0); + map->battle_scene = mapBattleScenes->value(0, "MAP_BATTLE_SCENE_NORMAL"); } bool Project::loadMapLayout(Map* map) { @@ -637,8 +637,8 @@ void Project::setNewMapLayout(Map* map) { layout->border_height = DEFAULT_BORDER_HEIGHT; layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name); layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name); - layout->tileset_primary_label = tilesetLabels["primary"].at(0); - layout->tileset_secondary_label = tilesetLabels["secondary"].at(0); + layout->tileset_primary_label = tilesetLabels["primary"].value(0, "gTileset_General"); + layout->tileset_secondary_label = tilesetLabels["secondary"].value(0, projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg"); map->layout = layout; map->layoutId = layout->id; @@ -1060,8 +1060,9 @@ bool Project::loadMapTilesets(Map* map) { map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label); if (!map->layout->tileset_primary) { - logWarn(QString("Map layout %1 has invalid primary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_primary_label).arg(tilesetLabels["primary"].at(0))); - map->layout->tileset_primary_label = tilesetLabels["primary"].at(0); + QString defaultTileset = tilesetLabels["primary"].value(0, "gTileset_General"); + logWarn(QString("Map layout %1 has invalid primary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_primary_label).arg(defaultTileset)); + map->layout->tileset_primary_label = defaultTileset; map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label); if (!map->layout->tileset_primary) { logError(QString("Failed to set default primary tileset.")); @@ -1071,8 +1072,9 @@ bool Project::loadMapTilesets(Map* map) { map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label); if (!map->layout->tileset_secondary) { - logWarn(QString("Map layout %1 has invalid secondary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_secondary_label).arg(tilesetLabels["secondary"].at(0))); - map->layout->tileset_secondary_label = tilesetLabels["secondary"].at(0); + QString defaultTileset = tilesetLabels["secondary"].value(0, projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg"); + logWarn(QString("Map layout %1 has invalid secondary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_secondary_label).arg(defaultTileset)); + map->layout->tileset_secondary_label = defaultTileset; map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label); if (!map->layout->tileset_secondary) { logError(QString("Failed to set default secondary tileset.")); @@ -2210,7 +2212,7 @@ QStringList Project::getSongNames() { songDefinePrefixes << "SE_" << "MUS_"; QMap<QString, int> songDefines = parser.readCDefines("include/constants/songs.h", songDefinePrefixes); QStringList names = songDefines.keys(); - this->defaultSong = names.at(0); + this->defaultSong = names.value(0, "MUS_DUMMY"); return names; } diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 18767135..f35af69e 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -152,9 +152,9 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->location = this->ui->comboBox_NewMap_Location->currentText(); newMap->song = this->project->defaultSong; newMap->requiresFlash = "0"; - newMap->weather = this->project->weatherNames->at(0); + newMap->weather = this->project->weatherNames->value(0, "WEATHER_NONE"); newMap->show_location = "1"; - newMap->battle_scene = this->project->mapBattleScenes->at(0); + newMap->battle_scene = this->project->mapBattleScenes->value(0, "MAP_BATTLE_SCENE_NORMAL"); if (this->existingLayout) { layout = this->project->mapLayouts.value(this->layoutId); From f2ae83b33e0aca957ae7ff83f427b3457af2f321 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sun, 19 Apr 2020 18:11:45 -0400 Subject: [PATCH 31/33] Use metatile attributes path from header --- src/project.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index 0c7c9651..ca6b46c5 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1099,8 +1099,12 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) { tileset->tiles_label = values->value(3); tileset->palettes_label = values->value(4); tileset->metatiles_label = values->value(5); - tileset->metatile_attrs_label = values->value(6); - tileset->callback_label = values->value(7); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + tileset->metatile_attrs_label = values->value(7); + } else { + tileset->metatile_attrs_label = values->value(6); + tileset->callback_label = values->value(7); + } loadTilesetAssets(tileset); From d91107a07d58d9d0261975c171d30e3d3ec663fe Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Sun, 19 Apr 2020 18:23:37 -0400 Subject: [PATCH 32/33] Read callback_label for FRLG --- src/project.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/project.cpp b/src/project.cpp index ca6b46c5..fcdb1dcb 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1100,6 +1100,7 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) { tileset->palettes_label = values->value(4); tileset->metatiles_label = values->value(5); if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + tileset->callback_label = values->value(6); tileset->metatile_attrs_label = values->value(7); } else { tileset->metatile_attrs_label = values->value(6); From 0c92dc05da9136946d0742e659b4ef019a369630 Mon Sep 17 00:00:00 2001 From: GriffinR <griffin.g.richards@gmail.com> Date: Mon, 20 Apr 2020 13:28:56 -0400 Subject: [PATCH 33/33] Save metatile attributes label in new order for FRLG --- src/core/tileset.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core/tileset.cpp b/src/core/tileset.cpp index 9b305e15..450458b8 100644 --- a/src/core/tileset.cpp +++ b/src/core/tileset.cpp @@ -2,6 +2,7 @@ #include "metatile.h" #include "project.h" #include "log.h" +#include "config.h" #include <QPainter> #include <QImage> @@ -115,8 +116,13 @@ bool Tileset::appendToHeaders(QString headerFile, QString friendlyName){ dataString.append(QString("\t.4byte gTilesetTiles_%1\n").arg(friendlyName)); dataString.append(QString("\t.4byte gTilesetPalettes_%1\n").arg(friendlyName)); dataString.append(QString("\t.4byte gMetatiles_%1\n").arg(friendlyName)); - dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName)); - dataString.append("\t.4byte NULL\n"); + if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + dataString.append("\t.4byte NULL\n"); + dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName)); + } else { + dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName)); + dataString.append("\t.4byte NULL\n"); + } file.write(dataString.toUtf8()); file.flush(); file.close();