Read/write MAPSEC values using the region map json

This commit is contained in:
GriffinR 2024-11-04 21:49:49 -05:00
parent 7d89031273
commit d448765d63
18 changed files with 143 additions and 241 deletions

View file

@ -59,7 +59,6 @@ The filepath that Porymap expects for each file can be overridden on the ``Files
include/constants/event_object_movement.h, yes, no, ``constants_obj_event_movement``,
include/constants/event_objects.h, yes, no, ``constants_obj_events``,
include/constants/event_bg.h, yes, no, ``constants_event_bg``,
include/constants/region_map_sections.h, yes, no, ``constants_region_map_sections``,
include/constants/metatile_labels.h, yes, yes, ``constants_metatile_labels``,
include/constants/metatile_behaviors.h, yes, no, ``constants_metatile_behaviors``,
include/constants/species.h, yes, no, ``constants_metatile_behaviors``, for the Wild Pokémon tab
@ -122,7 +121,6 @@ In addition to these files, there are some specific symbol and macro names that
``define_map_empty``, ``UNDEFINED``, macro name after prefix for empty maps
``define_map_section_prefix``, ``MAPSEC_``, expected prefix for location macro names
``define_map_section_empty``, ``NONE``, macro name after prefix for empty region map sections
``define_map_section_count``, ``COUNT``, macro name after prefix for total number of region map sections
``define_species_prefix``, ``SPECIES_``, expected prefix for species macro names
``regex_behaviors``, ``\bMB_``, regex to find metatile behavior macro names
``regex_obj_event_gfx``, ``\bOBJ_EVENT_GFX_``, regex to find Object Event graphics ID macro names

View file

