diff --git a/.gitignore b/.gitignore index 3d265d53..bde28f17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,14 @@ porymap.pro.user *.autosave *.stash *.o -moc_* -qrc_* porymap.app* porymap +porymap.cfg +porymap.log Makefile -# Generated UI header +# Qt generated files ui_*.h - +moc_*.h +moc_*.cpp +qrc_*.cpp diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index 1aa69cdd..c1e76938 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -237,7 +237,7 @@ - 0 + 4 false @@ -1066,8 +1066,8 @@ 8 0 - 221 - 328 + 222 + 353 @@ -2693,6 +2693,785 @@ + + + Region Map + + + + + 460 + 420 + 301 + 181 + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignHCenter|Qt::AlignTop + + + + true + + + + 8 + 0 + 283 + 179 + + + + + 0 + 0 + + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + true + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 19 + 9 + 381 + 291 + + + + 0 + + + + Background Image + + + + + 30 + 20 + 321 + 211 + + + + + 1 + 0 + + + + true + + + + + 0 + 0 + 319 + 209 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + false + + + false + + + QAbstractScrollArea::AdjustIgnored + + + QGraphicsView::NoDrag + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + + + + Map Layout + + + + + 20 + 20 + 321 + 211 + + + + + 1 + 0 + + + + true + + + + + 0 + 0 + 319 + 209 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + false + + + false + + + QAbstractScrollArea::AdjustIgnored + + + QGraphicsView::NoDrag + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + + + + + + 80 + 380 + 261 + 251 + + + + + 1 + 0 + + + + true + + + + + 0 + 0 + 259 + 249 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + false + + + false + + + QAbstractScrollArea::AdjustIgnored + + + QGraphicsView::NoDrag + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + + + + 440 + 20 + 351 + 291 + + + + 0 + + + + + + 30 + 20 + 281 + 261 + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignHCenter|Qt::AlignTop + + + + true + + + + 8 + 0 + 263 + 259 + + + + + 0 + 0 + + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + true + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + false + + + + 50 + 40 + 261 + 170 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Connected Map + + + + + + + <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 display when the player enters it.</p></body></html> + + + true + + + + + + + Weather + + + + + + + <html><head/><body><p>The default weather for this map.</p></body></html> + + + true + + + + + + + Type + + + + + + + <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> + + + true + + + + + + + Show Location Name + + + + + + + <html><head/><body><p>Whether or not to display the location name when the player enters the map.</p></body></html> + + + + + + + + + + Battle scene + + + + + + + <html><head/><body><p>Determines the type of battle scene graphics to use.</p></body></html> + + + true + + + + + + + + diff --git a/include/core/regionmapeditor.h b/include/core/regionmapeditor.h new file mode 100644 index 00000000..2875ef81 --- /dev/null +++ b/include/core/regionmapeditor.h @@ -0,0 +1,179 @@ +#ifndef REGIONMAP_H +#define REGIONMAP_H + +#include "project.h" +#include "map.h" +#include "tilemaptileselector.h" +//#include "block.h" + +#include +#include +#include +#include +#include +#include + +// if editing map bins, will need to remake the graphics when editing +// are the scenes set in the editor / project / mainwindow files? + +/* + * - display the region map background image + * - edit the region_map_layout.h layout + * - edit city maps metatile layout and JUST save the mapname_num.bin + * - edit + * who edits pokenav_city_maps 1 and 2? + * users can: - add the incbins probably themselves + * - add + * - edit region map background image + * + * + * + * + * Editor: + * - void displayCityMapMetatileSelector + * - void displayRegionMapTileSelector + * - void selectRegionMapTile(QString mapname) + * - QGraphicsScene *scene_city_map_metatiles + * - TilemapTileSelector *city_map_metatile_selector_item + * - Tileset *city_map_squares (or tileset_city_map?) + * - Tileset *tileset_region_map + * + * MainWindow: + * + * + * Project: + * + */ + +// rename this struct +struct CityMapPosition +{ + // + //QString filename; // eg. dewford_0 + QString tilemap;// eg. "dewford_0" + int x; + int y; +}; + +// class that holds data for each square in this project +// struct? +// TODO: change char / uint8_t to unsigned +class RegionMapSquare +{ +public: + // + // are positions layout positions? (yes) so out of bounds are all (-1, -1) <-- how it's used in code + // (GetRegionMapLocationPosition) + // or image positions + int x = -1;// x position, 0-indexed from top left + int y = -1;// y position, 0-indexed from top left + uint8_t tile_img_id;// tilemap ids for the background image + bool has_map = false;// whether this square is linked to a map or is empty + QString map_name;// name of the map associated with this square (if has_map is true): eg. "MAUVILLE_CITY" + // ^ use project mapsec to names table + bool has_city_map;// whether there is a city map on this grid + //QList city_maps; + QString city_map_name;// filename of the city_map tilemap + //bool is_flyable;//? needed ? + friend class RegionMap;// not necessary if instance? what +}; + +class RegionMap : public QObject +{ + Q_OBJECT +//public: +// explicit Map(QObject *parent = nullptr); + +public: + RegionMap() = default; + + ~RegionMap() { + delete mapname_abbr; + delete layout_map_names; + //delete background_image_tiles; + //delete map_squares; + //delete background_image_selector_item; + }; + + static QMap> ruby_city_maps_; + static QString mapSecToMapConstant(QString); + + //RegionMapSquare *map_squares = nullptr;// array of RegionMapSquares + QList map_squares; + + QString temp_path;// delete this + QString city_map_squares_path; + QString region_map_png_path; + QString region_map_bin_path;// = QString::null; + QString city_map_header_path;//dafuq is this? + QString region_map_layout_path; + + //QMap something;// name of map : info about city map, position in layoit, etc. + //QMap regionMapLayoutTng; // mapName : tilemaptileselector + // maybe position data to select correct square when changing map on side but only if map is a valid + //QList *background_image_tiles;// the visible ones anyways // using list because replace + //TilemapTileSelector *background_image_selector_item;// ? + QMap *mapname_abbr;// layout shortcuts mapname:region_map_layout defines (both ways) + // make this a QHash?? <-- no because something + QStringList *layout_map_names; + // uint8_t border_tile; + + bool hasUnsavedChanges(); + + void init(Project*);//QString); + + // parseutil.cpp ? + void readBkgImgBin(); + void readCityMaps();// more complicated + void readLayout(QMap*); + + QString newAbbr(QString);// makes a *unique* 5 character abbreviation from mapname to add to mapname_abbr + + // editing functions + // if they are booleans, returns true if successful? + bool placeTile(char, int, int);// place tile at x, y + bool removeTile(char, int, int);// replaces with 0x00 byte at x,y + bool placeMap(QString, int, int); + bool removeMap(QString, int, int); + bool removeMap(QString);// remove all instances of map + + void save(); + void saveBkgImgBin(); + void saveLayout(); + void saveCityMaps(); + + void update();// update the view in case something is broken? + void resize(int, int); + void setWidth(int); + void setHeight(int); + int width(); + int height(); + QSize imgSize(); + unsigned getTileId(int, int); + + // implement these here? + void undo(); + void redo(); + + void test(QMap*);// remove when done testing obvi + +// TODO: move read / write functions to private (and others) +private: + // + int layout_width_; + int layout_height_; + int img_width_; + int img_height_; + int img_index_(int, int);// returns index int at x,y args (x + y * width_ * 2) // 2 because + int layout_index_(int, int); + +//protected: + // + +//signals: + // +}; + +//TilemapTileSelector *city_map_metatile_selector_item = nullptr; + +#endif // REGIONMAP_H diff --git a/include/editor.h b/include/editor.h index 4b7f71a0..b28f0ebf 100644 --- a/include/editor.h +++ b/include/editor.h @@ -19,6 +19,8 @@ #include "currentselectedmetatilespixmapitem.h" #include "collisionpixmapitem.h" #include "mappixmapitem.h" +#include "regionmappixmapitem.h" +#include "regionmapeditor.h" #include "settings.h" #include "movablerect.h" #include "cursortilerect.h" @@ -77,6 +79,33 @@ public: void updateCustomMapHeaderValues(QTableWidget *); Tileset *getCurrentMapPrimaryTileset(); +// + RegionMap *region_map; + void loadRegionMapData(); + + QGraphicsScene *scene_region_map_image = nullptr; + QGraphicsScene *scene_region_map_layout = nullptr;//? + QGraphicsScene *scene_region_map_tiles = nullptr; + TilemapTileSelector *mapsquare_selector_item = nullptr; + RegionMapPixmapItem *region_map_item = nullptr; + + void displayRegionMap(); + void displayRegionMapTileSelector(); + + // selectedTileChanged, hoveredTileChanged, hoveredTileCleared + void onRegionMapTileSelectorSelectedTileChanged(); + void onRegionMapTileSelectorHoveredTileChanged(unsigned); + void onRegionMapTileSelectorHoveredTileCleared(); + +private slots: + void onHoveredRegionMapTileChanged(int, int); + void onHoveredRegionMapTileCleared(); + void mouseEvent_region_map(QGraphicsSceneMouseEvent *, RegionMapPixmapItem *); + +public: + QString regionMapTabStatusbarMessage;// TODO: make this name not terrible +// + DraggablePixmapItem *addMapEvent(Event *event); void selectMapEvent(DraggablePixmapItem *object); void selectMapEvent(DraggablePixmapItem *object, bool toggle); @@ -105,6 +134,7 @@ public: QGraphicsScene *scene_selected_border_metatiles = nullptr; QGraphicsScene *scene_collision_metatiles = nullptr; QGraphicsScene *scene_elevation_metatiles = nullptr; + MetatileSelector *metatile_selector_item = nullptr; BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr; diff --git a/include/mainwindow.h b/include/mainwindow.h index bb7d98c1..3cbe1fc0 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -65,6 +65,8 @@ private slots: void on_checkBox_AllowBiking_clicked(bool checked); void on_checkBox_AllowEscapeRope_clicked(bool checked); + void on_tabWidget_Region_Map_currentChanged(int); + void on_tabWidget_currentChanged(int index); void on_actionUndo_triggered(); diff --git a/include/ui/regionmappixmapitem.h b/include/ui/regionmappixmapitem.h new file mode 100644 index 00000000..12de3385 --- /dev/null +++ b/include/ui/regionmappixmapitem.h @@ -0,0 +1,36 @@ +#ifndef REGIONMAPPIXMAPITEM_H +#define REGIONMAPPIXMAPITEM_H + +#include "regionmapeditor.h" +#include "tilemaptileselector.h" +#include + +class RegionMapPixmapItem : public QObject, public QGraphicsPixmapItem { + Q_OBJECT +public: + RegionMapPixmapItem(RegionMap *rmap, TilemapTileSelector *tile_selector) { + this->region_map = rmap; + this->tile_selector = tile_selector; + setAcceptHoverEvents(true); + } + RegionMap *region_map; + TilemapTileSelector *tile_selector; + + virtual void paint(QGraphicsSceneMouseEvent*); + virtual void select(QGraphicsSceneMouseEvent*); + virtual void draw(); + +signals: + void mouseEvent(QGraphicsSceneMouseEvent *, RegionMapPixmapItem *); + void hoveredRegionMapTileChanged(int x, int y); + void hoveredRegionMapTileCleared(); + +protected: + void hoverMoveEvent(QGraphicsSceneHoverEvent*); + void hoverLeaveEvent(QGraphicsSceneHoverEvent*); + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); +}; + +#endif // REGIONMAPPIXMAPITEM_H diff --git a/include/ui/tilemaptileselector.h b/include/ui/tilemaptileselector.h new file mode 100644 index 00000000..8bb52050 --- /dev/null +++ b/include/ui/tilemaptileselector.h @@ -0,0 +1,51 @@ +#ifndef TILEMAPTILESELECTOR_H +#define TILEMAPTILESELECTOR_H + +#include "selectablepixmapitem.h" + +class TilemapTileSelector: public SelectablePixmapItem { + Q_OBJECT +public: + TilemapTileSelector(QPixmap pixmap): SelectablePixmapItem(8, 8, 1, 1) { + this->pixmap = pixmap; + this->numTilesWide = 16; + this->selectedTile = 0x00; + setAcceptHoverEvents(true); + } + void draw(); + void select(unsigned tileId); + unsigned getSelectedTile(); + + int pixelWidth; + int pixelHeight; + + unsigned selectedTile; + + // TODO: which of these need to be made public? + // call this tilemap? or is tilemap the binary file? + QPixmap pixmap;// pointer? + QImage currTile;// image of just the currently selected tile to draw onto graphicsview + QImage tileImg(unsigned tileId); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); + void hoverMoveEvent(QGraphicsSceneHoverEvent*); + void hoverLeaveEvent(QGraphicsSceneHoverEvent*); + +private: + int numTilesWide; + int numTiles; + void updateSelectedTile(); + unsigned getTileId(int x, int y); + QPoint getTileIdCoords(unsigned); + unsigned getValidTileId(unsigned);// TODO: implement this to prevent segfaults + +signals: + void hoveredTileChanged(unsigned); + void hoveredTileCleared(); + void selectedTileChanged(unsigned); +}; + +#endif // TILEMAPTILESELECTOR_H diff --git a/porymap.pro b/porymap.pro index cfd02755..3868a8a2 100644 --- a/porymap.pro +++ b/porymap.pro @@ -28,6 +28,7 @@ SOURCES += src/core/block.cpp \ src/core/parseutil.cpp \ src/core/tile.cpp \ src/core/tileset.cpp \ + src/core/regionmapeditor.cpp \ src/ui/aboutporymap.cpp \ src/ui/bordermetatilespixmapitem.cpp \ src/ui/collisionpixmapitem.cpp \ @@ -40,6 +41,7 @@ SOURCES += src/core/block.cpp \ src/ui/graphicsview.cpp \ src/ui/imageproviders.cpp \ src/ui/mappixmapitem.cpp \ + src/ui/regionmappixmapitem.cpp \ src/ui/mapsceneeventfilter.cpp \ src/ui/metatilelayersitem.cpp \ src/ui/metatileselector.cpp \ @@ -53,6 +55,7 @@ SOURCES += src/core/block.cpp \ src/ui/tileseteditor.cpp \ src/ui/tileseteditormetatileselector.cpp \ src/ui/tileseteditortileselector.cpp \ + src/ui/tilemaptileselector.cpp \ src/ui/newmappopup.cpp \ src/config.cpp \ src/editor.cpp \ @@ -78,6 +81,7 @@ HEADERS += include/core/block.h \ include/core/parseutil.h \ include/core/tile.h \ include/core/tileset.h \ + include/core/regionmapeditor.h \ include/ui/aboutporymap.h \ include/ui/bordermetatilespixmapitem.h \ include/ui/collisionpixmapitem.h \ @@ -90,6 +94,7 @@ HEADERS += include/core/block.h \ include/ui/graphicsview.h \ include/ui/imageproviders.h \ include/ui/mappixmapitem.h \ + include/ui/regionmappixmapitem.h \ include/ui/mapsceneeventfilter.h \ include/ui/metatilelayersitem.h \ include/ui/metatileselector.h \ @@ -103,6 +108,7 @@ HEADERS += include/core/block.h \ include/ui/tileseteditor.h \ include/ui/tileseteditormetatileselector.h \ include/ui/tileseteditortileselector.h \ + include/ui/tilemaptileselector.h \ include/ui/newmappopup.h \ include/config.h \ include/editor.h \ diff --git a/src/core/regionmapeditor.cpp b/src/core/regionmapeditor.cpp new file mode 100644 index 00000000..73b27c0f --- /dev/null +++ b/src/core/regionmapeditor.cpp @@ -0,0 +1,402 @@ +#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(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/editor.cpp b/src/editor.cpp index 5674721b..9cfce50e 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -19,12 +19,16 @@ Editor::Editor(Ui::MainWindow* ui) this->settings = new Settings(); this->playerViewRect = new MovableRect(&this->settings->playerViewRectEnabled, 30 * 8, 20 * 8, qRgb(255, 255, 255)); this->cursorMapTileRect = new CursorTileRect(&this->settings->cursorTileRectEnabled, qRgb(255, 255, 255)); + this->region_map = new RegionMap;// TODO: why is this here? } void Editor::saveProject() { if (project) { project->saveAllMaps(); project->saveAllDataStructures(); + if (region_map) { + region_map->save(); + } } } @@ -33,6 +37,9 @@ void Editor::save() { project->saveMap(map); project->saveAllDataStructures(); } + if (project && region_map) { + region_map->save(); + } } void Editor::undo() { @@ -600,6 +607,9 @@ void Editor::displayMap() { scene->addItem(this->playerViewRect); scene->addItem(this->cursorMapTileRect); + displayRegionMapTileSelector();//? + displayRegionMap(); + if (map_item) { map_item->setVisible(false); } @@ -1261,6 +1271,93 @@ void Editor::deleteEvent(Event *event) { //updateSelectedObjects(); } +void Editor::loadRegionMapData() { + // + region_map->init(project); +} + +// TODO: get this to display on a decent scale +void Editor::displayRegionMapTileSelector() { + // + this->mapsquare_selector_item = new TilemapTileSelector(QPixmap(this->region_map->region_map_png_path)); + this->mapsquare_selector_item->draw(); + + this->scene_region_map_tiles = new QGraphicsScene; + this->scene_region_map_tiles->addItem(this->mapsquare_selector_item); + + connect(this->mapsquare_selector_item, &TilemapTileSelector::selectedTileChanged, + this, &Editor::onRegionMapTileSelectorSelectedTileChanged);// TODO: remove this? + connect(this->mapsquare_selector_item, &TilemapTileSelector::hoveredTileChanged, + this, &Editor::onRegionMapTileSelectorHoveredTileChanged); + connect(this->mapsquare_selector_item, &TilemapTileSelector::hoveredTileCleared, + this, &Editor::onRegionMapTileSelectorHoveredTileCleared); + + this->ui->graphicsView_RegionMap_Tiles->setScene(this->scene_region_map_tiles); + this->ui->graphicsView_RegionMap_Tiles->setFixedSize(this->mapsquare_selector_item->pixelWidth + 2, + this->mapsquare_selector_item->pixelHeight + 2); +} + +// TODO: change the signal slot to new syntax +void Editor::displayRegionMap() { + // + this->region_map_item = new RegionMapPixmapItem(this->region_map, this->mapsquare_selector_item); + connect(region_map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*, RegionMapPixmapItem*)), + this, SLOT(mouseEvent_region_map(QGraphicsSceneMouseEvent*, RegionMapPixmapItem*))); + connect(region_map_item, SIGNAL(hoveredRegionMapTileChanged(int, int)), + this, SLOT(onHoveredRegionMapTileChanged(int, int))); + connect(region_map_item, SIGNAL(hoveredRegionMapTileCleared()), + this, SLOT(onHoveredRegionMapTileCleared())); + this->region_map_item->draw(); + + this->scene_region_map_image = new QGraphicsScene; + this->scene_region_map_image->addItem(this->region_map_item); + this->scene_region_map_image->setSceneRect(this->scene_region_map_image->sceneRect()); + + //this->scene_region_map_image->scale(2, 2); + this->ui->graphicsView_Region_Map_BkgImg->setScene(this->scene_region_map_image); + this->ui->graphicsView_Region_Map_BkgImg->setFixedSize(this->region_map->imgSize()); + //this->ui->graphicsView_Region_Map_BkgImg->scale(2.0, 2.0); +} + +void Editor::onRegionMapTileSelectorSelectedTileChanged() { + // +} + +void Editor::onRegionMapTileSelectorHoveredTileChanged(unsigned tileId) { + QString message = QString("Tile: 0x") + QString("%1").arg(tileId, 4, 16, QChar('0')).toUpper(); + this->ui->statusBar->showMessage(message); +} + +void Editor::onRegionMapTileSelectorHoveredTileCleared() { + // + QString message = QString("Selected Tile: 0x") + QString("%1").arg(this->mapsquare_selector_item->selectedTile, 4, 16, QChar('0')).toUpper(); + this->ui->statusBar->showMessage(message); +} + +void Editor::onHoveredRegionMapTileChanged(int x, int y) { + // + regionMapTabStatusbarMessage = QString("x: %1, y: %2 Tile: 0x").arg(x).arg(y) + QString("%1").arg(this->region_map->getTileId(x, y), 4, 16, QChar('0')).toUpper(); + this->ui->statusBar->showMessage(regionMapTabStatusbarMessage); +} + +void Editor::onHoveredRegionMapTileCleared() { + // + this->ui->statusBar->clearMessage(); +} + +void Editor::mouseEvent_region_map(QGraphicsSceneMouseEvent *event, RegionMapPixmapItem *item) { + // + if (event->buttons() & Qt::RightButton) { + // + item->select(event); + } else if (event->buttons() & Qt::MiddleButton) { + // TODO: add functionality here? replace or? + } else { + // + item->paint(event); + } +} + // It doesn't seem to be possible to prevent the mousePress event // from triggering both event's DraggablePixmapItem and the background mousePress. // Since the DraggablePixmapItem's event fires first, we can set a temp @@ -1274,6 +1371,5 @@ void Editor::objectsView_onMousePress(QMouseEvent *event) { selected_events->append(first); updateSelectedEvents(); } - selectingEvent = false; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 982f3be8..0bf6e874 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -263,11 +263,13 @@ bool MainWindow::openProject(QString dir) { setWindowTitle(editor->project->getProjectTitle()); loadDataStructures(); populateMapList(); + editor->loadRegionMapData(); success = setMap(getDefaultMap(), true); } else { setWindowTitle(editor->project->getProjectTitle()); loadDataStructures(); populateMapList(); + editor->loadRegionMapData(); } if (success) { @@ -596,6 +598,11 @@ void MainWindow::on_checkBox_AllowEscapeRope_clicked(bool checked) } } +void MainWindow::on_tabWidget_Region_Map_currentChanged(int index) { + // + ui->stackedWidget_RM_Options->setCurrentIndex(index); +} + void MainWindow::loadDataStructures() { Project *project = editor->project; project->readMapLayouts(); diff --git a/src/ui/regionmappixmapitem.cpp b/src/ui/regionmappixmapitem.cpp new file mode 100644 index 00000000..4c751898 --- /dev/null +++ b/src/ui/regionmappixmapitem.cpp @@ -0,0 +1,73 @@ +#include "regionmappixmapitem.h" +#include "imageproviders.h" + + + +// the function that draws the map on the scene +// (qnqlogous to Map::render) +// TODO: figure out why this is being called twice!! +void RegionMapPixmapItem::draw() { + if (!region_map) return; + + QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888); + + QPainter painter(&image); + for (int i = 0; i < region_map->map_squares.size(); i++) { + QImage img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id); + int x = i % region_map->width(); + int y = i / region_map->width(); + QPoint pos = QPoint(x * 8, y * 8); + painter.drawImage(pos, img); + } + painter.end(); + + this->setPixmap(QPixmap::fromImage(image)); +} + +void RegionMapPixmapItem::paint(QGraphicsSceneMouseEvent *event) { + if (region_map) { + if (event->type() == QEvent::GraphicsSceneMousePress) { + } else { + QPointF pos = event->pos(); + int x = static_cast(pos.x()) / 8; + int y = static_cast(pos.y()) / 8; + this->region_map->map_squares[x + y * region_map->width()].tile_img_id = this->tile_selector->selectedTile; + } + draw(); + } +} + +void RegionMapPixmapItem::select(QGraphicsSceneMouseEvent *event) { + QPointF pos = event->pos(); + int x = static_cast(pos.x()) / 8; + int y = static_cast(pos.y()) / 8; + this->tile_selector->select(this->region_map->getTileId(x, y)); +} + +void RegionMapPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + int x = static_cast(event->pos().x()) / 8; + int y = static_cast(event->pos().y()) / 8; + emit this->hoveredRegionMapTileChanged(x, y); +} + +void RegionMapPixmapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { + emit this->hoveredRegionMapTileCleared(); +} + +void RegionMapPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QPointF pos = event->pos(); + int x = static_cast(pos.x()) / 8; + int y = static_cast(pos.y()) / 8; + emit mouseEvent(event, this); +} + +void RegionMapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + int x = static_cast(event->pos().x()) / 8; + int y = static_cast(event->pos().y()) / 8; + emit this->hoveredRegionMapTileChanged(x, y); + emit mouseEvent(event, this); +} + +void RegionMapPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + emit mouseEvent(event, this); +} diff --git a/src/ui/tilemaptileselector.cpp b/src/ui/tilemaptileselector.cpp new file mode 100644 index 00000000..b109ceb2 --- /dev/null +++ b/src/ui/tilemaptileselector.cpp @@ -0,0 +1,112 @@ +#include "tilemaptileselector.h" + +#include + +void TilemapTileSelector::draw() { + size_t width_ = this->pixmap.width(); + this->pixelWidth = width_; + size_t height_ = this->pixmap.height(); + this->pixelHeight = height_; + size_t ntiles_ = (width_/8) * (height_/8);// length_ + + this->numTilesWide = width_ / 8; + this->numTiles = ntiles_; + + this->setPixmap(this->pixmap); + this->drawSelection(); +} + +//* +void TilemapTileSelector::select(unsigned tileId) { + QPoint coords = this->getTileIdCoords(tileId); + SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0); + this->selectedTile = tileId; + emit selectedTileChanged(tileId); +} +//*/ + +//* +void TilemapTileSelector::updateSelectedTile() { + QPoint origin = this->getSelectionStart(); + this->selectedTile = this->getTileId(origin.x(), origin.y()); +} +//*/ + +unsigned TilemapTileSelector::getSelectedTile() { + return this->selectedTile; +} + +//* +unsigned TilemapTileSelector::getTileId(int x, int y) { + int index = y * this->numTilesWide + x; + return index < this->numTiles ? index : this->numTiles % index; +} +//*/ + +//* +void TilemapTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mousePressEvent(event); + this->updateSelectedTile(); + emit selectedTileChanged(this->selectedTile); +} +//*/ + +//* +void TilemapTileSelector::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mouseMoveEvent(event); + this->updateSelectedTile(); + emit hoveredTileChanged(this->selectedTile); + emit selectedTileChanged(this->selectedTile); +} +//*/ + +//* +void TilemapTileSelector::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + SelectablePixmapItem::mouseReleaseEvent(event); + this->updateSelectedTile(); + emit selectedTileChanged(this->selectedTile); +} +//*/ + +//* +void TilemapTileSelector::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + QPoint pos = this->getCellPos(event->pos()); + unsigned tileId = this->getTileId(pos.x(), pos.y()); + emit this->hoveredTileChanged(tileId); +} +//*/ + +//* +void TilemapTileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { + emit this->hoveredTileCleared(); +} +//*/ + +//* +QPoint TilemapTileSelector::getTileIdCoords(unsigned tileId) { + int index = tileId < this->numTiles ? tileId : this->numTiles % tileId;// TODO: change this? + return QPoint(index % this->numTilesWide, index / this->numTilesWide);// ? is this right? +} +//*/ + +QImage TilemapTileSelector::tileImg(unsigned tileId) { + // + QPoint pos = getTileIdCoords(tileId); + return pixmap.copy(pos.x() * 8, pos.y() * 8, 8, 8).toImage(); +} + + + + + + + + + + + + + + + +