From 2246ead5a827899242cb519b740fde86212096b9 Mon Sep 17 00:00:00 2001 From: yenatch Date: Tue, 6 Sep 2016 23:50:47 -0400 Subject: [PATCH] Initial commit --- asm.cpp | 59 ++ asm.h | 15 + block.cpp | 29 + block.h | 20 + blockdata.cpp | 39 ++ blockdata.h | 28 + editor.cpp | 324 +++++++++ editor.h | 155 +++++ event.cpp | 52 ++ event.h | 100 +++ main.cpp | 11 + mainwindow.cpp | 370 ++++++++++ mainwindow.h | 69 ++ mainwindow.ui | 938 ++++++++++++++++++++++++++ map.cpp | 600 ++++++++++++++++ map.h | 165 +++++ metatile.cpp | 6 + metatile.h | 16 + pretmap.pro | 43 ++ project.cpp | 787 +++++++++++++++++++++ project.h | 69 ++ resources/icons/folder.ico | Bin 0 -> 5430 bytes resources/icons/folder_closed.ico | Bin 0 -> 5430 bytes resources/icons/folder_closed_map.ico | Bin 0 -> 1150 bytes resources/icons/folder_image.ico | Bin 0 -> 5430 bytes resources/icons/folder_map.ico | Bin 0 -> 5430 bytes resources/icons/image.ico | Bin 0 -> 1150 bytes resources/icons/map.ico | Bin 0 -> 1150 bytes resources/images.qrc | 11 + tile.cpp | 6 + tile.h | 16 + tileset.cpp | 6 + tileset.h | 27 + 33 files changed, 3961 insertions(+) create mode 100755 asm.cpp create mode 100755 asm.h create mode 100755 block.cpp create mode 100755 block.h create mode 100755 blockdata.cpp create mode 100755 blockdata.h create mode 100755 editor.cpp create mode 100755 editor.h create mode 100755 event.cpp create mode 100755 event.h create mode 100755 main.cpp create mode 100755 mainwindow.cpp create mode 100755 mainwindow.h create mode 100755 mainwindow.ui create mode 100755 map.cpp create mode 100755 map.h create mode 100755 metatile.cpp create mode 100755 metatile.h create mode 100755 pretmap.pro create mode 100755 project.cpp create mode 100755 project.h create mode 100755 resources/icons/folder.ico create mode 100755 resources/icons/folder_closed.ico create mode 100755 resources/icons/folder_closed_map.ico create mode 100755 resources/icons/folder_image.ico create mode 100755 resources/icons/folder_map.ico create mode 100755 resources/icons/image.ico create mode 100755 resources/icons/map.ico create mode 100755 resources/images.qrc create mode 100755 tile.cpp create mode 100755 tile.h create mode 100755 tileset.cpp create mode 100755 tileset.h diff --git a/asm.cpp b/asm.cpp new file mode 100755 index 00000000..60855b76 --- /dev/null +++ b/asm.cpp @@ -0,0 +1,59 @@ +#include "asm.h" + +Asm::Asm() +{ +} + +void Asm::strip_comment(QString *line) { + bool in_string = false; + for (int i = 0; i < line->length(); i++) { + if (line->at(i) == '"') { + in_string = !in_string; + } else if (line->at(i) == '@') { + if (!in_string) { + line->truncate(i); + break; + } + } + } +} + +QList* Asm::parse(QString text) { + QList *parsed = new QList; + QStringList lines = text.split('\n'); + for (QString line : lines) { + QString label; + //QString macro; + //QStringList *params; + strip_comment(&line); + if (line.isEmpty()) { + } else if (line.contains(':')) { + label = line.left(line.indexOf(':')); + QStringList *list = new QStringList; + list->append(".label"); // This is not a real keyword. It's used only to make the output more regular. + list->append(label); + parsed->append(*list); + // There should not be anything else on the line. + // gas will raise a syntax error if there is. + } else { + line = line.trimmed(); + //parsed->append(line.split(QRegExp("\\s*,\\s*"))); + QString macro; + QStringList params; + int index = line.indexOf(QRegExp("\\s+")); + macro = line.left(index); + params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*")); + params.prepend(macro); + parsed->append(params); + } + //if (macro != NULL) { + // if (macros->contains(macro)) { + // void* function = macros->value(macro); + // if (function != NULL) { + // std::function function(params); + // } + // } + //} + } + return parsed; +} diff --git a/asm.h b/asm.h new file mode 100755 index 00000000..5aa55b55 --- /dev/null +++ b/asm.h @@ -0,0 +1,15 @@ +#ifndef ASM_H +#define ASM_H + +#include +#include + +class Asm +{ +public: + Asm(); + void strip_comment(QString*); + QList* parse(QString); +}; + +#endif // ASM_H diff --git a/block.cpp b/block.cpp new file mode 100755 index 00000000..144ba2de --- /dev/null +++ b/block.cpp @@ -0,0 +1,29 @@ +#include "block.h" + +Block::Block() { +} + +Block::Block(uint16_t word) +{ + tile = word & 0x3ff; + collision = (word >> 10) & 0x3; + elevation = (word >> 12) & 0xf; +} + +Block::Block(const Block &block) { + tile = block.tile; + collision = block.collision; + elevation = block.elevation; +} + +uint16_t Block::rawValue() { + return (tile & 0x3ff) + ((collision & 0x3) << 10) + ((elevation & 0xf) << 12); +} + +bool Block::operator ==(Block other) { + return (tile == other.tile) && (collision == other.collision) && (elevation == other.elevation); +} + +bool Block::operator !=(Block other) { + return !(operator ==(other)); +} diff --git a/block.h b/block.h new file mode 100755 index 00000000..8b3943d5 --- /dev/null +++ b/block.h @@ -0,0 +1,20 @@ +#ifndef BLOCK_H +#define BLOCK_H + +#include + +class Block +{ +public: + Block(); + Block(uint16_t); + Block(const Block&); + bool operator ==(Block); + bool operator !=(Block); + uint16_t tile:10; + uint16_t collision:2; + uint16_t elevation:4; + uint16_t rawValue(); +}; + +#endif // BLOCK_H diff --git a/blockdata.cpp b/blockdata.cpp new file mode 100755 index 00000000..b08b936d --- /dev/null +++ b/blockdata.cpp @@ -0,0 +1,39 @@ +#include "blockdata.h" + +Blockdata::Blockdata(QObject *parent) : QObject(parent) +{ + blocks = new QList; +} + +void Blockdata::addBlock(uint16_t word) { + Block block(word); + blocks->append(block); +} + +void Blockdata::addBlock(Block block) { + blocks->append(block); +} + +QByteArray Blockdata::serialize() { + QByteArray data; + for (int i = 0; i < blocks->length(); i++) { + Block block = blocks->value(i); + uint16_t word = block.rawValue(); + data.append(word & 0xff); + data.append((word >> 8) & 0xff); + } + return data; +} + +void Blockdata::copyFrom(Blockdata* other) { + blocks->clear(); + for (int i = 0; i < other->blocks->length(); i++) { + addBlock(other->blocks->value(i)); + } +} + +Blockdata* Blockdata::copy() { + Blockdata* blockdata = new Blockdata; + blockdata->copyFrom(this); + return blockdata; +} diff --git a/blockdata.h b/blockdata.h new file mode 100755 index 00000000..5ba4930b --- /dev/null +++ b/blockdata.h @@ -0,0 +1,28 @@ +#ifndef BLOCKDATA_H +#define BLOCKDATA_H + +#include "block.h" + +#include +#include + +class Blockdata : public QObject +{ + Q_OBJECT +public: + explicit Blockdata(QObject *parent = 0); + +public: + QList *blocks; + void addBlock(uint16_t); + void addBlock(Block); + QByteArray serialize(); + void copyFrom(Blockdata*); + Blockdata* copy(); + +signals: + +public slots: +}; + +#endif // BLOCKDATA_H diff --git a/editor.cpp b/editor.cpp new file mode 100755 index 00000000..9a56e5fc --- /dev/null +++ b/editor.cpp @@ -0,0 +1,324 @@ +#include "editor.h" + +Editor::Editor() +{ + +} + +void Editor::saveProject() { + if (project) { + project->saveAllMaps(); + } +} + +void Editor::save() { + if (project && map) { + project->saveMap(map); + } +} + +void Editor::undo() { + if (current_view) { + ((MapPixmapItem*)current_view)->undo(); + } +} + +void Editor::redo() { + if (current_view) { + ((MapPixmapItem*)current_view)->redo(); + } +} + +void Editor::setEditingMap() { + current_view = map_item; + map_item->draw(); + map_item->setVisible(true); + map_item->setEnabled(true); + collision_item->setVisible(false); + objects_group->setVisible(false); +} + +void Editor::setEditingCollision() { + current_view = collision_item; + collision_item->draw(); + collision_item->setVisible(true); + map_item->setVisible(false); + objects_group->setVisible(false); +} + +void Editor::setEditingObjects() { + objects_group->setVisible(true); + map_item->setVisible(true); + map_item->setEnabled(false); + collision_item->setVisible(false); +} + +void Editor::setMap(QString map_name) { + if (map_name.isNull()) { + return; + } + map = project->getMap(map_name); + displayMap(); +} + +void Editor::displayMap() { + scene = new QGraphicsScene; + + map_item = new MapPixmapItem(map); + map_item->draw(); + scene->addItem(map_item); + + collision_item = new CollisionPixmapItem(map); + collision_item->draw(); + scene->addItem(collision_item); + + objects_group = new QGraphicsItemGroup; + scene->addItem(objects_group); + + map_item->setVisible(false); + collision_item->setVisible(false); + objects_group->setVisible(false); + + int tw = 16; + int th = 16; + scene->setSceneRect( + -6 * tw, + -6 * th, + map_item->pixmap().width() + 12 * tw, + map_item->pixmap().height() + 12 * th + ); + + displayMetatiles(); + displayCollisionMetatiles(); + displayElevationMetatiles(); + displayMapObjects(); + displayMapConnections(); + displayMapBorder(); +} + +void Editor::displayMetatiles() { + scene_metatiles = new QGraphicsScene; + metatiles_item = new MetatilesPixmapItem(map); + metatiles_item->draw(); + scene_metatiles->addItem(metatiles_item); +} + +void Editor::displayCollisionMetatiles() { + scene_collision_metatiles = new QGraphicsScene; + collision_metatiles_item = new CollisionMetatilesPixmapItem(map); + collision_metatiles_item->draw(); + scene_collision_metatiles->addItem(collision_metatiles_item); +} + +void Editor::displayElevationMetatiles() { + scene_elevation_metatiles = new QGraphicsScene; + elevation_metatiles_item = new ElevationMetatilesPixmapItem(map); + elevation_metatiles_item->draw(); + scene_elevation_metatiles->addItem(elevation_metatiles_item); +} + +void Editor::displayMapObjects() { + for (QGraphicsItem *child : objects_group->childItems()) { + objects_group->removeFromGroup(child); + } + + project->loadObjectPixmaps(map->object_events); + for (int i = 0; i < map->object_events.length(); i++) { + ObjectEvent *object_event = map->object_events.value(i); + DraggablePixmapItem *object = new DraggablePixmapItem(object_event); + objects_group->addToGroup(object); + } + objects_group->setFiltersChildEvents(false); +} + +void Editor::displayMapConnections() { + for (Connection *connection : map->connections) { + if (connection->direction == "dive" || connection->direction == "emerge") { + continue; + } + Map *connected_map = project->getMap(connection->map_name); + QPixmap pixmap = connected_map->renderConnection(*connection); + int offset = connection->offset.toInt(nullptr, 0); + int x, y; + if (connection->direction == "up") { + x = offset * 16; + y = -pixmap.height(); + } else if (connection->direction == "down") { + x = offset * 16; + y = map->getHeight() * 16; + } else if (connection->direction == "left") { + x = -pixmap.width(); + y = offset * 16; + } else if (connection->direction == "right") { + x = map->getWidth() * 16; + y = offset * 16; + } + QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); + item->setX(x); + item->setY(y); + scene->addItem(item); + } +} + +void Editor::displayMapBorder() { + QPixmap pixmap = map->renderBorder(); + for (int y = -6; y < map->getHeight() + 6; y += 2) + for (int x = -6; x < map->getWidth() + 6; x += 2) { + QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); + item->setX(x * 16); + item->setY(y * 16); + item->setZValue(-1); + scene->addItem(item); + } +} + + +void MetatilesPixmapItem::draw() { + setPixmap(map->renderMetatiles()); +} + +void MetatilesPixmapItem::pick(uint tile) { + map->paint_tile = tile; + draw(); +} + +void MetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QPointF pos = event->pos(); + int x = ((int)pos.x()) / 16; + int y = ((int)pos.y()) / 16; + //qDebug() << QString("(%1, %2)").arg(x).arg(y); + int width = pixmap().width() / 16; + int height = pixmap().height() / 16; + if ((x >= 0 && x < width) && (y >=0 && y < height)) { + pick(y * width + x); + } +} +void MetatilesPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + mousePressEvent(event); +} + + +void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) { + if (map) { + QPointF pos = event->pos(); + int x = (int)(pos.x()) / 16; + int y = (int)(pos.y()) / 16; + Block *block = map->getBlock(x, y); + if (block) { + block->tile = map->paint_tile; + map->setBlock(x, y, *block); + } + draw(); + } +} + +void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) { + if (map) { + QPointF pos = event->pos(); + int x = (int)(pos.x()) / 16; + int y = (int)(pos.y()) / 16; + map->floodFill(x, y, map->paint_tile); + draw(); + } +} + +void MapPixmapItem::draw() { + setPixmap(map->render()); +} + +void MapPixmapItem::undo() { + map->undo(); + draw(); +} + +void MapPixmapItem::redo() { + map->redo(); + draw(); +} + +void MapPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + active = true; + if (event->button() == Qt::RightButton) { + right_click = true; + floodFill(event); + } else { + right_click = false; + paint(event); + } +} +void MapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + if (active) { + if (right_click) { + floodFill(event); + } else { + paint(event); + } + } +} +void MapPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + active = false; +} + +void CollisionPixmapItem::draw() { + setPixmap(map->renderCollision()); +} + +void CollisionPixmapItem::paint(QGraphicsSceneMouseEvent *event) { + if (map) { + QPointF pos = event->pos(); + int x = (int)(pos.x()) / 16; + int y = (int)(pos.y()) / 16; + Block *block = map->getBlock(x, y); + if (block) { + if (map->paint_collision >= 0) { + block->collision = map->paint_collision; + } + if (map->paint_elevation >= 0) { + block->elevation = map->paint_elevation; + } + map->setBlock(x, y, *block); + } + draw(); + } +} + +void CollisionPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) { + if (map) { + QPointF pos = event->pos(); + int x = (int)(pos.x()) / 16; + int y = (int)(pos.y()) / 16; + bool collision = map->paint_collision >= 0; + bool elevation = map->paint_elevation >= 0; + if (collision && elevation) { + map->floodFillCollisionElevation(x, y, map->paint_collision, map->paint_elevation); + } else if (collision) { + map->floodFillCollision(x, y, map->paint_collision); + } else if (elevation) { + map->floodFillElevation(x, y, map->paint_elevation); + } + draw(); + } +} + +void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) { + active = true; + last_x = mouse->pos().x() / 16; + last_y = mouse->pos().y() / 16; + qDebug() << event->x_ + ", " + event->y_; +} + +void DraggablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouse) { + if (active) { + int x = mouse->pos().x() / 16; + int y = mouse->pos().y() / 16; + if (x != last_x || y != last_y) { + event->setX(event->x() + x - last_x); + event->setY(event->y() + y - last_y); + update(); + } + } +} + +void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouse) { + active = false; +} diff --git a/editor.h b/editor.h new file mode 100755 index 00000000..54564247 --- /dev/null +++ b/editor.h @@ -0,0 +1,155 @@ +#ifndef EDITOR_H +#define EDITOR_H + +#include +#include +#include + +#include "project.h" + + +class DraggablePixmapItem : public QGraphicsPixmapItem { +public: + DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) { + } + Event *event; + DraggablePixmapItem(Event *event_) : QGraphicsPixmapItem(event_->pixmap) { + event = event_; + update(); + } + bool active; + bool right_click; + int last_x; + int last_y; + void update() { + int x = event->x() * 16; + int y = event->y() * 16; + x -= pixmap().width() / 32 * 16; + y -= pixmap().height() - 16; + setX(x); + setY(y); + setZValue(event->y()); + } + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); +}; + +class MapPixmapItem : public QGraphicsPixmapItem { +public: + MapPixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) { + } + Map *map; + MapPixmapItem(Map *map_) { + map = map_; + } + bool active; + bool right_click; + virtual void paint(QGraphicsSceneMouseEvent*); + virtual void floodFill(QGraphicsSceneMouseEvent*); + virtual void undo(); + virtual void redo(); + virtual void draw(); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseMoveEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); +}; + +class CollisionPixmapItem : public MapPixmapItem { +public: + CollisionPixmapItem(QPixmap pixmap): MapPixmapItem(pixmap) { + } + CollisionPixmapItem(Map *map_): MapPixmapItem(map_) { + } + +public: + virtual void paint(QGraphicsSceneMouseEvent*); + virtual void floodFill(QGraphicsSceneMouseEvent*); + virtual void draw(); +}; + +class MetatilesPixmapItem : public QGraphicsPixmapItem { +public: + MetatilesPixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) { + } + MetatilesPixmapItem(Map *map_) { + map = map_; + } + Map* map; + virtual void pick(uint); + virtual void draw(); +protected: + void mousePressEvent(QGraphicsSceneMouseEvent*); + void mouseReleaseEvent(QGraphicsSceneMouseEvent*); +}; + +class CollisionMetatilesPixmapItem : public MetatilesPixmapItem { +public: + CollisionMetatilesPixmapItem(Map *map_): MetatilesPixmapItem(map_) { + } + virtual void pick(uint collision) { + map->paint_collision = collision; + draw(); + } + virtual void draw() { + setPixmap(map->renderCollisionMetatiles()); + } +}; + +class ElevationMetatilesPixmapItem : public MetatilesPixmapItem { +public: + ElevationMetatilesPixmapItem(Map *map_): MetatilesPixmapItem(map_) { + } + virtual void pick(uint elevation) { + map->paint_elevation = elevation; + draw(); + } + virtual void draw() { + setPixmap(map->renderElevationMetatiles()); + } +}; + + +class Editor +{ +public: + Editor(); +public: + Project *project; + Map *map; + void saveProject(); + void save(); + void undo(); + void redo(); + void setMap(QString map_name); + void displayMap(); + void displayMetatiles(); + void displayCollisionMetatiles(); + void displayElevationMetatiles(); + void displayMapObjects(); + void displayMapConnections(); + void displayMapBorder(); + + void setEditingMap(); + void setEditingCollision(); + void setEditingObjects(); + + QGraphicsScene *scene; + QGraphicsPixmapItem *current_view; + MapPixmapItem *map_item; + CollisionPixmapItem *collision_item; + QGraphicsItemGroup *objects_group; + + QGraphicsScene *scene_metatiles; + QGraphicsScene *scene_collision_metatiles; + QGraphicsScene *scene_elevation_metatiles; + MetatilesPixmapItem *metatiles_item; + CollisionMetatilesPixmapItem *collision_metatiles_item; + ElevationMetatilesPixmapItem *elevation_metatiles_item; +}; + +#endif // EDITOR_H diff --git a/event.cpp b/event.cpp new file mode 100755 index 00000000..11ca06cd --- /dev/null +++ b/event.cpp @@ -0,0 +1,52 @@ +#include "event.h" + +Event::Event() +{ + +} + +ObjectEvent::ObjectEvent() +{ + +} + +Warp::Warp() +{ + +} + +CoordEvent::CoordEvent() +{ + +} + +BGEvent::BGEvent() +{ + +} + +Sign::Sign() +{ + +} + +Sign::Sign(const BGEvent &bg) +{ + x_ = bg.x_; + y_ = bg.y_; + elevation_ = bg.elevation_; + type = bg.type; +} + +HiddenItem::HiddenItem() +{ + +} + +HiddenItem::HiddenItem(const BGEvent &bg) +{ + x_ = bg.x_; + y_ = bg.y_; + elevation_ = bg.elevation_; + type = bg.type; +} diff --git a/event.h b/event.h new file mode 100755 index 00000000..3b1dc635 --- /dev/null +++ b/event.h @@ -0,0 +1,100 @@ +#ifndef EVENT_H +#define EVENT_H + +#include +#include + +class Event +{ +public: + Event(); + +public: + int x() { + return x_.toInt(nullptr, 0); + } + int y() { + return y_.toInt(nullptr, 0); + } + int elevation() { + return elevation_.toInt(nullptr, 0); + } + void setX(int x) { + x_ = QString("%1").arg(x); + } + void setY(int y) { + y_ = QString("%1").arg(y); + } + + QString x_; + QString y_; + QString elevation_; + QPixmap pixmap; +}; + +class ObjectEvent : public Event { +public: + ObjectEvent(); + +public: + QString sprite; + QString replacement; // ???? + QString behavior; + QString radius_x; + QString radius_y; + QString property; + QString sight_radius; + QString script_label; + QString event_flag; +}; + +class Warp : public Event { +public: + Warp(); + +public: + QString destination_warp; + QString destination_map; +}; + +class CoordEvent : public Event { +public: + CoordEvent(); + +public: + QString unknown1; + QString unknown2; + QString unknown3; + QString unknown4; + QString script_label; +}; + +class BGEvent : public Event { +public: + BGEvent(); +public: + bool is_item() { + return type.toInt(nullptr, 0) >= 5; + } + QString type; +}; + +class Sign : public BGEvent { +public: + Sign(); + Sign(const BGEvent&); +public: + QString script_label; +}; + +class HiddenItem : public BGEvent { +public: + HiddenItem(); + HiddenItem(const BGEvent&); +public: + QString item; + QString unknown5; + QString unknown6; +}; + +#endif // EVENT_H diff --git a/main.cpp b/main.cpp new file mode 100755 index 00000000..aab39bb8 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100755 index 00000000..09695706 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,370 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "project.h" + +#include +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + QCoreApplication::setOrganizationName("pret"); + QCoreApplication::setApplicationName("pretmap"); + + editor = new Editor; + + new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z), this, SLOT(redo())); + ui->setupUi(this); + + QSettings settings; + QString key = "recent_projects"; + if (settings.contains(key)) { + QString default_dir = settings.value(key).toStringList().last(); + openProject(default_dir); + } +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::openProject(QString dir) { + bool already_open = (editor->project != NULL) && (editor->project->root == dir); + if (!already_open) { + editor->project = new Project; + editor->project->root = dir; + populateMapList(); + setMap(getDefaultMap()); + } else { + populateMapList(); + } +} + +QString MainWindow::getDefaultMap() { + QSettings settings; + QString key = "project:" + editor->project->root; + if (settings.contains(key)) { + QMap qmap = settings.value(key).toMap(); + if (qmap.contains("recent_map")) { + QString map_name = qmap.value("recent_map").toString(); + return map_name; + } + } + // Failing that, just get the first map in the list. + for (int i = 0; i < editor->project->groupedMapNames->length(); i++) { + QStringList *list = editor->project->groupedMapNames->value(i); + if (list->length()) { + return list->value(0); + } + } + return NULL; +} + +QString MainWindow::getExistingDirectory(QString dir) { + return QFileDialog::getExistingDirectory(this, "Open Directory", dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); +} + +void MainWindow::on_action_Open_Project_triggered() +{ + QSettings settings; + QString key = "recent_projects"; + QString recent = "."; + if (settings.contains(key)) { + recent = settings.value(key).toStringList().last(); + } + QString dir = getExistingDirectory(recent); + if (!dir.isEmpty()) { + QStringList recents; + if (settings.contains(key)) { + recents = settings.value(key).toStringList(); + } + recents.removeAll(dir); + recents.append(dir); + settings.setValue(key, recents); + + openProject(dir); + } +} + +void MainWindow::setMap(QString map_name) { + if (map_name.isNull()) { + return; + } + editor->setMap(map_name); + + if (ui->tabWidget->currentIndex() == 1) { + editor->setEditingObjects(); + } else { + if (ui->tabWidget_2->currentIndex() == 1) { + editor->setEditingCollision(); + } else { + editor->setEditingMap(); + } + } + + ui->graphicsView_Map->setScene(editor->scene); + ui->graphicsView_Map->setSceneRect(editor->scene->sceneRect()); + ui->graphicsView_Map->setFixedSize(editor->scene->width() + 2, editor->scene->height() + 2); + + ui->graphicsView_Objects_Map->setScene(editor->scene); + ui->graphicsView_Objects_Map->setSceneRect(editor->scene->sceneRect()); + ui->graphicsView_Objects_Map->setFixedSize(editor->scene->width() + 2, editor->scene->height() + 2); + + ui->graphicsView_Metatiles->setScene(editor->scene_metatiles); + //ui->graphicsView_Metatiles->setSceneRect(editor->scene_metatiles->sceneRect()); + ui->graphicsView_Metatiles->setFixedSize(editor->metatiles_item->pixmap().width() + 2, editor->metatiles_item->pixmap().height() + 2); + + ui->graphicsView_Collision->setScene(editor->scene_collision_metatiles); + //ui->graphicsView_Collision->setSceneRect(editor->scene_collision_metatiles->sceneRect()); + ui->graphicsView_Collision->setFixedSize(editor->collision_metatiles_item->pixmap().width() + 2, editor->collision_metatiles_item->pixmap().height() + 2); + + ui->graphicsView_Elevation->setScene(editor->scene_elevation_metatiles); + //ui->graphicsView_Elevation->setSceneRect(editor->scene_elevation_metatiles->sceneRect()); + ui->graphicsView_Elevation->setFixedSize(editor->elevation_metatiles_item->pixmap().width() + 2, editor->elevation_metatiles_item->pixmap().height() + 2); + + displayMapProperties(); + + setRecentMap(map_name); + updateMapList(); +} + +void MainWindow::setRecentMap(QString map_name) { + QSettings settings; + QString key = "project:" + editor->project->root; + QMap qmap; + if (settings.contains(key)) { + qmap = settings.value(key).toMap(); + } + qmap.insert("recent_map", map_name); + settings.setValue(key, qmap); +} + +void MainWindow::displayMapProperties() { + Map *map = editor->map; + Project *project = editor->project; + + QStringList songs = project->getSongNames(); + ui->comboBox_Song->clear(); + ui->comboBox_Song->addItems(songs); + QString song = map->song; + if (!songs.contains(song)) { + song = project->getSongName(song.toInt()); + } + ui->comboBox_Song->setCurrentText(song); + + ui->comboBox_Location->clear(); + ui->comboBox_Location->addItems(project->getLocations()); + ui->comboBox_Location->setCurrentText(map->location); + + ui->comboBox_Visibility->clear(); + ui->comboBox_Visibility->addItems(project->getVisibilities()); + ui->comboBox_Visibility->setCurrentText(map->visibility); + + ui->comboBox_Weather->clear(); + ui->comboBox_Weather->addItems(project->getWeathers()); + ui->comboBox_Weather->setCurrentText(map->weather); + + ui->comboBox_Type->clear(); + ui->comboBox_Type->addItems(project->getMapTypes()); + ui->comboBox_Type->setCurrentText(map->type); + + ui->comboBox_BattleScene->clear(); + ui->comboBox_BattleScene->addItems(project->getBattleScenes()); + ui->comboBox_BattleScene->setCurrentText(map->battle_scene); + + ui->checkBox_ShowLocation->setChecked(map->show_location.toInt() > 0 || map->show_location == "TRUE"); +} + +void MainWindow::on_comboBox_Song_activated(const QString &song) +{ + editor->map->song = song; +} + +void MainWindow::on_comboBox_Location_activated(const QString &location) +{ + editor->map->location = location; +} + +void MainWindow::on_comboBox_Visibility_activated(const QString &visibility) +{ + editor->map->visibility = visibility; +} + +void MainWindow::on_comboBox_Weather_activated(const QString &weather) +{ + editor->map->weather = weather; +} + +void MainWindow::on_comboBox_Type_activated(const QString &type) +{ + editor->map->type = type; +} + +void MainWindow::on_comboBox_BattleScene_activated(const QString &battle_scene) +{ + editor->map->battle_scene = battle_scene; +} + +void MainWindow::on_checkBox_ShowLocation_clicked(bool checked) +{ + if (checked) { + editor->map->show_location = "TRUE"; + } else { + editor->map->show_location = "FALSE"; + } +} + + +void MainWindow::populateMapList() { + Project *project = editor->project; + + QIcon mapFolderIcon; + mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off); + mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On); + + QIcon folderIcon; + folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off); + + QIcon mapIcon; + mapIcon.addFile(QStringLiteral(":/icons/map.ico"), QSize(), QIcon::Normal, QIcon::Off); + mapIcon.addFile(QStringLiteral(":/icons/image.ico"), QSize(), QIcon::Normal, QIcon::On); + + QStandardItemModel *model = new QStandardItemModel; + + QStandardItem *entry = new QStandardItem; + entry->setText(project->getProjectTitle()); + entry->setIcon(folderIcon); + entry->setEditable(false); + model->appendRow(entry); + + QStandardItem *maps = new QStandardItem; + maps->setText("maps"); + maps->setIcon(folderIcon); + maps->setEditable(false); + entry->appendRow(maps); + + project->readMapGroups(); + for (int i = 0; i < project->groupNames->length(); i++) { + QString group_name = project->groupNames->value(i); + QStandardItem *group = new QStandardItem; + group->setText(group_name); + group->setIcon(mapFolderIcon); + group->setEditable(false); + maps->appendRow(group); + QStringList *names = project->groupedMapNames->value(i); + for (int j = 0; j < names->length(); j++) { + QString map_name = names->value(j); + QStandardItem *map = new QStandardItem; + map->setText(QString("[%1.%2] ").arg(i).arg(j, 2, 10, QLatin1Char('0')) + map_name); + map->setIcon(mapIcon); + map->setEditable(false); + map->setData(map_name, Qt::UserRole); + group->appendRow(map); + //ui->mapList->setExpanded(model->indexFromItem(map), false); // redundant + } + } + + ui->mapList->setModel(model); + ui->mapList->setUpdatesEnabled(true); + ui->mapList->expandToDepth(2); + ui->mapList->repaint(); +} + +void MainWindow::on_mapList_activated(const QModelIndex &index) +{ + QVariant data = index.data(Qt::UserRole); + if (!data.isNull()) { + setMap(data.toString()); + } + updateMapList(); +} + +void MainWindow::markAllEdited(QAbstractItemModel *model) { + QList list; + list.append(QModelIndex()); + while (list.length()) { + QModelIndex parent = list.takeFirst(); + for (int i = 0; i < model->rowCount(parent); i++) { + QModelIndex index = model->index(i, 0, parent); + if (model->hasChildren(index)) { + list.append(index); + } + markEdited(index); + } + } +} + +void MainWindow::markEdited(QModelIndex index) { + QVariant data = index.data(Qt::UserRole); + if (!data.isNull()) { + QString map_name = data.toString(); + if (editor->project) { + if (editor->project->map_cache->contains(map_name)) { + // Just mark anything that's been opened for now. + // TODO if (project->getMap()->saved) + ui->mapList->setExpanded(index, true); + } + } + } +} + +void MainWindow::updateMapList() { + QAbstractItemModel *model = ui->mapList->model(); + markAllEdited(model); +} + +void MainWindow::on_action_Save_Project_triggered() +{ + editor->saveProject(); + updateMapList(); +} + +void MainWindow::undo() { + editor->undo(); +} + +void MainWindow::redo() { + editor->redo(); +} + +void MainWindow::on_action_Save_triggered() { + editor->save(); +} + +void MainWindow::on_tabWidget_2_currentChanged(int index) +{ + if (index == 0) { + editor->setEditingMap(); + } else if (index == 1) { + editor->setEditingCollision(); + } +} + +void MainWindow::on_action_Exit_triggered() +{ + QApplication::quit(); +} + +void MainWindow::on_tabWidget_currentChanged(int index) +{ + if (index == 0) { + on_tabWidget_2_currentChanged(ui->tabWidget_2->currentIndex()); + } else if (index == 1) { + editor->setEditingObjects(); + } +} + +void MainWindow::on_actionUndo_triggered() +{ + undo(); +} + +void MainWindow::on_actionRedo_triggered() +{ + redo(); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100755 index 00000000..0d79638a --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,69 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include "project.h" +#include "map.h" +#include "editor.h" + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void on_action_Open_Project_triggered(); + void on_mapList_activated(const QModelIndex &index); + void on_action_Save_Project_triggered(); + + void undo(); + void redo(); + + void on_action_Save_triggered(); + void on_tabWidget_2_currentChanged(int index); + void on_action_Exit_triggered(); + void on_comboBox_Song_activated(const QString &arg1); + void on_comboBox_Location_activated(const QString &arg1); + void on_comboBox_Visibility_activated(const QString &arg1); + void on_comboBox_Weather_activated(const QString &arg1); + void on_comboBox_Type_activated(const QString &arg1); + void on_comboBox_BattleScene_activated(const QString &arg1); + void on_checkBox_ShowLocation_clicked(bool checked); + + void on_tabWidget_currentChanged(int index); + + void on_actionUndo_triggered(); + + void on_actionRedo_triggered(); + +private: + Ui::MainWindow *ui; + Editor *editor; + void setMap(QString); + void populateMapList(); + QString getExistingDirectory(QString); + void openProject(QString dir); + QString getDefaultMap(); + void setRecentMap(QString map_name); + + void markAllEdited(QAbstractItemModel *model); + void markEdited(QModelIndex index); + void updateMapList(); + + void displayMapProperties(); +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100755 index 00000000..adb7c468 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,938 @@ + + + MainWindow + + + + 0 + 0 + 1019 + 666 + + + + + 0 + 0 + + + + MainWindow + + + + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + 100 + 0 + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectItems + + + false + + + + + true + + + + 1 + 0 + + + + 1 + + + false + + + false + + + + + :/icons/map.ico:/icons/map.ico + + + Map + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + true + + + + + 0 + 0 + 571 + 564 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + + 0 + 0 + + + + false + + + + + + + + + true + + + + 0 + 0 + + + + + 156 + 0 + + + + 1 + + + + + 0 + 0 + + + + Blocks + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + + true + + + + 0 + 0 + 81 + 28 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + + + + + + + + + + true + + + + 0 + 0 + + + + Collision + + + + + 20 + 60 + 111 + 20 + + + + Qt::Horizontal + + + + + + 0 + 80 + 151 + 101 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 47 + 13 + + + + Elevation + + + + + + 10 + 30 + 131 + 61 + + + + + + + + 0 + 0 + 151 + 61 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 47 + 13 + + + + Collision + + + + + + 40 + 30 + 66 + 18 + + + + + + + + + + + + + true + + + Objects + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + true + + + + + 0 + 0 + 571 + 564 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Horizontal + + + + 166 + 16 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + Qt::Vertical + + + + 16 + 166 + + + + + + + + + 0 + 0 + + + + + + + + + + true + + + + 0 + 0 + + + + + 156 + 0 + + + + + + + Selected + + + + + + + + 16777215 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 0 + 0 + 31 + 31 + + + + New + + + + + + 100 + 0 + 31 + 31 + + + + Delete + + + + + + + + + + + + + Attributes + + + + + 10 + 10 + 301 + 251 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 20 + 30 + 47 + 21 + + + + Song + + + + + + 20 + 60 + 47 + 21 + + + + Location + + + + + + 20 + 90 + 47 + 21 + + + + Visibility + + + + + + 20 + 120 + 47 + 21 + + + + Weather + + + + + + 20 + 150 + 47 + 21 + + + + Type + + + + + + 20 + 180 + 101 + 21 + + + + Show location name + + + + + + 20 + 210 + 81 + 21 + + + + Battle scene + + + + + + 80 + 60 + 211 + 22 + + + + + + + 80 + 90 + 211 + 22 + + + + + + + 80 + 30 + 211 + 22 + + + + + + + 80 + 120 + 211 + 22 + + + + + + + 80 + 150 + 211 + 22 + + + + + + + 90 + 210 + 201 + 22 + + + + + + + 130 + 180 + 161 + 21 + + + + + + + + + + 0 + 0 + 47 + 13 + + + + Header + + + + + + + + + + + + + 0 + 0 + 1019 + 21 + + + + + File + + + + + + + + + + Edit + + + + + + + + + + TopToolBarArea + + + false + + + + + + Save All + + + Ctrl+Shift+S + + + + + Exit + + + Ctrl+Q + + + + + Open Project... + + + Ctrl+O + + + + + Save + + + Ctrl+S + + + + + Undo + + + Ctrl+Z + + + + + Redo + + + + 50 + false + + + + Ctrl+Y + + + + + + + + + diff --git a/map.cpp b/map.cpp new file mode 100755 index 00000000..941838ff --- /dev/null +++ b/map.cpp @@ -0,0 +1,600 @@ +#include "map.h" + +#include +#include +#include + +Map::Map(QObject *parent) : QObject(parent) +{ + cached_blockdata = new Blockdata; + cached_collision = new Blockdata; + cached_border = new Blockdata; + paint_tile = 1; + paint_collision = 0; + paint_elevation = 3; +} + +int Map::getWidth() { + return width.toInt(nullptr, 0); +} + +int Map::getHeight() { + return height.toInt(nullptr, 0); +} + +Tileset* Map::getBlockTileset(uint metatile_index) { + uint primary_size = 0x200;//tileset_primary->metatiles->length(); + if (metatile_index < primary_size) { + return tileset_primary; + } else { + return tileset_secondary; + } +} + +QImage Map::getMetatileTile(uint tile) { + uint primary_size = 0x200;//tileset_primary->metatiles->length(); + if (tile < primary_size) { + return tileset_primary->tiles->value(tile); + } else { + return tileset_secondary->tiles->value(tile - primary_size); + } +} + +Metatile* Map::getMetatile(uint index) { + uint primary_size = 0x200;//tileset_primary->metatiles->length(); + if (index < primary_size) { + return tileset_primary->metatiles->value(index); + } else { + //qDebug() << QString("secondary tileset: %1").arg(index - primary_size, 0, 16); + return tileset_secondary->metatiles->value(index - primary_size); + } +} + +QImage Map::getCollisionMetatileImage(Block block) { + return getCollisionMetatileImage(block.collision); +} + +QImage Map::getCollisionMetatileImage(int collision) { + QImage metatile_image(16, 16, QImage::Format_RGBA8888); + QColor color; + if (collision == 0) { + color.setGreen(0xff); + } else if (collision == 1) { + color.setRed(0xff); + } else if (collision == 2) { + color.setBlue(0xff); + } else if (collision == 3) { + // black + } + metatile_image.fill(color); + return metatile_image; +} + +QImage Map::getElevationMetatileImage(Block block) { + return getElevationMetatileImage(block.elevation); +} + +QImage Map::getElevationMetatileImage(int elevation) { + QImage metatile_image(16, 16, QImage::Format_RGBA8888); + QColor color; + if (elevation < 15) { + uint saturation = (elevation + 1) * 16 + 15; + color.setGreen(saturation); + color.setRed(saturation); + color.setBlue(saturation); + } else { + color.setGreen(0xd0); + color.setBlue(0xd0); + color.setRed(0); + } + metatile_image.fill(color); + //QPainter painter(&metatile_image); + //painter.end(); + return metatile_image; +} + +QImage Map::getMetatileImage(uint tile) { + + QImage metatile_image(16, 16, QImage::Format_RGBA8888); + + Metatile* metatile = getMetatile(tile); + if (metatile == NULL) { + metatile_image.fill(0xffffffff); + return metatile_image; + } + + Tileset* blockTileset = getBlockTileset(tile); + + for (int layer = 0; layer < 2; layer++) + for (int y = 0; y < 2; y++) + for (int x = 0; x < 2; x++) { + //qDebug() << QString("x=%1 y=%2 layer=%3").arg(x).arg(y).arg(layer); + Tile tile = metatile->tiles->value((y * 2) + x + (layer * 4)); + QImage tile_image = getMetatileTile(tile.tile); + QList palette = blockTileset->palettes->value(tile.palette); + for (int j = 0; j < palette.length(); j++) { + tile_image.setColor(j, palette.value(j)); + } + //QVector vector = palette.toVector(); + //tile_image.setColorTable(vector); + if (layer > 0) { + QColor color(tile_image.color(15)); + color.setAlpha(0); + tile_image.setColor(15, color.rgba()); + } + QPainter metatile_painter(&metatile_image); + QPoint origin = QPoint(x*8, y*8); + metatile_painter.drawImage(origin, tile_image.mirrored(tile.xflip == 1, tile.yflip == 1)); + metatile_painter.end(); + } + + return metatile_image; +} + +bool Map::blockChanged(int i, Blockdata *cache) { + if (cache->blocks->length() <= i) { + return true; + } + return blockdata->blocks->value(i) != cache->blocks->value(i); +} + +void Map::cacheBorder() { + cached_border = new Blockdata; + for (int i = 0; i < border->blocks->length(); i++) { + Block block = border->blocks->value(i); + cached_border->blocks->append(block); + } +} + +void Map::cacheBlockdata() { + cached_blockdata = new Blockdata; + for (int i = 0; i < blockdata->blocks->length(); i++) { + Block block = blockdata->blocks->value(i); + cached_blockdata->blocks->append(block); + } +} + +void Map::cacheCollision() { + cached_collision = new Blockdata; + for (int i = 0; i < blockdata->blocks->length(); i++) { + Block block = blockdata->blocks->value(i); + cached_collision->blocks->append(block); + } +} + +QPixmap Map::renderCollision() { + bool changed_any = false; + int width_ = getWidth(); + int height_ = getHeight(); + if ( + collision_image.isNull() + || collision_image.width() != width_ * 16 + || collision_image.height() != height_ * 16 + ) { + collision_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + changed_any = true; + } + QPainter painter(&collision_image); + for (int i = 0; i < blockdata->blocks->length(); i++) { + if (!blockChanged(i, cached_collision)) { + continue; + } + changed_any = true; + Block block = blockdata->blocks->value(i); + QImage metatile_image = getMetatileImage(block.tile); + QImage collision_metatile_image = getCollisionMetatileImage(block); + QImage elevation_metatile_image = getElevationMetatileImage(block); + int map_y = i / width_; + int map_x = i % width_; + QPoint metatile_origin = QPoint(map_x * 16, map_y * 16); + painter.setOpacity(1); + painter.drawImage(metatile_origin, metatile_image); + + painter.save(); + if (block.elevation == 15) { + painter.setOpacity(0.5); + } else if (block.elevation == 0) { + painter.setOpacity(0); + } else { + painter.setOpacity(1);//(block.elevation / 16.0) * 0.8); + painter.setCompositionMode(QPainter::CompositionMode_Overlay); + } + painter.drawImage(metatile_origin, elevation_metatile_image); + painter.restore(); + + painter.save(); + if (block.collision == 0) { + painter.setOpacity(0.1); + } else { + painter.setOpacity(0.4); + } + painter.drawImage(metatile_origin, collision_metatile_image); + painter.restore(); + + painter.save(); + painter.setOpacity(0.6); + painter.setPen(QColor(255, 255, 255, 192)); + painter.setFont(QFont("Helvetica", 8)); + painter.drawText(QPoint(metatile_origin.x(), metatile_origin.y() + 8), QString("%1").arg(block.elevation)); + painter.restore(); + } + painter.end(); + cacheCollision(); + if (changed_any) { + collision_pixmap = collision_pixmap.fromImage(collision_image); + } + return collision_pixmap; +} + +QPixmap Map::render() { + bool changed_any = false; + int width_ = getWidth(); + int height_ = getHeight(); + if ( + image.isNull() + || image.width() != width_ * 16 + || image.height() != height_ * 16 + ) { + image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + changed_any = true; + } + QPainter painter(&image); + for (int i = 0; i < blockdata->blocks->length(); i++) { + if (!blockChanged(i, cached_blockdata)) { + continue; + } + changed_any = true; + Block block = blockdata->blocks->value(i); + QImage metatile_image = getMetatileImage(block.tile); + int map_y = i / width_; + int map_x = i % width_; + QPoint metatile_origin = QPoint(map_x * 16, map_y * 16); + painter.drawImage(metatile_origin, metatile_image); + } + painter.end(); + if (changed_any) { + cacheBlockdata(); + pixmap = pixmap.fromImage(image); + } + return pixmap; +} + +QPixmap Map::renderBorder() { + bool changed_any = false; + int width_ = 2; + int height_ = 2; + if (border_image.isNull()) { + border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + changed_any = true; + } + QPainter painter(&border_image); + for (int i = 0; i < border->blocks->length(); i++) { + if (!blockChanged(i, cached_border)) { + continue; + } + changed_any = true; + Block block = border->blocks->value(i); + QImage metatile_image = getMetatileImage(block.tile); + int map_y = i / width_; + int map_x = i % width_; + painter.drawImage(QPoint(map_x * 16, map_y * 16), metatile_image); + } + painter.end(); + if (changed_any) { + cacheBorder(); + border_pixmap = border_pixmap.fromImage(border_image); + } + return border_pixmap; +} + +QPixmap Map::renderConnection(Connection connection) { + render(); + int x, y, w, h; + if (connection.direction == "up") { + x = 0; + y = getHeight() - 6; + w = getWidth(); + h = 6; + } else if (connection.direction == "down") { + x = 0; + y = 0; + w = getWidth(); + h = 6; + } else if (connection.direction == "left") { + x = getWidth() - 6; + y = 0; + w = 6; + h = getHeight(); + } else if (connection.direction == "right") { + x = 0; + y = 0; + w = 6; + h = getHeight(); + } else { + // this should not happen + x = 0; + y = 0; + w = getWidth(); + h = getHeight(); + } + QImage connection_image = image.copy(x * 16, y * 16, w * 16, h * 16); + //connection_image = connection_image.convertToFormat(QImage::Format_Grayscale8); + return QPixmap::fromImage(connection_image); +} + +QPixmap Map::renderCollisionMetatiles() { + int length_ = 4; + int height_ = 1; + int width_ = length_ / height_; + QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + QPainter painter(&image); + for (int i = 0; i < length_; i++) { + int y = i / width_; + int x = i % width_; + QPoint origin(x * 16, y * 16); + QImage metatile_image = getCollisionMetatileImage(i); + painter.drawImage(origin, metatile_image); + } + drawSelection(paint_collision, width_, &painter); + painter.end(); + return QPixmap::fromImage(image); +} + +QPixmap Map::renderElevationMetatiles() { + int length_ = 16; + int height_ = 2; + int width_ = length_ / height_; + QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + QPainter painter(&image); + for (int i = 0; i < length_; i++) { + int y = i / width_; + int x = i % width_; + QPoint origin(x * 16, y * 16); + QImage metatile_image = getElevationMetatileImage(i); + painter.drawImage(origin, metatile_image); + } + drawSelection(paint_elevation, width_, &painter); + painter.end(); + return QPixmap::fromImage(image); +} + +void Map::drawSelection(int i, int w, QPainter *painter) { + int x = i % w; + int y = i / w; + painter->save(); + painter->setPen(QColor(0xff, 0xff, 0xff)); + painter->drawRect(x * 16, y * 16, 15, 15); + painter->setPen(QColor(0, 0, 0)); + painter->drawRect(x * 16 - 1, y * 16 - 1, 17, 17); + painter->drawRect(x * 16 + 1, y * 16 + 1, 13, 13); + painter->restore(); +} + +QPixmap Map::renderMetatiles() { + int primary_length = tileset_primary->metatiles->length(); + int length_ = primary_length + tileset_secondary->metatiles->length(); + int width_ = 8; + int height_ = length_ / width_; + QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888); + QPainter painter(&image); + for (int i = 0; i < length_; i++) { + uint tile = i; + if (i >= primary_length) { + tile += 0x200 - primary_length; + } + QImage metatile_image = getMetatileImage(tile); + int map_y = i / width_; + int map_x = i % width_; + QPoint metatile_origin = QPoint(map_x * 16, map_y * 16); + painter.drawImage(metatile_origin, metatile_image); + } + + drawSelection(paint_tile, width_, &painter); + + painter.end(); + return QPixmap::fromImage(image); +} + +Block* Map::getBlock(int x, int y) { + if (x >= 0 && x < getWidth()) + if (y >= 0 && y < getHeight()) { + int i = y * getWidth() + x; + return new Block(blockdata->blocks->value(i)); + } + return NULL; +} + +void Map::_setBlock(int x, int y, Block block) { + int i = y * getWidth() + x; + blockdata->blocks->replace(i, block); +} + +void Map::_floodFill(int x, int y, uint tile) { + QList todo; + todo.append(QPoint(x, y)); + while (todo.length()) { + QPoint point = todo.takeAt(0); + x = point.x(); + y = point.y(); + Block *block = getBlock(x, y); + if (block == NULL) { + continue; + } + uint old_tile = block->tile; + if (old_tile == tile) { + continue; + } + block->tile = tile; + _setBlock(x, y, *block); + if ((block = getBlock(x + 1, y)) && block->tile == old_tile) { + todo.append(QPoint(x + 1, y)); + } + if ((block = getBlock(x - 1, y)) && block->tile == old_tile) { + todo.append(QPoint(x - 1, y)); + } + if ((block = getBlock(x, y + 1)) && block->tile == old_tile) { + todo.append(QPoint(x, y + 1)); + } + if ((block = getBlock(x, y - 1)) && block->tile == old_tile) { + todo.append(QPoint(x, y - 1)); + } + } +} + +void Map::_floodFillCollision(int x, int y, uint collision) { + QList todo; + todo.append(QPoint(x, y)); + while (todo.length()) { + QPoint point = todo.takeAt(0); + x = point.x(); + y = point.y(); + Block *block = getBlock(x, y); + if (block == NULL) { + continue; + } + uint old_coll = block->collision; + if (old_coll == collision) { + continue; + } + block->collision = collision; + _setBlock(x, y, *block); + if ((block = getBlock(x + 1, y)) && block->collision == old_coll) { + todo.append(QPoint(x + 1, y)); + } + if ((block = getBlock(x - 1, y)) && block->collision == old_coll) { + todo.append(QPoint(x - 1, y)); + } + if ((block = getBlock(x, y + 1)) && block->collision == old_coll) { + todo.append(QPoint(x, y + 1)); + } + if ((block = getBlock(x, y - 1)) && block->collision == old_coll) { + todo.append(QPoint(x, y - 1)); + } + } +} + +void Map::_floodFillElevation(int x, int y, uint elevation) { + QList todo; + todo.append(QPoint(x, y)); + while (todo.length()) { + QPoint point = todo.takeAt(0); + x = point.x(); + y = point.y(); + Block *block = getBlock(x, y); + if (block == NULL) { + continue; + } + uint old_z = block->elevation; + if (old_z == elevation) { + continue; + } + Block block_(*block); + block_.elevation = elevation; + _setBlock(x, y, block_); + if ((block = getBlock(x + 1, y)) && block->elevation == old_z) { + todo.append(QPoint(x + 1, y)); + } + if ((block = getBlock(x - 1, y)) && block->elevation == old_z) { + todo.append(QPoint(x - 1, y)); + } + if ((block = getBlock(x, y + 1)) && block->elevation == old_z) { + todo.append(QPoint(x, y + 1)); + } + if ((block = getBlock(x, y - 1)) && block->elevation == old_z) { + todo.append(QPoint(x, y - 1)); + } + } +} + +void Map::_floodFillCollisionElevation(int x, int y, uint collision, uint elevation) { + QList todo; + todo.append(QPoint(x, y)); + while (todo.length()) { + QPoint point = todo.takeAt(0); + x = point.x(); + y = point.y(); + Block *block = getBlock(x, y); + if (block == NULL) { + continue; + } + uint old_coll = block->collision; + uint old_elev = block->elevation; + if (old_coll == collision && old_elev == elevation) { + continue; + } + block->collision = collision; + block->elevation = elevation; + _setBlock(x, y, *block); + if ((block = getBlock(x + 1, y)) && block->collision == old_coll && block->elevation == old_elev) { + todo.append(QPoint(x + 1, y)); + } + if ((block = getBlock(x - 1, y)) && block->collision == old_coll && block->elevation == old_elev) { + todo.append(QPoint(x - 1, y)); + } + if ((block = getBlock(x, y + 1)) && block->collision == old_coll && block->elevation == old_elev) { + todo.append(QPoint(x, y + 1)); + } + if ((block = getBlock(x, y - 1)) && block->collision == old_coll && block->elevation == old_elev) { + todo.append(QPoint(x, y - 1)); + } + } +} + + +void Map::undo() { + Blockdata *commit = history.pop(); + if (commit != NULL) { + blockdata->copyFrom(commit); + } +} + +void Map::redo() { + Blockdata *commit = history.next(); + if (commit != NULL) { + blockdata->copyFrom(commit); + } +} + +void Map::commit() { + Blockdata* commit = blockdata->copy(); + history.push(commit); +} + +void Map::setBlock(int x, int y, Block block) { + Block *old_block = getBlock(x, y); + if (old_block && (*old_block) != block) { + _setBlock(x, y, block); + commit(); + } +} + +void Map::floodFill(int x, int y, uint tile) { + Block *block = getBlock(x, y); + if (block && block->tile != tile) { + _floodFill(x, y, tile); + commit(); + } +} + +void Map::floodFillCollision(int x, int y, uint collision) { + Block *block = getBlock(x, y); + if (block && block->collision != collision) { + _floodFillCollision(x, y, collision); + commit(); + } +} + +void Map::floodFillElevation(int x, int y, uint elevation) { + Block *block = getBlock(x, y); + if (block && block->elevation != elevation) { + _floodFillElevation(x, y, elevation); + commit(); + } +} +void Map::floodFillCollisionElevation(int x, int y, uint collision, uint elevation) { + Block *block = getBlock(x, y); + if (block && (block->collision != collision || block->elevation != elevation)) { + _floodFillCollisionElevation(x, y, collision, elevation); + commit(); + } +} diff --git a/map.h b/map.h new file mode 100755 index 00000000..aad182cb --- /dev/null +++ b/map.h @@ -0,0 +1,165 @@ +#ifndef MAP_H +#define MAP_H + +#include "tileset.h" +#include "blockdata.h" +#include "event.h" + +#include +#include +#include + + +template +class History { +public: + QList history; + int head; + + History() { + head = -1; + } + T pop() { + if (head > 0) { + return history.at(--head); + } + return NULL; + } + T next() { + if (head + 1 < history.length()) { + return history.at(++head); + } + return NULL; + } + void push(T commit) { + while (head + 1 < history.length()) { + history.removeLast(); + } + history.append(commit); + head++; + } +}; + +class Connection { +public: + Connection() { + } +public: + QString direction; + QString offset; + QString map_name; +}; + +class Map : public QObject +{ + Q_OBJECT +public: + explicit Map(QObject *parent = 0); + +public: + QString name; + QString attributes_label; + QString events_label; + QString scripts_label; + QString connections_label; + QString song; + QString index; + QString location; + QString visibility; + QString weather; + QString type; + QString unknown; + QString show_location; + QString battle_scene; + + QString width; + QString height; + QString border_label; + QString blockdata_label; + QString tileset_primary_label; + QString tileset_secondary_label; + + Tileset *tileset_primary; + Tileset *tileset_secondary; + + Blockdata* blockdata; + +public: + int getWidth(); + int getHeight(); + Tileset* getBlockTileset(uint); + Metatile* getMetatile(uint); + QImage getMetatileImage(uint); + QImage getMetatileTile(uint); + QPixmap render(); + QPixmap renderMetatiles(); + + QPixmap renderCollision(); + QImage collision_image; + QPixmap collision_pixmap; + QImage getCollisionMetatileImage(Block); + QImage getElevationMetatileImage(Block); + QImage getCollisionMetatileImage(int); + QImage getElevationMetatileImage(int); + + QPixmap renderCollisionMetatiles(); + QPixmap renderElevationMetatiles(); + void drawSelection(int i, int w, QPainter *painter); + + bool blockChanged(int, Blockdata*); + Blockdata* cached_blockdata; + void cacheBlockdata(); + Blockdata* cached_collision; + void cacheCollision(); + QImage image; + QPixmap pixmap; + QList metatile_images; + int paint_tile; + int paint_collision; + int paint_elevation; + + Block *getBlock(int x, int y); + void setBlock(int x, int y, Block block); + void _setBlock(int x, int y, Block block); + + void floodFill(int x, int y, uint tile); + void _floodFill(int x, int y, uint tile); + void floodFillCollision(int x, int y, uint collision); + void _floodFillCollision(int x, int y, uint collision); + void floodFillElevation(int x, int y, uint elevation); + void _floodFillElevation(int x, int y, uint elevation); + void floodFillCollisionElevation(int x, int y, uint collision, uint elevation); + void _floodFillCollisionElevation(int x, int y, uint collision, uint elevation); + + History history; + void undo(); + void redo(); + void commit(); + + QString object_events_label; + QString warps_label; + QString coord_events_label; + QString bg_events_label; + + QList object_events; + QList warps; + QList coord_events; + QList signs; + QList hidden_items; + + QList connections; + QPixmap renderConnection(Connection); + + QImage border_image; + QPixmap border_pixmap; + Blockdata *border; + Blockdata *cached_border; + QPixmap renderBorder(); + void cacheBorder(); + +signals: + +public slots: +}; + +#endif // MAP_H diff --git a/metatile.cpp b/metatile.cpp new file mode 100755 index 00000000..93d435fa --- /dev/null +++ b/metatile.cpp @@ -0,0 +1,6 @@ +#include "metatile.h" + +Metatile::Metatile() +{ + tiles = new QList; +} diff --git a/metatile.h b/metatile.h new file mode 100755 index 00000000..851d04b7 --- /dev/null +++ b/metatile.h @@ -0,0 +1,16 @@ +#ifndef METATILE_H +#define METATILE_H + +#include "tile.h" +#include + +class Metatile +{ +public: + Metatile(); +public: + QList *tiles; + int attr; +}; + +#endif // METATILE_H diff --git a/pretmap.pro b/pretmap.pro new file mode 100755 index 00000000..3b951a3c --- /dev/null +++ b/pretmap.pro @@ -0,0 +1,43 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-08-31T15:19:13 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = pretmap +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp \ + project.cpp \ + asm.cpp \ + map.cpp \ + blockdata.cpp \ + block.cpp \ + tileset.cpp \ + metatile.cpp \ + tile.cpp \ + event.cpp \ + editor.cpp + +HEADERS += mainwindow.h \ + project.h \ + asm.h \ + map.h \ + blockdata.h \ + block.h \ + tileset.h \ + metatile.h \ + tile.h \ + event.h \ + editor.h + +FORMS += mainwindow.ui + +RESOURCES += \ + resources/images.qrc diff --git a/project.cpp b/project.cpp new file mode 100755 index 00000000..93602ca7 --- /dev/null +++ b/project.cpp @@ -0,0 +1,787 @@ +#include "asm.h" +#include "project.h" +#include "tile.h" +#include "tileset.h" +#include "metatile.h" +#include "event.h" + +#include +#include +#include +#include +#include + +Project::Project() +{ + groupNames = new QStringList; + groupedMapNames = new QList; + map_cache = new QMap; + tileset_cache = new QMap; +} + +QString Project::getProjectTitle() { + return root.section('/', -1); +} + +Map* Project::loadMap(QString map_name) { + Map *map = new Map; + + map->name = map_name; + readMapHeader(map); + readMapAttributes(map); + getTilesets(map); + loadBlockdata(map); + loadMapBorder(map); + readMapEvents(map); + loadMapConnections(map); + map->commit(); + + map_cache->insert(map_name, map); + return map; +} + +void Project::loadMapConnections(Map *map) { + map->connections.clear(); + if (!map->connections_label.isNull()) { + QString path = root + QString("/data/maps/%1/connections.s").arg(map->name); + QString text = readTextFile(path); + if (text != NULL) { + QList *commands = parse(text); + QStringList *list = getLabelValues(commands, map->connections_label); + + //// Avoid using this value. It ought to be generated instead. + //int num_connections = list->value(0).toInt(nullptr, 0); + + QString connections_list_label = list->value(1); + QList *connections = getLabelMacros(commands, connections_list_label); + for (QStringList command : *connections) { + QString macro = command.value(0); + if (macro == "connection") { + Connection *connection = new Connection; + connection->direction = command.value(1); + connection->offset = command.value(2); + connection->map_name = command.value(3); + map->connections.append(connection); + } + } + } + } +} + +QList* Project::getLabelMacros(QList *list, QString label) { + bool in_label = false; + QList *new_list = new QList; + for (int i = 0; i < list->length(); i++) { + QStringList params = list->value(i); + QString macro = params.value(0); + if (macro == ".label") { + if (params.value(1) == label) { + in_label = true; + } else if (in_label) { + // If nothing has been read yet, assume the label + // we're looking for is in a stack of labels. + if (new_list->length() > 0) { + break; + } + } + } else if (in_label) { + new_list->append(params); + } + } + return new_list; +} + +// For if you don't care about filtering by macro, +// and just want all values associated with some label. +QStringList* Project::getLabelValues(QList *list, QString label) { + list = getLabelMacros(list, label); + QStringList *values = new QStringList; + for (int i = 0; i < list->length(); i++) { + QStringList params = list->value(i); + QString macro = params.value(0); + // Ignore .align + if (macro == ".align") { + continue; + } + for (int j = 1; j < params.length(); j++) { + values->append(params.value(j)); + } + } + return values; +} + +void Project::readMapHeader(Map* map) { + QString label = map->name; + Asm *parser = new Asm; + + QString header_text = readTextFile(root + "/data/maps/" + label + "/header.s"); + QStringList *header = getLabelValues(parser->parse(header_text), label); + map->attributes_label = header->value(0); + map->events_label = header->value(1); + map->scripts_label = header->value(2); + map->connections_label = header->value(3); + map->song = header->value(4); + map->index = header->value(5); + map->location = header->value(6); + map->visibility = header->value(7); + map->weather = header->value(8); + map->type = header->value(9); + map->unknown = header->value(10); + map->show_location = header->value(11); + map->battle_scene = header->value(12); +} + +void Project::saveMapHeader(Map *map) { + QString label = map->name; + QString header_path = root + "/data/maps/" + label + "/header.s"; + QString text = ""; + text += QString("%1::\n").arg(label); + text += QString("\t.4byte %1\n").arg(map->attributes_label); + text += QString("\t.4byte %1\n").arg(map->events_label); + text += QString("\t.4byte %1\n").arg(map->scripts_label); + text += QString("\t.4byte %1\n").arg(map->connections_label); + text += QString("\t.2byte %1\n").arg(map->song); + text += QString("\t.2byte %1\n").arg(map->index); + text += QString("\t.byte %1\n").arg(map->location); + text += QString("\t.byte %1\n").arg(map->visibility); + text += QString("\t.byte %1\n").arg(map->weather); + text += QString("\t.byte %1\n").arg(map->type); + text += QString("\t.2byte %1\n").arg(map->unknown); + text += QString("\t.byte %1\n").arg(map->show_location); + text += QString("\t.byte %1\n").arg(map->battle_scene); + saveTextFile(header_path, text); +} + +void Project::readMapAttributes(Map* map) { + Asm *parser = new Asm; + + QString assets_text = readTextFile(root + "/data/maps/_assets.s"); + QStringList *attributes = getLabelValues(parser->parse(assets_text), map->attributes_label); + map->width = attributes->value(0); + map->height = attributes->value(1); + map->border_label = attributes->value(2); + map->blockdata_label = attributes->value(3); + map->tileset_primary_label = attributes->value(4); + map->tileset_secondary_label = attributes->value(5); +} + +void Project::getTilesets(Map* map) { + map->tileset_primary = getTileset(map->tileset_primary_label); + map->tileset_secondary = getTileset(map->tileset_secondary_label); +} + +Tileset* Project::loadTileset(QString label) { + Asm *parser = new Asm; + + QString headers_text = readTextFile(root + "/data/tilesets/headers.s"); + QStringList *values = getLabelValues(parser->parse(headers_text), label); + Tileset *tileset = new Tileset; + tileset->name = label; + tileset->is_compressed = values->value(0); + tileset->is_secondary = values->value(1); + tileset->padding = values->value(2); + 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); + + loadTilesetAssets(tileset); + + tileset_cache->insert(label, tileset); + return tileset; +} + +QString Project::getBlockdataPath(Map* map) { + QString text = readTextFile(root + "/data/maps/_assets.s"); + QStringList *values = getLabelValues(parse(text), map->blockdata_label); + QString path; + if (!values->isEmpty()) { + path = root + "/" + values->value(0).section('"', 1, 1); + } else { + path = root + "/data/maps/" + map->name + "/map.bin"; + } + return path; +} + +QString Project::getMapBorderPath(Map *map) { + QString text = readTextFile(root + "/data/maps/_assets.s"); + QStringList *values = getLabelValues(parse(text), map->border_label); + QString path; + if (!values->isEmpty()) { + path = root + "/" + values->value(0).section('"', 1, 1); + } else { + path = root + "/data/maps/" + map->name + "/border.bin"; + } + return path; +} + +void Project::loadBlockdata(Map* map) { + QString path = getBlockdataPath(map); + map->blockdata = readBlockdata(path); +} + +void Project::loadMapBorder(Map *map) { + QString path = getMapBorderPath(map); + map->border = readBlockdata(path); +} + +void Project::saveBlockdata(Map* map) { + QString path = getBlockdataPath(map); + writeBlockdata(path, map->blockdata); +} + +void Project::writeBlockdata(QString path, Blockdata *blockdata) { + QFile file(path); + if (file.open(QIODevice::WriteOnly)) { + QByteArray data = blockdata->serialize(); + file.write(data); + } +} + +void Project::saveAllMaps() { + QList keys = map_cache->keys(); + for (int i = 0; i < keys.length(); i++) { + QString key = keys.value(i); + Map* map = map_cache->value(key); + saveMap(map); + } +} + +void Project::saveMap(Map *map) { + saveBlockdata(map); + saveMapHeader(map); +} + +void Project::loadTilesetAssets(Tileset* tileset) { + Asm* parser = new Asm; + QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary"; + QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower(); + + QString graphics_text = readTextFile(root + "/data/tilesets/graphics.s"); + QList *graphics = parser->parse(graphics_text); + QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label); + QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label); + + QString tiles_path; + if (!tiles_values->isEmpty()) { + tiles_path = root + "/" + tiles_values->value(0).section('"', 1, 1); + } else { + tiles_path = dir_path + "/tiles.4bpp"; + if (tileset->is_compressed == "TRUE") { + tiles_path += ".lz"; + } + } + + QStringList *palette_paths = new QStringList; + if (!palettes_values->isEmpty()) { + for (int i = 0; i < palettes_values->length(); i++) { + QString value = palettes_values->value(i); + palette_paths->append(root + "/" + value.section('"', 1, 1)); + } + } else { + QString palettes_dir_path = dir_path + "/palettes"; + for (int i = 0; i < 16; i++) { + palette_paths->append(palettes_dir_path + "/" + QString("%1").arg(i, 2, 10, QLatin1Char('0')) + ".gbapal"); + } + } + + QString metatiles_path; + QString metatile_attrs_path; + QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.s"); + QList *metatiles_macros = parser->parse(metatiles_text); + QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label); + if (!metatiles_values->isEmpty()) { + metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1); + } else { + metatiles_path = dir_path + "/metatiles.bin"; + } + QStringList *metatile_attrs_values = getLabelValues(metatiles_macros, tileset->metatile_attrs_label); + if (!metatile_attrs_values->isEmpty()) { + metatile_attrs_path = root + "/" + metatile_attrs_values->value(0).section('"', 1, 1); + } else { + metatile_attrs_path = dir_path + "/metatile_attributes.bin"; + } + + // tiles + tiles_path = fixGraphicPath(tiles_path); + QImage *image = new QImage(tiles_path); + //image->setColor(0, qRgb(0xff, 0, 0)); // debug + + QList *tiles = new QList; + int w = 8; + int h = 8; + for (int y = 0; y < image->height(); y += h) + for (int x = 0; x < image->width(); x += w) { + QImage tile = image->copy(x, y, w, h); + tiles->append(tile); + } + tileset->tiles = tiles; + + // metatiles + //qDebug() << metatiles_path; + QFile metatiles_file(metatiles_path); + if (metatiles_file.open(QIODevice::ReadOnly)) { + QByteArray data = metatiles_file.readAll(); + int num_metatiles = data.length() / 16; + int num_layers = 2; + QList *metatiles = new QList; + for (int i = 0; i < num_metatiles; i++) { + Metatile *metatile = new Metatile; + int index = i * 16; + for (int j = 0; j < 4 * num_layers; j++) { + uint16_t word = data[index++] & 0xff; + word += (data[index++] & 0xff) << 8; + Tile tile; + tile.tile = word & 0x3ff; + tile.xflip = (word >> 10) & 1; + tile.yflip = (word >> 11) & 1; + tile.palette = (word >> 12) & 0xf; + metatile->tiles->append(tile); + } + metatiles->append(metatile); + } + tileset->metatiles = metatiles; + } + + QFile attrs_file(metatile_attrs_path); + //qDebug() << metatile_attrs_path; + if (attrs_file.open(QIODevice::ReadOnly)) { + QByteArray data = attrs_file.readAll(); + int num_metatiles = data.length() / 2; + for (int i = 0; i < num_metatiles; i++) { + uint16_t word = data[i*2] & 0xff; + word += (data[i*2 + 1] & 0xff) << 8; + tileset->metatiles->value(i)->attr = word; + } + } + + // palettes + QList> *palettes = new QList>; + for (int i = 0; i < palette_paths->length(); i++) { + QString path = palette_paths->value(i); + // the palettes are not compressed. this should never happen. it's only a precaution. + path = path.replace(QRegExp("\\.lz$"), ""); + // TODO default to .pal (JASC-PAL) + // just use .gbapal for now + QFile file(path); + QList palette; + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.readAll(); + for (int j = 0; j < 16; j++) { + uint16_t word = data[j*2] & 0xff; + word += (data[j*2 + 1] & 0xff) << 8; + int red = word & 0x1f; + int green = (word >> 5) & 0x1f; + int blue = (word >> 10) & 0x1f; + QRgb color = qRgb(red * 8, green * 8, blue * 8); + palette.prepend(color); + } + } + //qDebug() << path; + palettes->append(palette); + } + tileset->palettes = palettes; +} + +Blockdata* Project::readBlockdata(QString path) { + Blockdata *blockdata = new Blockdata; + //qDebug() << path; + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.readAll(); + for (int i = 0; (i + 1) < data.length(); i += 2) { + uint16_t word = (data[i] & 0xff) + ((data[i + 1] & 0xff) << 8); + blockdata->addBlock(word); + } + } + return blockdata; +} + +Map* Project::getMap(QString map_name) { + if (map_cache->contains(map_name)) { + return map_cache->value(map_name); + } else { + Map *map = loadMap(map_name); + return map; + } +} + +Tileset* Project::getTileset(QString label) { + if (tileset_cache->contains(label)) { + return tileset_cache->value(label); + } else { + Tileset *tileset = loadTileset(label); + return tileset; + } +} + +QString Project::readTextFile(QString path) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { + //QMessageBox::information(0, "Error", QString("Could not open '%1': ").arg(path) + file.errorString()); + return NULL; + } + QTextStream in(&file); + QString text = ""; + while (!in.atEnd()) { + text += in.readLine() + "\n"; + } + return text; +} + +void Project::saveTextFile(QString path, QString text) { + QFile file(path); + if (file.open(QIODevice::WriteOnly)) { + file.write(text.toUtf8()); + } +} + +void Project::readMapGroups() { + QString text = readTextFile(root + "/data/maps/_groups.s"); + if (text == NULL) { + return; + } + Asm *parser = new Asm; + QList *commands = parser->parse(text); + + bool in_group_pointers = false; + QStringList *groups = new QStringList; + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".label") { + if (in_group_pointers) { + break; + } + if (params.value(1) == "gMapGroups") { + in_group_pointers = true; + } + } else if (macro == ".4byte") { + if (in_group_pointers) { + for (int j = 1; j < params.length(); j++) { + groups->append(params.value(j)); + } + } + } + } + + QList *maps = new QList; + for (int i = 0; i < groups->length(); i++) { + QStringList *list = new QStringList; + maps->append(list); + } + + int group = -1; + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".label") { + group = groups->indexOf(params.value(1)); + } else if (macro == ".4byte") { + if (group != -1) { + for (int j = 1; j < params.length(); j++) { + QStringList *list = maps->value(group); + list->append(params.value(j)); + } + } + } + } + + groupNames = groups; + groupedMapNames = maps; +} + +QList* Project::parse(QString text) { + Asm *parser = new Asm; + return parser->parse(text); +} + +QStringList Project::getLocations() { + // TODO + QStringList names; + for (int i = 0; i < 88; i++) { + names.append(QString("%1").arg(i)); + } + return names; +} + +QStringList Project::getVisibilities() { + // TODO + QStringList names; + for (int i = 0; i < 16; i++) { + names.append(QString("%1").arg(i)); + } + return names; +} + +QStringList Project::getWeathers() { + // TODO + QStringList names; + for (int i = 0; i < 16; i++) { + names.append(QString("%1").arg(i)); + } + return names; +} + +QStringList Project::getMapTypes() { + // TODO + QStringList names; + for (int i = 0; i < 16; i++) { + names.append(QString("%1").arg(i)); + } + return names; +} + +QStringList Project::getBattleScenes() { + // TODO + QStringList names; + for (int i = 0; i < 16; i++) { + names.append(QString("%1").arg(i)); + } + return names; +} + +QStringList Project::getSongNames() { + QStringList names; + QString text = readTextFile(root + "/constants/songs.s"); + if (text != NULL) { + QList *commands = parse(text); + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".equiv") { + names.append(params.value(1)); + } + } + } + return names; +} + +QString Project::getSongName(int value) { + QStringList names; + QString text = readTextFile(root + "/constants/songs.s"); + if (text != NULL) { + QList *commands = parse(text); + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".equiv") { + if (value == ((QString)(params.value(2))).toInt(nullptr, 0)) { + return params.value(1); + } + } + } + } + return ""; +} + +QMap Project::getMapObjGfxConstants() { + QMap constants; + QString text = readTextFile(root + "/constants/map_object_constants.s"); + if (text != NULL) { + QList *commands = parse(text); + for (int i = 0; i < commands->length(); i++) { + QStringList params = commands->value(i); + QString macro = params.value(0); + if (macro == ".set") { + QString constant = params.value(1); + if (constant.startsWith("MAP_OBJ_GFX_")) { + int value = params.value(2).toInt(nullptr, 0); + constants.insert(constant, value); + } + } + } + } + return constants; +} + +QString Project::fixGraphicPath(QString path) { + path = path.replace(QRegExp("\\.lz$"), ""); + path = path.replace(QRegExp("\\.[1248]bpp$"), ".png"); + return path; +} + +void Project::loadObjectPixmaps(QList objects) { + bool needs_update = false; + for (ObjectEvent *object : objects) { + if (object->pixmap.isNull()) { + needs_update = true; + break; + } + } + if (!needs_update) { + return; + } + + QMap constants = getMapObjGfxConstants(); + + QString pointers_path = root + "/data/graphics/field_objects/map_object_graphics_info_pointers.s"; + QString pointers_text = readTextFile(pointers_path); + if (pointers_text == NULL) { + return; + } + QString info_path = root + "/data/graphics/field_objects/map_object_graphics_info.s"; + QString info_text = readTextFile(info_path); + if (info_text == NULL) { + return; + } + QString pic_path = root + "/data/graphics/field_objects/map_object_pic_tables.s"; + QString pic_text = readTextFile(pic_path); + if (pic_text == NULL) { + return; + } + QString assets_path = root + "/data/graphics/field_objects/map_object_graphics.s"; + QString assets_text = readTextFile(assets_path); + if (assets_text == NULL) { + return; + } + + QStringList *pointers = getLabelValues(parse(pointers_text), "gMapObjectGraphicsInfoPointers"); + QList *info_commands = parse(info_text); + QList *asset_commands = parse(assets_text); + QList *pic_commands = parse(pic_text); + + for (ObjectEvent *object : objects) { + if (!object->pixmap.isNull()) { + continue; + } + int id = constants.value(object->sprite); + QString info_label = pointers->value(id); + QStringList *info = getLabelValues(info_commands, info_label); + QString pic_label = info->value(12); + + QList *pic = getLabelMacros(pic_commands, pic_label); + for (int i = 0; i < pic->length(); i++) { + QStringList command = pic->value(i); + QString macro = command.value(0); + if (macro == "obj_frame_tiles") { + QString label = command.value(1); + QStringList *incbins = getLabelValues(asset_commands, label); + QString path = incbins->value(0).section('"', 1, 1); + path = fixGraphicPath(path); + QPixmap pixmap(root + "/" + path); + object->pixmap = pixmap; + break; + } + } + } +} + +void Project::readMapEvents(Map *map) { + // lazy + QString path = root + QString("/data/maps/events/%1.s").arg(map->name); + QString text = readTextFile(path); + + QStringList *labels = getLabelValues(parse(text), map->events_label); + map->object_events_label = labels->value(0); + map->warps_label = labels->value(1); + map->coord_events_label = labels->value(2); + map->bg_events_label = labels->value(3); + + QList *object_events = getLabelMacros(parse(text), map->object_events_label); + map->object_events.clear(); + for (QStringList command : *object_events) { + if (command.value(0) == "object_event") { + ObjectEvent *object = new ObjectEvent; + // This macro is not fixed as of writing, but it should take fewer args. + bool old_macro = false; + if (command.length() >= 20) { + command.removeAt(19); + command.removeAt(18); + command.removeAt(15); + command.removeAt(13); + command.removeAt(11); + command.removeAt(7); + command.removeAt(5); + command.removeAt(1); // id. not 0, but is just the index in the list of objects + old_macro = true; + } + int i = 1; + object->sprite = command.value(i++); + object->replacement = command.value(i++); + object->x_ = command.value(i++); + object->y_ = command.value(i++); + object->elevation_ = command.value(i++); + object->behavior = command.value(i++); + if (old_macro) { + int radius = command.value(i++).toInt(nullptr, 0); + object->radius_x = QString("%1").arg(radius & 0xf); + object->radius_y = QString("%1").arg((radius >> 4) & 0xf); + } else { + object->radius_x = command.value(i++); + object->radius_y = command.value(i++); + } + object->property = command.value(i++); + object->sight_radius = command.value(i++); + object->script_label = command.value(i++); + object->event_flag = command.value(i++); + + map->object_events.append(object); + } + } + + QList *warps = getLabelMacros(parse(text), map->warps_label); + map->warps.clear(); + for (QStringList command : *warps) { + if (command.value(0) == "warp_def") { + Warp *warp = new Warp; + int i = 1; + warp->x_ = command.value(i++); + warp->y_ = command.value(i++); + warp->elevation_ = command.value(i++); + warp->destination_warp = command.value(i++); + warp->destination_map = command.value(i++); + map->warps.append(warp); + } + } + + QList *coords = getLabelMacros(parse(text), map->coord_events_label); + map->coord_events.clear(); + for (QStringList command : *coords) { + if (command.value(0) == "coord_event") { + CoordEvent *coord = new CoordEvent; + bool old_macro = false; + if (command.length() >= 9) { + command.removeAt(7); + command.removeAt(6); + command.removeAt(4); + old_macro = true; + } + int i = 1; + coord->x_ = command.value(i++); + coord->y_ = command.value(i++); + coord->elevation_ = command.value(i++); + coord->unknown1 = command.value(i++); + coord->script_label = command.value(i++); + map->coord_events.append(coord); + } + } + + QList *bgs = getLabelMacros(parse(text), map->warps_label); + map->hidden_items.clear(); + map->signs.clear(); + for (QStringList command : *bgs) { + if (command.value(0) == "bg_event") { + BGEvent *bg = new BGEvent; + int i = 1; + bg->x_ = command.value(i++); + bg->y_ = command.value(i++); + bg->elevation_ = command.value(i++); + bg->type = command.value(i++); + i++; + if (bg->is_item()) { + HiddenItem *item = new HiddenItem(*bg); + item->item = command.value(i++); + item->unknown5 = command.value(i++); + item->unknown6 = command.value(i++); + map->hidden_items.append(item); + } else { + Sign *sign = new Sign(*bg); + sign->script_label = command.value(i++); + map->signs.append(sign); + } + } + } + +} diff --git a/project.h b/project.h new file mode 100755 index 00000000..de3820f5 --- /dev/null +++ b/project.h @@ -0,0 +1,69 @@ +#ifndef PROJECT_H +#define PROJECT_H + +#include "map.h" +#include "blockdata.h" + +#include +#include + +class Project +{ +public: + Project(); + QString root; + QStringList *groupNames; + QList *groupedMapNames; + + QMap *map_cache; + Map* loadMap(QString); + Map* getMap(QString); + + QMap *tileset_cache; + Tileset* loadTileset(QString); + Tileset* getTileset(QString); + + Blockdata* readBlockdata(QString); + void loadBlockdata(Map*); + + QString readTextFile(QString path); + void saveTextFile(QString path, QString text); + + void readMapGroups(); + QString getProjectTitle(); + + QList* getLabelMacros(QList*, QString); + QStringList* getLabelValues(QList*, QString); + void readMapHeader(Map*); + void readMapAttributes(Map*); + void getTilesets(Map*); + void loadTilesetAssets(Tileset*); + + QString getBlockdataPath(Map*); + void saveBlockdata(Map*); + void writeBlockdata(QString, Blockdata*); + void saveAllMaps(); + void saveMap(Map*); + void saveMapHeader(Map*); + + QList* parse(QString text); + QStringList getSongNames(); + QString getSongName(int); + QStringList getLocations(); + QStringList getVisibilities(); + QStringList getWeathers(); + QStringList getMapTypes(); + QStringList getBattleScenes(); + + void loadObjectPixmaps(QList objects); + QMap getMapObjGfxConstants(); + QString fixGraphicPath(QString path); + + void readMapEvents(Map *map); + void loadMapConnections(Map *map); + + void loadMapBorder(Map *map); + QString getMapBorderPath(Map *map); +}; + +#endif // PROJECT_H diff --git a/resources/icons/folder.ico b/resources/icons/folder.ico new file mode 100755 index 0000000000000000000000000000000000000000..12525f115c762ef89cdbe76c71f7bac0aa784743 GIT binary patch literal 5430 zcmeI0c}!GS6vm%R)24~mv~`juO+(YPX&aMjRlo&V1WlSWrfbs14T;F=u;YT&B5EoE zD!5A<8%uGmYl4c_q*ei8ScV-2aHAr%3KX4TmapF#W^|mQqK@ew_9nl~yZ60&zjN<9 z@7{ApQ3fajm0`ma{<mcok?QR;C&}D7o_}^V+}E7HgGcIlOh0uE z>N+FBs(TPpWx%{j1A<91ZQI>)3!W?Tk9l#;kNpkAHW(3J+=+;iE<|X$5J{$Puf&(f z+fdIntGNYKlPcjhZ8QO*J(2xSbKRrsjfmqI@w_1<(Dqo`?9VYgY<7)ZQ;acb#qeCK zffxI7?b|1?e-XzFrF{`3oXB-(RS&{yj0mah!OU|Vq!Tj=I&tKZ-rCnY<7}wBKj|;_ z%q}+|uuP95?Pk<*Jh545FaV8QODpt|7CQSRu6e)~?P%#QcF(*H@mJ=gT57Y-r=9N^`@ ziv2#H9YoLNwqZr~88_lXWIwVN*?63aYixb8z3N%E!RdAU7uDw|DxRTw%7}(&ITvXk zMf}L*r-Y3CA$f%iB#uQDu(_;@dxGt((^$_sIqzJBx15ccB^?xfi#+cr&TExu%QLy$ z2e)$1-@tv_mB`r|c=!TF1g(yw-cV=#$(zbC<8U*QwVl{{16X|xNOd7H=Cbme@LZmk zFY_g`YuSs+m-~JawPzh_!B2d4WvdyhuDFJk94DjAf}M;Zyfe$>Y=4tD`k_i$%t&z&$sFfrjyr3=4sU-E{}uIz*eB0lmAv~Lo{dwotB~G!8{6A} zr58;2)1J7hNzT!*%?o^P1~iT4JN1=KSwfd z79t*o)_{--1K+C|nMG|F5xyab+SYSV=ATD>c}Izj^f~(LBIX0K9*dnwx@f`Yv~OCj z4q;VB%;lItjBn@kgV}s$DP!@1>qdC2I$cD4IgeBltDoe$M%!|UUY|44=bWHzi42Mt zHk++$^ihru^^Bvd86Qim-5)CXTpi`s_p}67b0!g>uP=nYUV?I zF`w;W)kYL@&AqtC%Up?bvFevnf1XxPKi1Qq?je!te-FRR4vZ_fHdB^L=xYwrZkxkl3iR=B(c{SW_IZ|bum9(6&D*&QcMHAZB_cVB9f{K% Xk$uw+FZ(QVU&gu1^ZaLmIG29_e*xgE literal 0 HcmV?d00001 diff --git a/resources/icons/folder_closed.ico b/resources/icons/folder_closed.ico new file mode 100755 index 0000000000000000000000000000000000000000..f01179fedcac25cdbec73e14711170c4b5b9c563 GIT binary patch literal 5430 zcmeI0S!`5Q9L6sQ;lY?RA@bZOIT(P&O(_NeaVc#kfgP9#Rw~IXUp&$@pf*J|NJqFg~9}Tl!bh2+*Emp1k{u!Xu0TdD=DVpRv zDT_im^L+MupnP_l4J?i^H!!Lah7-gz=0o|Y7v&=!l<6qp`}tsb8UKvtUZh%jkVeui z-N-o6jpx3;hLRxeNZY0S zAocgyRqVC9@FF>X-G?#8O;CePS_#+A9LLPiVb|I);RQyRU)m~+bNtdcCXcgjsec#e zcsVv?x7(2SR{!UuOZp*sL&$sXY5TYQK309={eJoRuj|>sa#B|InPg%hvL9&=H=acA zGx7H`zJ2bVe*ELdwXvDVv9#?jBO0Q$>}=z!#LL<91j)NgNZpT;tz=_p-SGFe+z#8V zY@TcX1)?RI;rg=Qy~91egXdv;3`oAWxt~SL+s5=aS)ZP>6qU18uPrLPdo`FrP zAbFavuaZyFBXEZMubj=1^iMj0<2?MS@Kvp~-FNcxsv zfySTxPJ-9xeF>qF^&De;=Bt5rzEAzkDEelOSHryDNl-uMOAOR+kp58LGNbkrkqSS&s$aOvAXbrj@^9! zhW;S6=_l+w)pzGU7P^TgZJ}Ux{T4|0_ZC F&p+=1`(FS6 literal 0 HcmV?d00001 diff --git a/resources/icons/folder_closed_map.ico b/resources/icons/folder_closed_map.ico new file mode 100755 index 0000000000000000000000000000000000000000..27f9810b52fba460a8812fd6d96b22f7ef525a61 GIT binary patch literal 1150 zcmbu8OH30{6oxMeJ2xaItX;aZ#0P{jEsaYynz(am&}vY+a-j@ZFoKj|XaQYlG)5C$ z$wng*V_RclK%i5Lv4k26CaoBQ4}7$p_V+*2F*G&C2Q&HR+;i^z=l=KJ8Kr7?*VQRL zw<&L}QuRuy?Sv&(%5?^%*tc~{87t=lz^33U9AxKT(7-WGHqsW2!!vGt)PgZo;||WD zlIniRMcX=NV59&HecvFs4un3FPj+NmYL#QIl>qms0aqx70rvI2|2M93K8;#85pCd2 z4(BpJf2Q;c1FQ+>vt$(*&g5|Y3-w%sJ2VeH3v|COpetR3o;J~K)59p7vGFe#;a@4C zZ`s5xu1yQhTl$k};CKo+O1$LQE9Rv0H~2W_&RSXT8jXQ+Earh^jxa8f6N^Rok|umF z3+Sw(gZW)sFZ4z?;b9a6E_h3J%5dnEU{=(7(+8 zlzTaKx`{4Kv_*96kNUB1;xP`~&m#E^Sopd@g8P{ZV-cEiquCW;QUW!kUC$f%a c`uK_Do{Ppq{vUt5Xk%0VFXjJr)leteA7stf#{d8T literal 0 HcmV?d00001 diff --git a/resources/icons/folder_image.ico b/resources/icons/folder_image.ico new file mode 100755 index 0000000000000000000000000000000000000000..6cbbc6db45a4820ab9116a8f98bdc31fca6a912a GIT binary patch literal 5430 zcmds)3s9C-8pq$P*4EOTOvctSrj#^q2_d3#6R?D&RkX{FC}3xH%JAU|pO%XM1Bzm$D2k*UBKyBv7e0dCaLb^-+T&^*MKjQJ!$Ved``PXRkb7fGPwdo{s8R% za1(Obhurwtkh%Oak?@(TzB}TpBo`b?U5VMOpUe88?6{_^72zbTyd5ExKrq{S>1Z{q zca*|9y%f{Z%P=jY9JZO4V4qcqS$ivw%wqj>?0-P95kVyIJEQvUU)&1+izWn?wqtcU zR08-cYX@d$6k>YJ;i=;9Qooqy@GUUHFTWX|-fTlD+be7Cgi}>c%7hkx!-NC<#eGka zt@ysYU!vVh*oIKfGPY^wVZZ%b%w*fWk@9mg3#-j*j=ozjdFFER?y|e!2j)+7%Ph1e zHeKxD`<@~@_ik&}#04ZIkh@Cvv6OH>8QihYSn}1G$bO_I*?9iHlI)yA$w*=`0HnOs z8`#dv3cZrFF_AbC*8w2qrJmHkmo##JwC5SwZ`Hj!iTk-=-q$yDdzU=*JNJE-mwFTy zJKRgMkhcDt)Okk8oZU;Z_>5zcG|XO)As$+cL>J9%SC#BEIv)i9|QGy(!*$j9sF|xV1V=*zp(r9jOx@Ey~oH?$N)A^5qplcgq-e-@p;J^H+SOp64b! z z>8o@Y@$EuK6q(>Ibvz5nkN6Sm^!Zx zE-SR~iqPXXNd~-~)&LD-lenx#Y}wa@)V)oJ-^@-k{^{ob7A}l6VyM0Blgrpo{dcan zVbirc^Ue*%M2w5f@z8_AYA}9gE$qGP@zP4pgGPs?vFt-K4m&%Y9!l(k|V??-&ZjUom0B9Z2{dSpP51zZ%cA zQNJ3GkEn*#10Gf1gXKHUP0>F@pO3uQggJYQ@h7@y%GFlwTmWnlm?%Q{RrDk`}BXA!bTj7|*sqL&6!?hB5Bclo|)b3EJ83=v5i}XfminKM#NA zT3&yp4gP1jem*S2-?+d0l{Pukjj#EBmV}nHV(rBimCzCsLKq9LDa9QL=J$XS-XA*k zhm3x1GPNHv>mR3n6fYVvjP)1t&R~~v4%1V<`3WH@QXn)={s2|RGjk-jiqtCCu+@{(inl|Z9%++=*V*g$}Sb;#^ z1y&Xsv4Zja^1Hy7W#Y?Q@%P$R*lo%^N9_@!FL#wwwCh^>TX>hxwbJi;!M;V&@77hd zsW$RBP@&!*F7SR(%>AQJ_IE%BeKFLx#JwJ@UT2f0f{R7O$9GDhm(F5XthUqt^|Q9vEm37}RN zqRIS&H`-9fcDnAbJjU9`V@;`>*xT5qX;b$A6@+h0?$zTqeNcs=u9EW27 literal 0 HcmV?d00001 diff --git a/resources/icons/folder_map.ico b/resources/icons/folder_map.ico new file mode 100755 index 0000000000000000000000000000000000000000..e4e728f30b7e44dd900119e213266d1e89934902 GIT binary patch literal 5430 zcmc(i3s98T7017%>DWmpZKjS)JDH}=q+{DjGHJBL7t3oGd^K8Q%uK8gd=?N8c?!GB z)5NJ*5`~ChoT)Y%@YSl3sJs?6)oPTNC@e0hiP~yX8*37l-R0l^xw}i2t$@bNW~a^_H9KYQ&u1mS`eXgV>Giof)je$QBIw?o zi;(j9(CwIu;0mVqM5#KNN5rPa&-9y`5n9}c;0+DXZD_)nVk<1!6WPWIL-k5T9A2TA zbR-dx0?Q;+vcI9U86oVu%K>cuFR=bLQ1As%V;avEJqW8!L3mAaKlF8}taGaV`jRHR zvfGA2>*v_^DUf>&Fnk$G+l%q?##Os!iGce+T`9n7DK;GzcX=Xz)E?nL0)Qy5cl2G16rN1a*r z??2=wx#8hoj0GvXgTt$*aladIi2Ih_)eGY#av4bb7});K8dx|7OLh?CU)JXl#uk+h z#?kyRRIFQyAojPge{!^?jrVT4(9ZF!-5%^f2eAr00GA0J^(CUTB~Wx<(ige!Z5%`BV4J|gGZ?@A zEGBSlf24i*rsf;oGe_OMC1u`rk`60r`k3WU8#XnMCS&?2WxBLwY=qC5b@BiSIpm(g zLu@5{hYWMyGb5P{C2}9Bz>CNKp5YJIzD?W{``TaLoZ4e#1PQngq`mZ${tpsljHgKm z(ccHsUiwM@2MHs#8>bzY`&QlE`Ml2s@4cSula?}7&wHQkr5^>$K0HVWkg>i_@Yo3X zXAcqr-shSmMDAaP;PT%ic>5fLygLV>v@MbrRGM`Y%jdwbZ?S4G`$fTC`QDTBU6$P| zqB}o1l4nrkh3${V_+9f6RK5T~74x90h;paB`JMAIVdp%A?OUSSi;eQg7kNJ-KP5lA z51wS(XX^4o)OZoJefq-*h&a@r$zmf}7O8Ay9Hvw!x#h3!lP~Vb=%=PHj~_XCaooM~ zWJFZ#@W2-rA653;2|ewpf%Y__DoJ6eN`$_KHk$d!8kWiYB+qt0FW&!3en3P?!)@M$ z9$SBw_I_w|8yemIK#tfmJHlzZLp}C9jBE6@?J_sXi_JH9Y`m|0ksU&NS?&PJ?f`Gm zZVg2-+x>~Q#O+Ur{B+7srakg~Aaw69=ZZ&}6pI(P>A_CG*;jd=&Ukk@h>Ww(H} zG|L4;u$HF!wa>i%2>k^5BQmzHPvT8W94`I|>wSF`{&#g}hSAqBQTBrUm$04kU%%$U znyZ8J`gQt5^ozXykc=z7&{X<0lWH?Dxz4EKskKH-sm;I?i{vvfsotp8?{oeF#K+tC zNiRa_Gwq;j^2W7ZOsh-FJ|sqRbf`sLs6pl=Ydr4@x2zr@>gg|aU@kvj-E9|4*FKbCIuHvu!2j)von7W)W4}gh2 zR4RSaYU6k{-jZW$kp%ui;o?$u@NO*-Pn4)7fE!?Qt5c5`H?PpI%i3jfCFztp~kF3byhH{vl$Cn z{i$MJIBX8ap{x)b$&2LvPyc|jKt`G^O8&Lhmm{Yi|I-)UgrE}l-m%?x4_b7I~LQwUvv*du}yY|11CRqVC)*p zDasx$^5v~k!+l*zeM{-nIS2L556&%}dY94VQhPLYhfTd7&hvfH%KKwLq~60h#_fDp z$a{dY#s5?C<*g*TmPC?=K;BYmHWy~@vSHjh{-c55zX}xAeTZ>y^4-F>i@b}}Tcr5R zdz7v8U)Fz|^5f3ik$AyQy&9S%IS2Bt<9-Z8GV2mAx=_Qhb-ZI`t;9bB$ejMc`!9xi zl)$&%in}1?Lc9lWKB1LobO7R69z#xWY*`}(4=BHZZT`^GO&#v0PWNXy^Uj}K7ef7)vP52GdNdA#9o&}kM?8DvWFXf&!9H1aMGv8RCG5l8F-;_^xT+{r?`NmeL{g6ZT KXBZbvB>WEzt>6Oy literal 0 HcmV?d00001 diff --git a/resources/icons/image.ico b/resources/icons/image.ico new file mode 100755 index 0000000000000000000000000000000000000000..9cee786f743cf913309a77ccffef386d21e2bb7d GIT binary patch literal 1150 zcmbu9jZ0Hu6vj^>p$TPS7O~7&iKaO%bYl%9sNB-r%7l!mL4Fl|=*+U9{FswPMpQ&7 zeLz%yK(^Jtl+OEoM>+H9ymz;#Aw>0Fo_p?l?)g3E<-RYMXdPcgMa1_q8ptCmA)*Qv zr#O?%b0Fe(YYYeH4*i210O;in|C>a#1@jXD%#Zv3EUpvv%)J(TV(KJ^zaKV7A0`7f zoZ?NaO%45HItKas-;Ns?XN`=SR{!7mZy;KPWA_4Fo)mlm3I4M( z+IT-YFRSQ}Xc%Iz(OViKLxNw)>CXp|7O-{mXE@6i;c~G@;}V)$WSnl75$;sb*Q;WX zy#}ue9zXfy)Cp@&w8S1M6mDEX$uWumu7oI}A|93^9| zJQJQN*5Vpk;M}hgbtV!P2l{lceKt8AlVs>wC3gx-SshC=p}k?B?59_jekFgJ z;qQN*CtlC$p4?{q=JA!WpU$4_13XVua<1=tHGyL<#xeB#B8C>maAM(-yYA$R<2b%J z2H(q=@;y&jo*!JDgjT(V;Bqga>UC8cma%#j`f6PHp6B_y(Ck|X)NUfU5?2IPZa}L| zs`YS_w*$3>x%By<|H@4w-5;#fUPkfvqV+VP*s>>Pd1KN1=o1dbe;EZG!zmtN` zPX2_sR-aOS@BD298iv{n*i#5PhN82U(NCnSaSzz$JK)~my~mEKOE28WV8otA$T3w6 z+a`3|fL@omfsux(=J)#FG3umowmE}yZ)b6yTxhsN>shsqHnWgK>KXbwee;3KYxiM% zEWvD*kZC=|?e`_zX_dP%&HD6*GGc2F>7(mg`LN1k&3lM%K0<0^9>)4S((A=8=0*|b zyT?du7ICHd!1I+Stil=QTjUG*{0Ba<_A9b)3l-%-EZ>b5t+@!_hf!FCK3J>tlVhzA Nf%JHg{5bp literal 0 HcmV?d00001 diff --git a/resources/images.qrc b/resources/images.qrc new file mode 100755 index 00000000..eccdadb9 --- /dev/null +++ b/resources/images.qrc @@ -0,0 +1,11 @@ + + + icons/folder.ico + icons/folder_closed.ico + icons/folder_closed_map.ico + icons/folder_image.ico + icons/folder_map.ico + icons/image.ico + icons/map.ico + + diff --git a/tile.cpp b/tile.cpp new file mode 100755 index 00000000..fd0f42f3 --- /dev/null +++ b/tile.cpp @@ -0,0 +1,6 @@ +#include "tile.h" + +Tile::Tile() +{ + +} diff --git a/tile.h b/tile.h new file mode 100755 index 00000000..f511a7cb --- /dev/null +++ b/tile.h @@ -0,0 +1,16 @@ +#ifndef TILE_H +#define TILE_H + + +class Tile +{ +public: + Tile(); +public: + int tile; + int xflip; + int yflip; + int palette; +}; + +#endif // TILE_H diff --git a/tileset.cpp b/tileset.cpp new file mode 100755 index 00000000..cb781cc6 --- /dev/null +++ b/tileset.cpp @@ -0,0 +1,6 @@ +#include "tileset.h" + +Tileset::Tileset() +{ + +} diff --git a/tileset.h b/tileset.h new file mode 100755 index 00000000..17006f18 --- /dev/null +++ b/tileset.h @@ -0,0 +1,27 @@ +#ifndef TILESET_H +#define TILESET_H + +#include "metatile.h" +#include + +class Tileset +{ +public: + Tileset(); +public: + QString name; + QString is_compressed; + QString is_secondary; + QString padding; + QString tiles_label; + QString palettes_label; + QString metatiles_label; + QString callback_label; + QString metatile_attrs_label; + + QList *tiles; + QList *metatiles; + QList> *palettes; +}; + +#endif // TILESET_H