#include "regionmapeditor.h" #include #include #include #include #include // TODO: add logging / config stuff // IN: ROUTE_101 ... OUT: MAP_ROUTE101 // eg. SOUTHERN_ISLAND -> MAP_SOUTHERN_ISLAND -> SouthernIsland(n) -> SouthernIsland_Exterior // MT_CHIMNEY -> MAP_MT_CHIMNEY -> MtChimney(y) // ROUTE_101 -> MAP_ROUTE101 -> Route101(y) // TODO: move this maybe? would I be able to call it from this file if it was in map.cpp? QString RegionMap::mapSecToMapConstant(QString mapSectionName) { // QString mapConstantName = "MAP_"; QString sectionNameTemp = mapSectionName.replace("ROUTE_","ROUTE"); mapConstantName += sectionNameTemp; return mapConstantName; } // TODO: verify these are in the correct order // also TODO: read this from the project somehow QMap> RegionMap::ruby_city_maps_ = QMap>({ {"LavaridgeTown", { {"lavaridge_0.bin", 5, 3}, }}, {"FallarborTown", { {"fallarbor_0.bin", 3, 0}, }}, {"FortreeCity", { {"fortree_0.bin", 12, 0}, }}, {"SlateportCity", { {"slateport_0.bin", 8, 10}, {"slateport_1.bin", 8, 11}, }}, {"RustboroCity", { {"rustboro_0.bin", 0, 5}, {"rustboro_1.bin", 0, 6}, }}, {"PacifidlogTown", { {"pacifidlog_0.bin", 17, 10}, }}, {"MauvilleCity", { {"mauville_0.bin", 8, 6}, {"mauville_1.bin", 9, 6}, }}, {"OldaleTown", { {"oldale_0.bin", 4, 9}, }}, {"LilycoveCity", { {"lilycove_0.bin", 18, 3}, {"lilycove_1.bin", 19, 3}, }}, {"LittlerootTown", { {"littleroot_0.bin", 4, 11}, }}, {"DewfordTown", { {"dewford_0.bin", 2, 14}, }}, {"SootopolisCity", { {"sootopolis_0.bin", 21, 7}, }}, {"EverGrandeCity", { {"ever_grande_0.bin", 27, 8}, {"ever_grande_1.bin", 27, 9}, }}, {"VerdanturfTown", { {"verdanturf_0.bin", 4, 6}, }}, {"MossdeepCity", { {"mossdeep_0.bin", 24, 5}, {"mossdeep_1.bin", 25, 5}, }}, {"PetalburgCity", { {"petalburg_0.bin", 1, 9}, }}, }); void RegionMap::init(Project *pro) { QString path = pro->root; // // TODO: in the future, allow these to be adjustable (and save values) // possibly use a config file? layout_width_ = 28; layout_height_ = 15; img_width_ = layout_width_ + 4; img_height_ = layout_height_ + 5; //city_map_squares_path = QString(); temp_path = path;// delete this region_map_bin_path = path + "/graphics/pokenav/region_map_map.bin"; region_map_png_path = path + "/graphics/pokenav/region_map.png"; region_map_layout_path = path + "/src/data/region_map_layout.h"; readBkgImgBin(); readLayout(pro->mapConstantsToMapNames); readCityMaps(); //tryGetMap(); //saveBkgImgBin(); //saveLayout(); test(pro->mapConstantsToMapNames); } // as of now, this needs to be called first because it initializes all the // RegionMapSquare s in the list // TODO: if the tileId is not valid for the provided image, make sure it does not crash void RegionMap::readBkgImgBin() { QFile binFile(region_map_bin_path); if (!binFile.open(QIODevice::ReadOnly)) return; QByteArray mapBinData = binFile.readAll(); binFile.close(); // the two is because lines are skipped for some reason // (maybe that is because there could be multiple layers?) // background image is also 32x20 for (int m = 0; m < img_height_; m++) { for (int n = 0; n < img_width_; n++) { RegionMapSquare square;// = square.tile_img_id = mapBinData.at(n + m * img_width_ * 2); map_squares.append(square); } } } void RegionMap::saveBkgImgBin() { QByteArray data(4096,0);// use a constant here? maybe read the original size? for (int m = 0; m < img_height_; m++) { for (int n = 0; n < img_width_; n++) { data[n + m * img_width_ * 2] = map_squares[n + m * img_width_].tile_img_id; } } QFile file(region_map_bin_path); if (!file.open(QIODevice::WriteOnly)) return; file.write(data); file.close(); } // done void RegionMap::readLayout(QMap *qmap) { QFile file(region_map_layout_path); if (!file.open(QIODevice::ReadOnly)) return; QMap * abbr = new QMap; QString line, text; QStringList *captured = new QStringList; QTextStream in(&file); while (!in.atEnd()) { line = in.readLine(); if (line.startsWith("#define")) { QStringList split = line.split(QRegularExpression("\\s+")); abbr->insert(split[2].replace("MAPSEC_",""), split[1]); } else { text += line.remove(" "); } } QRegularExpression re("{(.*?)}"); *captured = re.match(text).captured(1).split(","); captured->removeAll({}); // replace abbreviations with names for (int i = 0; i < captured->length(); i++) { QString value = (*captured)[i]; if (value.startsWith("R(")) {// routes are different captured->replace(i, QString("ROUTE_%1").arg(value.mid(2,3))); } else { captured->replace(i, abbr->key(value)); } } // TODO: improve this? for (int m = 0, i = 0; m < layout_height_; m++) { for (int n = 0; n < layout_width_; n++) { i = img_index_(n,m); QString secname = (*captured)[layout_index_(n,m)]; if (secname != "NOTHING") map_squares[i].has_map = true; map_squares[i].map_name = qmap->value(mapSecToMapConstant(secname)); map_squares[i].x = n; map_squares[i].y = m; } } mapname_abbr = abbr; layout_map_names = captured; file.close(); } // does it matter that it doesn't save in order? // do i need to use a QList ?? void RegionMap::saveLayout() { // QString layout_text = ""; QString mapsec = "MAPSEC_"; QString define = "#define "; QString array_start = "static const u8 sRegionMapLayout[] =\n{"; QString array_close = "\n};\n"; QString tab = " "; for (QString key : mapname_abbr->keys()) { layout_text += define + mapname_abbr->value(key) + tab + mapsec + key + "\n"; } layout_text += "\n" + array_start;// + + array_close;//oops //qDebug() << *layout_map_names; int cnt = 0; for (QString s : *layout_map_names) { // if (!(cnt % layout_width_)) { layout_text += "\n" + tab; } if (s.startsWith("ROUTE_")) { layout_text += QString("R(%1)").arg(s.replace("ROUTE_","")) + ", "; } else { layout_text += mapname_abbr->value(s) + ", "; } cnt++; } //layout_text. layout_text += array_close; QFile file(region_map_layout_path); if (!file.open(QIODevice::WriteOnly)) return; file.write(layout_text.toUtf8()); file.close(); } void RegionMap::readCityMaps() { // //for (int m = 0; m < layout_height_; m++) { // QString tester; // for (int n = 0; n < layout_width_; n++) { // tester += (QString::number(img_index_(n,m)).rightJustified(3, '.') + " "); // } // qDebug() << tester; //} //for (auto map : map_squares) { for (int map = 0; map < map_squares.size(); map++) { // if (map_squares[map].has_map) { // if (ruby_city_maps_.contains(map_squares[map].map_name)) { map_squares[map].has_city_map = true; //map_squares[map].city_map_name = ruby_city_maps_.value(map_squares[map].map_name)[0].tilemap; QList city_maps = ruby_city_maps_.value(map_squares[map].map_name); for (auto city_map : city_maps) { // if (city_map.x == map_squares[map].x && city_map.y == map_squares[map].y) // map_squares[map].city_map_name = city_map.tilemap; } } } } } //done QString RegionMap::newAbbr(QString mapname) { QString abbr; QStringList words = mapname.split("_"); if (words.length() == 1) { abbr = (words[0] + "_____X").left(6); } else { abbr = (words.front() + "___X").left(4) + "_" + words.back().at(0); } // to guarantee unique abbreviations (up to 14) QString extra_chars = "23456789BCDEF"; int count = 0; while ((*mapname_abbr).values().contains(abbr)) { abbr.replace(5,1,extra_chars[count]); count++; } return abbr; } // layout coords to image index int RegionMap::img_index_(int x, int y) { return ((x + 1) + (y + 2) * img_width_); } // layout coords to layout index int RegionMap::layout_index_(int x, int y) { return (x + y * layout_width_); } // img coords to layout index? // img coords to img index? void RegionMap::test(QMap* qmap) { // bool debug_rmap = false; if (debug_rmap) { for (auto square : map_squares) { qDebug() << "(" << square.x << "," << square.y << ")" << square.tile_img_id << square.has_map << square.map_name << square.has_city_map << square.city_map_name ; //if (qmap->contains(mapSecToMapConstant(square.map_name))) // extras += qmap->value(mapSecToMapConstant(square.map_name)) + " "; //else // extras += "nothing "; } QPixmap png(region_map_png_path); //png.load(region_map_png_path); qDebug() << "png num 8x8 tiles" << QString("0x%1").arg((png.width()/8) * (png.height() / 8), 2, 16, QChar('0')); } } int RegionMap::width() { return this->img_width_; } int RegionMap::height() { return this->img_height_; } // TODO: remove +2 and put elsewhere QSize RegionMap::imgSize() { return QSize(img_width_ * 8 + 2, img_height_ * 8 + 2); } // TODO: rename to getTileIdAt()? unsigned RegionMap::getTileId(int x, int y) { // return map_squares[x + y * img_width_].tile_img_id; //qDebug() << x << y; //return 0; } // sidenote: opening the map from MAPSEC_x will not always be right // there needs to be a mapsections to mapname QMap // otherwie, look for the first map with right substring // mapConstantsToMapNames [MAP_ROUTE106] = "Route106" // eg. SOUTHERN_ISLAND -> MAP_SOUTHERN_ISLAND -> SouthernIsland(n) -> SouthernIsland_Exterior // MT_CHIMNEY -> MAP_MT_CHIMNEY -> MtChimney(y) // ROUTE_101 -> MAP_ROUTE101 -> Route101(y) // (or synchronize these for consistency in the repos :: underscore / no underscore) // TODO: change debugs to logs void RegionMap::save() { // qDebug() << "saving region map image tilemap at" << region_map_bin_path << "\n" ;//<< "saving region map layout at" << region_map_layout_path << "\n"; saveBkgImgBin(); }