@ -213,7 +213,6 @@ enum ProjectIdentifier {
define_map_empty,
define_map_section_prefix,
define_map_section_empty,
define_map_section_count,
define_species_prefix,
regex_behaviors,
regex_obj_event_gfx,
@ -269,7 +268,6 @@ enum ProjectFilePath {
constants_obj_event_movement,
constants_obj_events,
constants_event_bg,
constants_region_map_sections,
constants_metatile_labels,
constants_metatile_behaviors,
constants_species,

View file

@ -57,8 +57,8 @@ public:
bool loadLayout(poryjson::Json);
bool loadEntries();
void setEntries(tsl::ordered_map<QString, MapSectionEntry> *entries) { this->region_map_entries = entries; }
void setEntries(tsl::ordered_map<QString, MapSectionEntry> entries) { *(this->region_map_entries) = entries; }
void setEntries(QMap<QString, MapSectionEntry> *entries) { this->region_map_entries = entries; }
void setEntries(const QMap<QString, MapSectionEntry> &entries) { *(this->region_map_entries) = entries; }
void clearEntries() { this->region_map_entries->clear(); }
MapSectionEntry getEntry(QString section);
void setEntry(QString section, MapSectionEntry entry);
@ -114,8 +114,6 @@ public:
void setLayer(QString layer) { this->current_layer = layer; }
QString getLayer() { return this->current_layer; }
QString fixCase(QString);
int padLeft() { return this->offset_left; }
int padTop() { return this->offset_top; }
int padRight() { return this->tilemap_width - this->layout_width - this->offset_left; }
@ -149,14 +147,12 @@ public:
const QString section_prefix;
const QString default_map_section;
const QString count_map_section;
signals:
void mapNeedsDisplaying();
private:
// TODO: defaults needed?
tsl::ordered_map<QString, MapSectionEntry> *region_map_entries = nullptr;
QMap<QString, MapSectionEntry> *region_map_entries = nullptr;
QString alias = "";

View file

@ -153,7 +153,7 @@ private:
/// ClearEntries
class ClearEntries : public QUndoCommand {
public:
ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry>, QUndoCommand *parent = nullptr);
ClearEntries(RegionMap *map, QMap<QString, MapSectionEntry>, QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
@ -163,7 +163,7 @@ public:
private:
RegionMap *map;
tsl::ordered_map<QString, MapSectionEntry> entries;
QMap<QString, MapSectionEntry> entries;
};
#endif // REGIONMAPEDITCOMMANDS_H

View file

@ -8,7 +8,7 @@
struct WildPokemon {
int minLevel = 5;
int maxLevel = 5;
QString species = "SPECIES_NONE";
QString species = "SPECIES_NONE"; // TODO: Use define_species_prefix
};
struct WildMonInfo {

View file

@ -49,9 +49,6 @@ public:
QMap<QString, QString> layoutIdsToNames;
QMap<QString, Layout*> mapLayouts;
QMap<QString, Layout*> mapLayoutsMaster;
QMap<QString, QString> mapSecToMapHoverName;
QMap<QString, int> mapSectionNameToValue;
QMap<int, QString> mapSectionValueToName;
QMap<QString, EventGraphics*> eventGraphicsMap;
QMap<QString, int> gfxDefines;
QString defaultSong;
@ -68,6 +65,8 @@ public:
QStringList bgEventFacingDirections;
QStringList trainerTypes;
QStringList globalScriptLabels;
QStringList mapSectionIdNames;
QMap<QString, MapSectionEntry> regionMapEntries;
QMap<QString, QMap<QString, uint16_t>> metatileLabelsMap;
QMap<QString, uint16_t> unusedMetatileLabels;
QMap<QString, uint32_t> metatileBehaviorMap;
@ -82,9 +81,7 @@ public:
int pokemonMaxLevel;
int maxEncounterRate;
bool wildEncountersLoaded;
// For files that are read and could contain extra text
QMap<QString, QString> extraFileText;
bool saveEmptyMapsec;
void set_root(QString);
@ -142,7 +139,7 @@ public:
bool readSpeciesIconPaths();
QMap<QString, QString> speciesToIconPath;
int appendMapsec(QString name);
void addNewMapsec(QString name);
bool hasUnsavedChanges();
bool hasUnsavedDataChanges = false;
@ -172,7 +169,7 @@ public:
void saveConfig();
void saveMapLayouts();
void saveMapGroups();
void saveMapSections();
void saveRegionMapSections();
void saveWildMonData();
void saveMapConstantsHeader();
void saveHealLocations(Map*);

View file

@ -132,7 +132,7 @@ public:
public:
void setMap(QString mapName) { this->openMap = mapName; }
QStandardItem *createAreaItem(QString areaName, int areaIndex);
QStandardItem *createAreaItem(QString areaName);
QStandardItem *createMapItem(QString mapName, int areaIndex, int mapIndex);
QStandardItem *insertAreaItem(QString areaName);

View file

@ -57,7 +57,6 @@ private:
tsl::ordered_map<QString, RegionMap *> region_maps;
QString configFilepath;
QString mapSectionFilepath;
poryjson::Json rmConfigJson;
@ -96,7 +95,7 @@ private:
void saveConfig();
bool loadRegionMapEntries();
bool saveRegionMapEntries();
tsl::ordered_map<QString, MapSectionEntry> region_map_entries;
QMap<QString, MapSectionEntry> region_map_entries;
bool buildConfigDialog();
poryjson::Json configRegionMapDialog();

View file

@ -110,7 +110,6 @@ const QMap<ProjectIdentifier, QPair<QString, QString>> ProjectConfig::defaultIde
{ProjectIdentifier::define_map_empty, {"define_map_empty", "UNDEFINED"}},
{ProjectIdentifier::define_map_section_prefix, {"define_map_section_prefix", "MAPSEC_"}},
{ProjectIdentifier::define_map_section_empty, {"define_map_section_empty", "NONE"}},
{ProjectIdentifier::define_map_section_count, {"define_map_section_count", "COUNT"}},
{ProjectIdentifier::define_species_prefix, {"define_species_prefix", "SPECIES_"}},
// Regex
{ProjectIdentifier::regex_behaviors, {"regex_behaviors", "\\bMB_"}},
@ -167,7 +166,6 @@ const QMap<ProjectFilePath, QPair<QString, QString>> ProjectConfig::defaultPaths
{ProjectFilePath::constants_obj_event_movement, { "constants_obj_event_movement", "include/constants/event_object_movement.h"}},
{ProjectFilePath::constants_obj_events, { "constants_obj_events", "include/constants/event_objects.h"}},
{ProjectFilePath::constants_event_bg, { "constants_event_bg", "include/constants/event_bg.h"}},
{ProjectFilePath::constants_region_map_sections, { "constants_region_map_sections", "include/constants/region_map_sections.h"}},
{ProjectFilePath::constants_metatile_labels, { "constants_metatile_labels", "include/constants/metatile_labels.h"}},
{ProjectFilePath::constants_metatile_behaviors, { "constants_metatile_behaviors", "include/constants/metatile_behaviors.h"}},
{ProjectFilePath::constants_species, { "constants_species", "include/constants/species.h"}},

View file

@ -19,8 +19,7 @@ using std::make_shared;
RegionMap::RegionMap(Project *project) :
section_prefix(projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix)),
default_map_section(section_prefix + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_empty)),
count_map_section(section_prefix + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_count))
default_map_section(project->getEmptyMapsecName())
{
this->project = project;
}
@ -157,7 +156,7 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
for (int x = 0; x < this->layout_width; x++) {
int bin_index = x + y * this->layout_width;
uint8_t square_section_id = mapBinData.at(bin_index);
QString square_section_name = project->mapSectionValueToName.value(square_section_id);
QString square_section_name = project->mapSectionIdNames.value(square_section_id, this->default_map_section);
LayoutSquare square;
square.map_section = square_section_name;
@ -401,7 +400,7 @@ void RegionMap::saveLayout() {
for (int m = 0; m < this->layout_height; m++) {
for (int n = 0; n < this->layout_width; n++) {
int i = n + this->layout_width * m;
data.append(this->project->mapSectionNameToValue.value(this->layouts["main"][i].map_section));
data.append(this->project->mapSectionIdNames.indexOf(this->layouts["main"][i].map_section));
}
}
QFile bfile(fullPath(this->layout_path));
@ -760,18 +759,15 @@ bool RegionMap::squareInLayout(int x, int y) {
}
MapSectionEntry RegionMap::getEntry(QString section) {
if (this->region_map_entries->contains(section))
return this->region_map_entries->operator[](section);
else
return MapSectionEntry();
return this->region_map_entries->value(section, MapSectionEntry());
}
void RegionMap::setEntry(QString section, MapSectionEntry entry) {
this->region_map_entries->operator[](section) = entry;
this->region_map_entries->insert(section, entry);
}
void RegionMap::removeEntry(QString section) {
this->region_map_entries->erase(section);
this->region_map_entries->remove(section);
}
QString RegionMap::palPath() {
@ -788,27 +784,6 @@ int RegionMap::getMapSquareIndex(int x, int y) {
return ((index < tilemap.length()) && (index >= 0)) ? index : 0;
}
// For turning a MAPSEC_NAME into a unique identifier sMapName-style variable.
// CAPS_WITH_UNDERSCORE to CamelCase
QString RegionMap::fixCase(QString caps) {
bool big = true;
QString camel;
static const QRegularExpression re_braced("({.*})");
for (auto ch : caps.remove(re_braced).remove(this->section_prefix)) {
if (ch == '_' || ch == ' ') {
big = true;
continue;
}
if (big) {
camel += ch.toUpper();
big = false;
}
else camel += ch.toLower();
}
return camel;
}
QString RegionMap::fullPath(QString local) {
return this->project->root + "/" + local;
}

View file

@ -260,7 +260,7 @@ void ResizeTilemap::undo() {
///
ClearEntries::ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry> entries, QUndoCommand *parent)
ClearEntries::ClearEntries(RegionMap *map, QMap<QString, MapSectionEntry> entries, QUndoCommand *parent)
: QUndoCommand(parent) {
setText("Clear Entries");

View file

@ -1177,7 +1177,7 @@ bool MainWindow::setProjectUI() {
ui->comboBox_Song->clear();
ui->comboBox_Song->addItems(project->songNames);
ui->comboBox_Location->clear();
ui->comboBox_Location->addItems(project->mapSectionValueToName.values());
ui->comboBox_Location->addItems(project->mapSectionIdNames);
ui->comboBox_PrimaryTileset->clear();
ui->comboBox_PrimaryTileset->addItems(project->primaryTilesetLabels);
ui->comboBox_SecondaryTileset->clear();
@ -1546,7 +1546,7 @@ void MainWindow::mapListAddArea() {
connect(&newItemButtonBox, &QDialogButtonBox::accepted, [&](){
const QString newAreaName = newNameDisplay->text();
if (this->editor->project->mapSectionNameToValue.contains(newAreaName)){
if (this->editor->project->mapSectionIdNames.contains(newAreaName)){
errorMessageLabel->setText(QString("An area with the name '%1' already exists").arg(newAreaName));
errorMessageLabel->setVisible(true);
} else {

View file

@ -708,36 +708,45 @@ void Project::saveMapGroups() {
mapGroupsFile.close();
}
void Project::saveMapSections() {
QString filepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::constants_region_map_sections);
QString text = QString("#ifndef GUARD_REGIONMAPSEC_H\n");
text += QString("#define GUARD_REGIONMAPSEC_H\n\n");
int longestLength = 0;
for (QString label : this->mapSectionNameToValue.keys()) {
if (label.size() > longestLength)
longestLength = label.size();
void Project::saveRegionMapSections() {
const QString filepath = QString("%1/%2").arg(this->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
QFile file(filepath);
if (!file.open(QIODevice::WriteOnly)) {
logError(QString("Could not open '%1' for writing").arg(filepath));
return;
}
longestLength += 1;
const QString emptyMapsecName = getEmptyMapsecName();
OrderedJson::array mapSectionArray;
for (const auto &idName : this->mapSectionIdNames) {
// The 'empty' map section (MAPSEC_NONE) isn't normally present in the region map sections data file.
// We append this name to mapSectionIdNames ourselves if it isn't present, in which case we don't want to output data for it here.
if (!this->saveEmptyMapsec && idName == emptyMapsecName)
continue;
// TODO: Maybe print as an enum now that we can?
for (int value : this->mapSectionValueToName.keys()) {
QString line = QString("#define %1 0x%2\n")
.arg(this->mapSectionValueToName[value], -1 * longestLength)
.arg(QString("%1").arg(value, 2, 16, QLatin1Char('0')).toUpper());
text += line;
OrderedJson::object mapSectionObj;
mapSectionObj["id"] = idName;
if (this->regionMapEntries.contains(idName)) {
MapSectionEntry entry = this->regionMapEntries.value(idName);
mapSectionObj["name"] = entry.name;
mapSectionObj["x"] = entry.x;
mapSectionObj["y"] = entry.y;
mapSectionObj["width"] = entry.width;
mapSectionObj["height"] = entry.height;
}
mapSectionArray.append(mapSectionObj);
}
// TODO: We should maybe consider another way to update MAPSEC values in this file, in case we break anything by relocating it to the bottom of the file.
// (or alternatively keep separate strings for text before/after the MAPSEC values)
text += "\n" + this->extraFileText[projectConfig.getFilePath(ProjectFilePath::constants_region_map_sections)] + "\n";
text += QString("#endif // GUARD_REGIONMAPSEC_H\n");
OrderedJson::object object;
object["map_sections"] = mapSectionArray;
ignoreWatchedFileTemporarily(filepath);
saveTextFile(filepath, text);
OrderedJson json(object);
OrderedJsonDoc jsonDoc(&json);
jsonDoc.dump(&file);
file.close();
}
void Project::saveWildMonData() {
@ -1459,7 +1468,7 @@ void Project::updateLayout(Layout *layout) {
void Project::saveAllDataStructures() {
saveMapLayouts();
saveMapGroups();
saveMapSections();
saveRegionMapSections();
saveMapConstantsHeader();
saveWildMonData();
saveConfig();
@ -2242,49 +2251,66 @@ bool Project::readFieldmapMasks() {
}
bool Project::readRegionMapSections() {
this->mapSectionNameToValue.clear();
this->mapSectionValueToName.clear();
this->mapSectionIdNames.clear();
this->regionMapEntries.clear();
this->saveEmptyMapsec = false;
const QString defaultName = getEmptyMapsecName();
const QString requiredPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix);
const QStringList regexList = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix))};
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_region_map_sections);
fileWatcher.addPath(root + "/" + filename);
this->mapSectionNameToValue = parser.readCDefinesByRegex(filename, regexList);
if (this->mapSectionNameToValue.isEmpty()) {
logError(QString("Failed to read region map sections from %1.").arg(filename));
QJsonDocument doc;
const QString filepath = QString("%1/%2").arg(this->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
if (!parser.tryParseJsonFile(&doc, filepath)) {
logError(QString("Failed to read region map sections from '%1'").arg(filepath));
return false;
}
fileWatcher.addPath(filepath);
for (QString defineName : this->mapSectionNameToValue.keys()) {
this->mapSectionValueToName.insert(this->mapSectionNameToValue[defineName], defineName);
QJsonArray mapSections = doc.object()["map_sections"].toArray();
for (const auto &mapSection : mapSections) {
// For each map section, "id" is the only required field. This is the field we use
// to display the location names in various drop-downs.
QJsonObject mapSectionObj = mapSection.toObject();
const QString idName = ParseUtil::jsonToQString(mapSectionObj["id"]);
if (!idName.startsWith(requiredPrefix)) {
logWarn(QString("Ignoring data for map section '%1'. IDs must start with the prefix '%2'").arg(idName).arg(requiredPrefix));
continue;
}
this->mapSectionIdNames.append(idName);
if (idName == defaultName) {
// If the user has data for the 'empty' MAPSEC we need to know to output it later,
// because we will otherwise add a dummy entry for this value.
this->saveEmptyMapsec = true;
}
// Map sections may have additional data indicating their position on the region map.
// If they have this data, we can add them to the region map entry list.
bool hasRegionMapData = true;
static const QSet<QString> regionMapFieldNames = { "name", "x", "y", "width", "height" };
for (auto fieldName : regionMapFieldNames) {
if (!mapSectionObj.contains(fieldName)) {
hasRegionMapData = false;
break;
}
}
if (!hasRegionMapData)
continue;
MapSectionEntry entry;
entry.name = ParseUtil::jsonToQString(mapSectionObj["name"]);
entry.x = ParseUtil::jsonToInt(mapSectionObj["x"]);
entry.y = ParseUtil::jsonToInt(mapSectionObj["y"]);
entry.width = ParseUtil::jsonToInt(mapSectionObj["width"]);
entry.height = ParseUtil::jsonToInt(mapSectionObj["height"]);
entry.valid = true;
this->regionMapEntries[idName] = entry;
}
// extra text
QString extraText;
QString fileText = ParseUtil::readTextFile(root + "/" + filename);
QTextStream stream(&fileText);
QString currentLine;
while (stream.readLineInto(&currentLine)) {
// is this line something that porymap will output again?
if (currentLine.isEmpty()) {
continue;
}
// include guards
// TODO: Assuming guard name is the same across projects (it isn't)
else if (currentLine.contains("GUARD_REGIONMAPSEC_H")) {
continue;
}
// defines captured
// TODO: Regex to consider comments/extra space
else if (currentLine.contains("#define " + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix))) {
continue;
}
// everything else should be kept here
else {
extraText += currentLine + "\n";
}
// Make sure the default name is present in the list.
if (!this->mapSectionIdNames.contains(defaultName)) {
this->mapSectionIdNames.append(defaultName);
}
stream.seek(0);
this->extraFileText[filename] = extraText;
return true;
}
@ -2292,24 +2318,15 @@ QString Project::getEmptyMapsecName() {
return projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_empty);
}
// This function assumes a valid and unique name.
// Will return the new index.
int Project::appendMapsec(QString name) {
const QString emptyMapsecName = getEmptyMapsecName();
int newMapsecValue = mapSectionValueToName.isEmpty() ? 0 : mapSectionValueToName.lastKey();
// If the user has the 'empty' MAPSEC value defined last in the list we'll shift it so that it stays last in the list.
if (this->mapSectionNameToValue.contains(emptyMapsecName) && this->mapSectionNameToValue.value(emptyMapsecName) == newMapsecValue) {
this->mapSectionNameToValue.insert(emptyMapsecName, newMapsecValue + 1);
this->mapSectionValueToName.insert(newMapsecValue + 1, emptyMapsecName);
// This function assumes a valid and unique name
void Project::addNewMapsec(QString name) {
if (!this->mapSectionIdNames.isEmpty() && this->mapSectionIdNames.last() == getEmptyMapsecName()) {
// If the default map section name (MAPSEC_NONE) is last in the list we'll keep it last in the list.
this->mapSectionIdNames.insert(this->mapSectionIdNames.length() - 1, name);
} else {
this->mapSectionIdNames.append(name);
}
// TODO: Update 'define_map_section_count'?
this->mapSectionNameToValue[name] = newMapsecValue;
this->mapSectionValueToName[newMapsecValue] = name;
this->hasUnsavedDataChanges = true;
return newMapsecValue;
}
// Read the constants to preserve any "unused" heal locations when writing the file later

View file

@ -836,7 +836,7 @@ QString MainWindow::getLocation() {
void MainWindow::setLocation(QString location) {
if (!this->ui || !this->editor || !this->editor->project)
return;
if (!this->editor->project->mapSectionNameToValue.contains(location)) {
if (!this->editor->project->mapSectionIdNames.contains(location)) {
logError(QString("Unknown location '%1'").arg(location));
return;
}

View file

@ -282,7 +282,7 @@ QList<QString> ScriptUtility::getSongNames() {
QList<QString> ScriptUtility::getLocationNames() {
if (!window || !window->editor || !window->editor->project)
return QList<QString>();
return window->editor->project->mapSectionNameToValue.keys();
return window->editor->project->mapSectionIdNames;
}
QList<QString> ScriptUtility::getWeatherNames() {

View file

@ -413,13 +413,12 @@ MapAreaModel::MapAreaModel(Project *project, QObject *parent) : MapListModel(par
initialize();
}
QStandardItem *MapAreaModel::createAreaItem(QString mapsecName, int areaIndex) {
QStandardItem *MapAreaModel::createAreaItem(QString mapsecName) {
QStandardItem *area = new QStandardItem;
area->setText(mapsecName);
area->setEditable(false);
area->setData(mapsecName, Qt::UserRole);
area->setData("map_section", MapListUserRoles::TypeRole);
area->setData(areaIndex, MapListUserRoles::GroupRole);
// group->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
this->areaItems.insert(mapsecName, area);
return area;
@ -437,20 +436,14 @@ QStandardItem *MapAreaModel::createMapItem(QString mapName, int, int) {
}
QStandardItem *MapAreaModel::insertAreaItem(QString areaName) {
int newAreaIndex = this->project->appendMapsec(areaName);
QStandardItem *item = createAreaItem(areaName, newAreaIndex);
this->root->insertRow(newAreaIndex, item);
// MAPSEC_NONE may have shifted to accomodate the new item, update it in the list.
const QString emptyMapsecName = Project::getEmptyMapsecName();
if (this->areaItems.contains(emptyMapsecName))
this->areaItems[emptyMapsecName]->setData(this->project->mapSectionNameToValue.value(emptyMapsecName), MapListUserRoles::GroupRole);
this->project->addNewMapsec(areaName);
QStandardItem *item = createAreaItem(areaName);
this->root->appendRow(item);
this->sort(0, Qt::AscendingOrder);
return item;
}
QStandardItem *MapAreaModel::insertMapItem(QString mapName, QString areaName, int groupIndex) {
// int areaIndex = this->project->mapSectionNameToValue[areaName];
QStandardItem *area = this->areaItems[areaName];
if (!area) {
return nullptr;
@ -461,21 +454,18 @@ QStandardItem *MapAreaModel::insertMapItem(QString mapName, QString areaName, in
return map;
}
// Note: Not actually supported in the interface at the moment.
void MapAreaModel::removeFolder(int index) {
this->removeRow(index);
this->project->mapSectionNameToValue.remove(this->project->mapSectionValueToName.take(index));
this->project->mapSectionIdNames.removeAt(index);
}
void MapAreaModel::initialize() {
this->areaItems.clear();
this->mapItems.clear();
this->setSortRole(MapListUserRoles::GroupRole);
// TODO: Ignore 'define_map_section_count' and/or 'define_map_section_empty'?
for (int i : this->project->mapSectionNameToValue) {
QString mapsecName = project->mapSectionValueToName.value(i);
QStandardItem *areaItem = createAreaItem(mapsecName, i);
this->root->appendRow(areaItem);
for (const auto &idName : this->project->mapSectionIdNames) {
this->root->appendRow(createAreaItem(idName));
}
for (int i = 0; i < this->project->groupNames.length(); i++) {
@ -560,9 +550,7 @@ QVariant MapAreaModel::data(const QModelIndex &index, int role) const {
QString type = item->data(MapListUserRoles::TypeRole).toString();
if (type == "map_section") {
return QString("[0x%1] %2")
.arg(QString("%1").arg(item->data(MapListUserRoles::GroupRole).toInt(), 2, 16, QLatin1Char('0')).toUpper())
.arg(item->data(Qt::UserRole).toString());
return item->data(Qt::UserRole).toString();
}
}
@ -603,6 +591,7 @@ QStandardItem *LayoutTreeModel::createMapItem(QString mapName) {
QStandardItem *LayoutTreeModel::insertLayoutItem(QString layoutId) {
QStandardItem *layoutItem = this->createLayoutItem(layoutId);
this->root->appendRow(layoutItem);
this->sort(0, Qt::AscendingOrder);
return layoutItem;
}
@ -644,6 +633,7 @@ void LayoutTreeModel::initialize() {
this->layoutItems[layoutId]->appendRow(map);
}
}
this->sort(0, Qt::AscendingOrder);
}
QStandardItem *LayoutTreeModel::getItem(const QModelIndex &index) const {

View file

@ -34,7 +34,7 @@ void NewMapPopup::initUi() {
ui->comboBox_NewMap_Group->addItems(project->groupNames);
ui->comboBox_NewMap_Song->addItems(project->songNames);
ui->comboBox_NewMap_Type->addItems(project->mapTypes);
ui->comboBox_NewMap_Location->addItems(project->mapSectionNameToValue.keys());
ui->comboBox_NewMap_Location->addItems(project->mapSectionIdNames);
const QSignalBlocker b(ui->comboBox_Layout);
ui->comboBox_Layout->addItems(project->mapLayoutsTable);
@ -186,7 +186,7 @@ void NewMapPopup::setDefaultSettings(Project *project) {
settings.primaryTilesetLabel = project->getDefaultPrimaryTilesetLabel();
settings.secondaryTilesetLabel = project->getDefaultSecondaryTilesetLabel();
settings.type = project->mapTypes.value(0, "0");
settings.location = project->mapSectionNameToValue.keys().value(0, "0");
settings.location = project->mapSectionIdNames.value(0, "0");
settings.song = project->defaultSong;
settings.canFlyTo = false;
settings.showLocationName = true;

View file

@ -29,7 +29,6 @@ RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project) :
this->ui->setupUi(this);
this->project = project;
this->configFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg));
this->mapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
this->initShortcuts();
this->restoreWindowState();
}
@ -110,67 +109,13 @@ void RegionMapEditor::applyUserShortcuts() {
}
bool RegionMapEditor::loadRegionMapEntries() {
this->region_map_entries.clear();
ParseUtil parser;
QJsonDocument sectionsDoc;
if (!parser.tryParseJsonFile(&sectionsDoc, this->mapSectionFilepath)) {
logError(QString("Failed to read map data from %1").arg(this->mapSectionFilepath));
return false;
}
// for some unknown reason, the OrderedJson class would not parse this properly
// perhaps updating nlohmann/json here would fix it, but that also requires using C++17
QJsonObject object = sectionsDoc.object();
for (auto entryRef : object["map_sections"].toArray()) {
QJsonObject entryObject = entryRef.toObject();
QString entryMapSection = ParseUtil::jsonToQString(entryObject["map_section"]);
MapSectionEntry entry;
entry.name = ParseUtil::jsonToQString(entryObject["name"]);
entry.x = ParseUtil::jsonToInt(entryObject["x"]);
entry.y = ParseUtil::jsonToInt(entryObject["y"]);
entry.width = ParseUtil::jsonToInt(entryObject["width"]);
entry.height = ParseUtil::jsonToInt(entryObject["height"]);
entry.valid = true;
this->region_map_entries[entryMapSection] = entry;
}
this->region_map_entries = this->project->regionMapEntries;
return true;
}
bool RegionMapEditor::saveRegionMapEntries() {
QFile sectionsFile(this->mapSectionFilepath);
if (!sectionsFile.open(QIODevice::WriteOnly)) {
logError(QString("Could not open %1 for writing").arg(this->mapSectionFilepath));
return false;
}
OrderedJson::object object;
OrderedJson::array mapSectionArray;
for (auto pair : this->region_map_entries) {
QString section = pair.first;
MapSectionEntry entry = pair.second;
OrderedJson::object entryObject;
entryObject["map_section"] = section;
entryObject["name"] = entry.name;
entryObject["x"] = entry.x;
entryObject["y"] = entry.y;
entryObject["width"] = entry.width;
entryObject["height"] = entry.height;
mapSectionArray.append(entryObject);
}
object["map_sections"] = mapSectionArray;
OrderedJson sectionsJson(object);
OrderedJsonDoc jsonDoc(&sectionsJson);
jsonDoc.dump(&sectionsFile);
sectionsFile.close();
this->project->regionMapEntries = this->region_map_entries;
this->project->saveRegionMapSections();
return true;
}
@ -708,7 +653,7 @@ void RegionMapEditor::displayRegionMapLayoutOptions() {
this->ui->comboBox_RM_ConnectedMap->blockSignals(true);
this->ui->comboBox_RM_ConnectedMap->clear();
this->ui->comboBox_RM_ConnectedMap->addItems(this->project->mapSectionValueToName.values());
this->ui->comboBox_RM_ConnectedMap->addItems(this->project->mapSectionIdNames);
this->ui->comboBox_RM_ConnectedMap->blockSignals(false);
this->ui->frame_RM_Options->setEnabled(true);
@ -775,7 +720,7 @@ void RegionMapEditor::displayRegionMapEntryOptions() {
if (!this->region_map->layoutEnabled()) return;
this->ui->comboBox_RM_Entry_MapSection->clear();
this->ui->comboBox_RM_Entry_MapSection->addItems(this->project->mapSectionValueToName.values());
this->ui->comboBox_RM_Entry_MapSection->addItems(this->project->mapSectionIdNames);
this->ui->spinBox_RM_Entry_x->setMaximum(128);
this->ui->spinBox_RM_Entry_y->setMaximum(128);
this->ui->spinBox_RM_Entry_width->setMinimum(1);
@ -787,17 +732,13 @@ void RegionMapEditor::displayRegionMapEntryOptions() {
void RegionMapEditor::updateRegionMapEntryOptions(QString section) {
if (!this->region_map->layoutEnabled()) return;
bool isSpecialSection = (section == this->region_map->default_map_section
|| section == this->region_map->count_map_section);
bool enabled = (!isSpecialSection && this->region_map_entries.contains(section));
bool enabled = (section != this->region_map->default_map_section) && this->region_map_entries.contains(section);
this->ui->lineEdit_RM_MapName->setEnabled(enabled);
this->ui->spinBox_RM_Entry_x->setEnabled(enabled);
this->ui->spinBox_RM_Entry_y->setEnabled(enabled);
this->ui->spinBox_RM_Entry_width->setEnabled(enabled);
this->ui->spinBox_RM_Entry_height->setEnabled(enabled);
this->ui->pushButton_entryActivate->setEnabled(!isSpecialSection);
this->ui->pushButton_entryActivate->setEnabled(section != this->region_map->default_map_section);
this->ui->pushButton_entryActivate->setText(enabled ? "Remove" : "Add");
this->ui->lineEdit_RM_MapName->blockSignals(true);
@ -902,14 +843,8 @@ void RegionMapEditor::onRegionMapEntryDragged(int new_x, int new_y) {
}
void RegionMapEditor::onRegionMapLayoutSelectedTileChanged(int index) {
QString message = QString();
this->currIndex = index;
this->region_map_layout_item->highlightedTile = index;
if (this->region_map->squareHasMap(index)) {
message = QString("\t %1").arg(this->project->mapSecToMapHoverName.value(
this->region_map->squareMapSection(index))).remove("{NAME_END}");
}
this->ui->statusbar->showMessage(message);
updateRegionMapLayoutOptions(index);
this->region_map_layout_item->draw();
@ -922,8 +857,7 @@ void RegionMapEditor::onRegionMapLayoutHoveredTileChanged(int index) {
if (x >= 0 && y >= 0) {
message = QString("(%1, %2)").arg(x).arg(y);
if (this->region_map->squareHasMap(index)) {
message += QString("\t %1").arg(this->project->mapSecToMapHoverName.value(
this->region_map->squareMapSection(index))).remove("{NAME_END}");
message += QString("\t %1").arg(this->region_map->squareMapSection(index));
}
}
this->ui->statusbar->showMessage(message);
@ -1203,10 +1137,10 @@ void RegionMapEditor::on_action_Swap_triggered() {
QFormLayout form(&popup);
QComboBox *oldSecBox = new QComboBox();
oldSecBox->addItems(this->project->mapSectionValueToName.values());
oldSecBox->addItems(this->project->mapSectionIdNames);
form.addRow(new QLabel("Map Section 1:"), oldSecBox);
QComboBox *newSecBox = new QComboBox();
newSecBox->addItems(this->project->mapSectionValueToName.values());
newSecBox->addItems(this->project->mapSectionIdNames);
form.addRow(new QLabel("Map Section 2:"), newSecBox);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);
@ -1242,10 +1176,10 @@ void RegionMapEditor::on_action_Replace_triggered() {
QFormLayout form(&popup);
QComboBox *oldSecBox = new QComboBox();
oldSecBox->addItems(this->project->mapSectionValueToName.values());
oldSecBox->addItems(this->project->mapSectionIdNames);
form.addRow(new QLabel("Old Map Section:"), oldSecBox);
QComboBox *newSecBox = new QComboBox();
newSecBox->addItems(this->project->mapSectionValueToName.values());
newSecBox->addItems(this->project->mapSectionIdNames);
form.addRow(new QLabel("New Map Section:"), newSecBox);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &popup);