Browse Source

Initial commit

yenatch 7 years ago
commit
2246ead5a8
33 changed files with 3961 additions and 0 deletions
  1. 59
    0
      asm.cpp
  2. 15
    0
      asm.h
  3. 29
    0
      block.cpp
  4. 20
    0
      block.h
  5. 39
    0
      blockdata.cpp
  6. 28
    0
      blockdata.h
  7. 324
    0
      editor.cpp
  8. 155
    0
      editor.h
  9. 52
    0
      event.cpp
  10. 100
    0
      event.h
  11. 11
    0
      main.cpp
  12. 370
    0
      mainwindow.cpp
  13. 69
    0
      mainwindow.h
  14. 938
    0
      mainwindow.ui
  15. 600
    0
      map.cpp
  16. 165
    0
      map.h
  17. 6
    0
      metatile.cpp
  18. 16
    0
      metatile.h
  19. 43
    0
      pretmap.pro
  20. 787
    0
      project.cpp
  21. 69
    0
      project.h
  22. BIN
      resources/icons/folder.ico
  23. BIN
      resources/icons/folder_closed.ico
  24. BIN
      resources/icons/folder_closed_map.ico
  25. BIN
      resources/icons/folder_image.ico
  26. BIN
      resources/icons/folder_map.ico
  27. BIN
      resources/icons/image.ico
  28. BIN
      resources/icons/map.ico
  29. 11
    0
      resources/images.qrc
  30. 6
    0
      tile.cpp
  31. 16
    0
      tile.h
  32. 6
    0
      tileset.cpp
  33. 27
    0
      tileset.h

+ 59
- 0
asm.cpp View File

@@ -0,0 +1,59 @@
1
+#include "asm.h"
2
+
3
+Asm::Asm()
4
+{
5
+}
6
+
7
+void Asm::strip_comment(QString *line) {
8
+    bool in_string = false;
9
+    for (int i = 0; i < line->length(); i++) {
10
+        if (line->at(i) == '"') {
11
+            in_string = !in_string;
12
+        } else if (line->at(i) == '@') {
13
+            if (!in_string) {
14
+                line->truncate(i);
15
+                break;
16
+            }
17
+        }
18
+    }
19
+}
20
+
21
+QList<QStringList>* Asm::parse(QString text) {
22
+    QList<QStringList> *parsed = new QList<QStringList>;
23
+    QStringList lines = text.split('\n');
24
+    for (QString line : lines) {
25
+        QString label;
26
+        //QString macro;
27
+        //QStringList *params;
28
+        strip_comment(&line);
29
+        if (line.isEmpty()) {
30
+        } else if (line.contains(':')) {
31
+            label = line.left(line.indexOf(':'));
32
+            QStringList *list = new QStringList;
33
+            list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
34
+            list->append(label);
35
+            parsed->append(*list);
36
+            // There should not be anything else on the line.
37
+            // gas will raise a syntax error if there is.
38
+        } else {
39
+            line = line.trimmed();
40
+            //parsed->append(line.split(QRegExp("\\s*,\\s*")));
41
+            QString macro;
42
+            QStringList params;
43
+            int index = line.indexOf(QRegExp("\\s+"));
44
+            macro = line.left(index);
45
+            params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
46
+            params.prepend(macro);
47
+            parsed->append(params);
48
+        }
49
+        //if (macro != NULL) {
50
+        //    if (macros->contains(macro)) {
51
+        //        void* function = macros->value(macro);
52
+        //        if (function != NULL) {
53
+        //            std::function function(params);
54
+        //        }
55
+        //    }
56
+        //}
57
+    }
58
+    return parsed;
59
+}

+ 15
- 0
asm.h View File

@@ -0,0 +1,15 @@
1
+#ifndef ASM_H
2
+#define ASM_H
3
+
4
+#include <QString>
5
+#include <QList>
6
+
7
+class Asm
8
+{
9
+public:
10
+    Asm();
11
+    void strip_comment(QString*);
12
+    QList<QStringList>* parse(QString);
13
+};
14
+
15
+#endif // ASM_H

+ 29
- 0
block.cpp View File

@@ -0,0 +1,29 @@
1
+#include "block.h"
2
+
3
+Block::Block() {
4
+}
5
+
6
+Block::Block(uint16_t word)
7
+{
8
+    tile = word & 0x3ff;
9
+    collision = (word >> 10) & 0x3;
10
+    elevation = (word >> 12) & 0xf;
11
+}
12
+
13
+Block::Block(const Block &block) {
14
+    tile = block.tile;
15
+    collision = block.collision;
16
+    elevation = block.elevation;
17
+}
18
+
19
+uint16_t Block::rawValue() {
20
+    return (tile & 0x3ff) + ((collision & 0x3) << 10) + ((elevation & 0xf) << 12);
21
+}
22
+
23
+bool Block::operator ==(Block other) {
24
+    return (tile == other.tile) && (collision == other.collision) && (elevation == other.elevation);
25
+}
26
+
27
+bool Block::operator !=(Block other) {
28
+    return !(operator ==(other));
29
+}

+ 20
- 0
block.h View File

@@ -0,0 +1,20 @@
1
+#ifndef BLOCK_H
2
+#define BLOCK_H
3
+
4
+#include <QObject>
5
+
6
+class Block
7
+{
8
+public:
9
+    Block();
10
+    Block(uint16_t);
11
+    Block(const Block&);
12
+    bool operator ==(Block);
13
+    bool operator !=(Block);
14
+    uint16_t tile:10;
15
+    uint16_t collision:2;
16
+    uint16_t elevation:4;
17
+    uint16_t rawValue();
18
+};
19
+
20
+#endif // BLOCK_H

+ 39
- 0
blockdata.cpp View File

@@ -0,0 +1,39 @@
1
+#include "blockdata.h"
2
+
3
+Blockdata::Blockdata(QObject *parent) : QObject(parent)
4
+{
5
+    blocks = new QList<Block>;
6
+}
7
+
8
+void Blockdata::addBlock(uint16_t word) {
9
+    Block block(word);
10
+    blocks->append(block);
11
+}
12
+
13
+void Blockdata::addBlock(Block block) {
14
+    blocks->append(block);
15
+}
16
+
17
+QByteArray Blockdata::serialize() {
18
+    QByteArray data;
19
+    for (int i = 0; i < blocks->length(); i++) {
20
+        Block block = blocks->value(i);
21
+        uint16_t word = block.rawValue();
22
+        data.append(word & 0xff);
23
+        data.append((word >> 8) & 0xff);
24
+    }
25
+    return data;
26
+}
27
+
28
+void Blockdata::copyFrom(Blockdata* other) {
29
+    blocks->clear();
30
+    for (int i = 0; i < other->blocks->length(); i++) {
31
+        addBlock(other->blocks->value(i));
32
+    }
33
+}
34
+
35
+Blockdata* Blockdata::copy() {
36
+    Blockdata* blockdata = new Blockdata;
37
+    blockdata->copyFrom(this);
38
+    return blockdata;
39
+}

+ 28
- 0
blockdata.h View File

@@ -0,0 +1,28 @@
1
+#ifndef BLOCKDATA_H
2
+#define BLOCKDATA_H
3
+
4
+#include "block.h"
5
+
6
+#include <QObject>
7
+#include <QByteArray>
8
+
9
+class Blockdata : public QObject
10
+{
11
+    Q_OBJECT
12
+public:
13
+    explicit Blockdata(QObject *parent = 0);
14
+
15
+public:
16
+    QList<Block> *blocks;
17
+    void addBlock(uint16_t);
18
+    void addBlock(Block);
19
+    QByteArray serialize();
20
+    void copyFrom(Blockdata*);
21
+    Blockdata* copy();
22
+
23
+signals:
24
+
25
+public slots:
26
+};
27
+
28
+#endif // BLOCKDATA_H

+ 324
- 0
editor.cpp View File

@@ -0,0 +1,324 @@
1
+#include "editor.h"
2
+
3
+Editor::Editor()
4
+{
5
+
6
+}
7
+
8
+void Editor::saveProject() {
9
+    if (project) {
10
+        project->saveAllMaps();
11
+    }
12
+}
13
+
14
+void Editor::save() {
15
+    if (project && map) {
16
+        project->saveMap(map);
17
+    }
18
+}
19
+
20
+void Editor::undo() {
21
+    if (current_view) {
22
+        ((MapPixmapItem*)current_view)->undo();
23
+    }
24
+}
25
+
26
+void Editor::redo() {
27
+    if (current_view) {
28
+        ((MapPixmapItem*)current_view)->redo();
29
+    }
30
+}
31
+
32
+void Editor::setEditingMap() {
33
+    current_view = map_item;
34
+    map_item->draw();
35
+    map_item->setVisible(true);
36
+    map_item->setEnabled(true);
37
+    collision_item->setVisible(false);
38
+    objects_group->setVisible(false);
39
+}
40
+
41
+void Editor::setEditingCollision() {
42
+    current_view = collision_item;
43
+    collision_item->draw();
44
+    collision_item->setVisible(true);
45
+    map_item->setVisible(false);
46
+    objects_group->setVisible(false);
47
+}
48
+
49
+void Editor::setEditingObjects() {
50
+    objects_group->setVisible(true);
51
+    map_item->setVisible(true);
52
+    map_item->setEnabled(false);
53
+    collision_item->setVisible(false);
54
+}
55
+
56
+void Editor::setMap(QString map_name) {
57
+    if (map_name.isNull()) {
58
+        return;
59
+    }
60
+    map = project->getMap(map_name);
61
+    displayMap();
62
+}
63
+
64
+void Editor::displayMap() {
65
+    scene = new QGraphicsScene;
66
+
67
+    map_item = new MapPixmapItem(map);
68
+    map_item->draw();
69
+    scene->addItem(map_item);
70
+
71
+    collision_item = new CollisionPixmapItem(map);
72
+    collision_item->draw();
73
+    scene->addItem(collision_item);
74
+
75
+    objects_group = new QGraphicsItemGroup;
76
+    scene->addItem(objects_group);
77
+
78
+    map_item->setVisible(false);
79
+    collision_item->setVisible(false);
80
+    objects_group->setVisible(false);
81
+
82
+    int tw = 16;
83
+    int th = 16;
84
+    scene->setSceneRect(
85
+        -6 * tw,
86
+        -6 * th,
87
+        map_item->pixmap().width() + 12 * tw,
88
+        map_item->pixmap().height() + 12 * th
89
+    );
90
+
91
+    displayMetatiles();
92
+    displayCollisionMetatiles();
93
+    displayElevationMetatiles();
94
+    displayMapObjects();
95
+    displayMapConnections();
96
+    displayMapBorder();
97
+}
98
+
99
+void Editor::displayMetatiles() {
100
+    scene_metatiles = new QGraphicsScene;
101
+    metatiles_item = new MetatilesPixmapItem(map);
102
+    metatiles_item->draw();
103
+    scene_metatiles->addItem(metatiles_item);
104
+}
105
+
106
+void Editor::displayCollisionMetatiles() {
107
+    scene_collision_metatiles = new QGraphicsScene;
108
+    collision_metatiles_item = new CollisionMetatilesPixmapItem(map);
109
+    collision_metatiles_item->draw();
110
+    scene_collision_metatiles->addItem(collision_metatiles_item);
111
+}
112
+
113
+void Editor::displayElevationMetatiles() {
114
+    scene_elevation_metatiles = new QGraphicsScene;
115
+    elevation_metatiles_item = new ElevationMetatilesPixmapItem(map);
116
+    elevation_metatiles_item->draw();
117
+    scene_elevation_metatiles->addItem(elevation_metatiles_item);
118
+}
119
+
120
+void Editor::displayMapObjects() {
121
+    for (QGraphicsItem *child : objects_group->childItems()) {
122
+        objects_group->removeFromGroup(child);
123
+    }
124
+
125
+    project->loadObjectPixmaps(map->object_events);
126
+    for (int i = 0; i < map->object_events.length(); i++) {
127
+        ObjectEvent *object_event = map->object_events.value(i);
128
+        DraggablePixmapItem *object = new DraggablePixmapItem(object_event);
129
+        objects_group->addToGroup(object);
130
+    }
131
+    objects_group->setFiltersChildEvents(false);
132
+}
133
+
134
+void Editor::displayMapConnections() {
135
+    for (Connection *connection : map->connections) {
136
+        if (connection->direction == "dive" || connection->direction == "emerge") {
137
+            continue;
138
+        }
139
+        Map *connected_map = project->getMap(connection->map_name);
140
+        QPixmap pixmap = connected_map->renderConnection(*connection);
141
+        int offset = connection->offset.toInt(nullptr, 0);
142
+        int x, y;
143
+        if (connection->direction == "up") {
144
+            x = offset * 16;
145
+            y = -pixmap.height();
146
+        } else if (connection->direction == "down") {
147
+            x = offset * 16;
148
+            y = map->getHeight() * 16;
149
+        } else if (connection->direction == "left") {
150
+            x = -pixmap.width();
151
+            y = offset * 16;
152
+        } else if (connection->direction == "right") {
153
+            x = map->getWidth() * 16;
154
+            y = offset * 16;
155
+        }
156
+        QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
157
+        item->setX(x);
158
+        item->setY(y);
159
+        scene->addItem(item);
160
+    }
161
+}
162
+
163
+void Editor::displayMapBorder() {
164
+    QPixmap pixmap = map->renderBorder();
165
+    for (int y = -6; y < map->getHeight() + 6; y += 2)
166
+    for (int x = -6; x < map->getWidth() + 6; x += 2) {
167
+        QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
168
+        item->setX(x * 16);
169
+        item->setY(y * 16);
170
+        item->setZValue(-1);
171
+        scene->addItem(item);
172
+    }
173
+}
174
+
175
+
176
+void MetatilesPixmapItem::draw() {
177
+    setPixmap(map->renderMetatiles());
178
+}
179
+
180
+void MetatilesPixmapItem::pick(uint tile) {
181
+    map->paint_tile = tile;
182
+    draw();
183
+}
184
+
185
+void MetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
186
+    QPointF pos = event->pos();
187
+    int x = ((int)pos.x()) / 16;
188
+    int y = ((int)pos.y()) / 16;
189
+    //qDebug() << QString("(%1, %2)").arg(x).arg(y);
190
+    int width = pixmap().width() / 16;
191
+    int height = pixmap().height() / 16;
192
+    if ((x >= 0 && x < width) && (y >=0 && y < height)) {
193
+        pick(y * width + x);
194
+    }
195
+}
196
+void MetatilesPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
197
+    mousePressEvent(event);
198
+}
199
+
200
+
201
+void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
202
+    if (map) {
203
+        QPointF pos = event->pos();
204
+        int x = (int)(pos.x()) / 16;
205
+        int y = (int)(pos.y()) / 16;
206
+        Block *block = map->getBlock(x, y);
207
+        if (block) {
208
+            block->tile = map->paint_tile;
209
+            map->setBlock(x, y, *block);
210
+        }
211
+        draw();
212
+    }
213
+}
214
+
215
+void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
216
+    if (map) {
217
+        QPointF pos = event->pos();
218
+        int x = (int)(pos.x()) / 16;
219
+        int y = (int)(pos.y()) / 16;
220
+        map->floodFill(x, y, map->paint_tile);
221
+        draw();
222
+    }
223
+}
224
+
225
+void MapPixmapItem::draw() {
226
+    setPixmap(map->render());
227
+}
228
+
229
+void MapPixmapItem::undo() {
230
+    map->undo();
231
+    draw();
232
+}
233
+
234
+void MapPixmapItem::redo() {
235
+    map->redo();
236
+    draw();
237
+}
238
+
239
+void MapPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
240
+    active = true;
241
+    if (event->button() == Qt::RightButton) {
242
+        right_click = true;
243
+        floodFill(event);
244
+    } else {
245
+        right_click = false;
246
+        paint(event);
247
+    }
248
+}
249
+void MapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
250
+    if (active) {
251
+        if (right_click) {
252
+            floodFill(event);
253
+        } else {
254
+            paint(event);
255
+        }
256
+    }
257
+}
258
+void MapPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
259
+    active = false;
260
+}
261
+
262
+void CollisionPixmapItem::draw() {
263
+    setPixmap(map->renderCollision());
264
+}
265
+
266
+void CollisionPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
267
+    if (map) {
268
+        QPointF pos = event->pos();
269
+        int x = (int)(pos.x()) / 16;
270
+        int y = (int)(pos.y()) / 16;
271
+        Block *block = map->getBlock(x, y);
272
+        if (block) {
273
+            if (map->paint_collision >= 0) {
274
+                block->collision = map->paint_collision;
275
+            }
276
+            if (map->paint_elevation >= 0) {
277
+                block->elevation = map->paint_elevation;
278
+            }
279
+            map->setBlock(x, y, *block);
280
+        }
281
+        draw();
282
+    }
283
+}
284
+
285
+void CollisionPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
286
+    if (map) {
287
+        QPointF pos = event->pos();
288
+        int x = (int)(pos.x()) / 16;
289
+        int y = (int)(pos.y()) / 16;
290
+        bool collision = map->paint_collision >= 0;
291
+        bool elevation = map->paint_elevation >= 0;
292
+        if (collision && elevation) {
293
+            map->floodFillCollisionElevation(x, y, map->paint_collision, map->paint_elevation);
294
+        } else if (collision) {
295
+            map->floodFillCollision(x, y, map->paint_collision);
296
+        } else if (elevation) {
297
+            map->floodFillElevation(x, y, map->paint_elevation);
298
+        }
299
+        draw();
300
+    }
301
+}
302
+
303
+void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
304
+    active = true;
305
+    last_x = mouse->pos().x() / 16;
306
+    last_y = mouse->pos().y() / 16;
307
+    qDebug() << event->x_ + ", " + event->y_;
308
+}
309
+
310
+void DraggablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouse) {
311
+    if (active) {
312
+        int x = mouse->pos().x() / 16;
313
+        int y = mouse->pos().y() / 16;
314
+        if (x != last_x || y != last_y) {
315
+            event->setX(event->x() + x - last_x);
316
+            event->setY(event->y() + y - last_y);
317
+            update();
318
+        }
319
+    }
320
+}
321
+
322
+void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouse) {
323
+    active = false;
324
+}

+ 155
- 0
editor.h View File

@@ -0,0 +1,155 @@
1
+#ifndef EDITOR_H
2
+#define EDITOR_H
3
+
4
+#include <QGraphicsScene>
5
+#include <QGraphicsItemGroup>
6
+#include <QGraphicsSceneMouseEvent>
7
+
8
+#include "project.h"
9
+
10
+
11
+class DraggablePixmapItem : public QGraphicsPixmapItem {
12
+public:
13
+    DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {
14
+    }
15
+    Event *event;
16
+    DraggablePixmapItem(Event *event_) : QGraphicsPixmapItem(event_->pixmap) {
17
+        event = event_;
18
+        update();
19
+    }
20
+    bool active;
21
+    bool right_click;
22
+    int last_x;
23
+    int last_y;
24
+    void update() {
25
+        int x = event->x() * 16;
26
+        int y = event->y() * 16;
27
+        x -= pixmap().width() / 32 * 16;
28
+        y -= pixmap().height() - 16;
29
+        setX(x);
30
+        setY(y);
31
+        setZValue(event->y());
32
+    }
33
+
34
+protected:
35
+    void mousePressEvent(QGraphicsSceneMouseEvent*);
36
+    void mouseMoveEvent(QGraphicsSceneMouseEvent*);
37
+    void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
38
+};
39
+
40
+class MapPixmapItem : public QGraphicsPixmapItem {
41
+public:
42
+    MapPixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {
43
+    }
44
+    Map *map;
45
+    MapPixmapItem(Map *map_) {
46
+        map = map_;
47
+    }
48
+    bool active;
49
+    bool right_click;
50
+    virtual void paint(QGraphicsSceneMouseEvent*);
51
+    virtual void floodFill(QGraphicsSceneMouseEvent*);
52
+    virtual void undo();
53
+    virtual void redo();
54
+    virtual void draw();
55
+
56
+protected:
57
+    void mousePressEvent(QGraphicsSceneMouseEvent*);
58
+    void mouseMoveEvent(QGraphicsSceneMouseEvent*);
59
+    void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
60
+};
61
+
62
+class CollisionPixmapItem : public MapPixmapItem {
63
+public:
64
+    CollisionPixmapItem(QPixmap pixmap): MapPixmapItem(pixmap) {
65
+    }
66
+    CollisionPixmapItem(Map *map_): MapPixmapItem(map_) {
67
+    }
68
+
69
+public:
70
+    virtual void paint(QGraphicsSceneMouseEvent*);
71
+    virtual void floodFill(QGraphicsSceneMouseEvent*);
72
+    virtual void draw();
73
+};
74
+
75
+class MetatilesPixmapItem : public QGraphicsPixmapItem {
76
+public:
77
+    MetatilesPixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {
78
+    }
79
+    MetatilesPixmapItem(Map *map_) {
80
+        map = map_;
81
+    }
82
+    Map* map;
83
+    virtual void pick(uint);
84
+    virtual void draw();
85
+protected:
86
+    void mousePressEvent(QGraphicsSceneMouseEvent*);
87
+    void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
88
+};
89
+
90
+class CollisionMetatilesPixmapItem : public MetatilesPixmapItem {
91
+public:
92
+    CollisionMetatilesPixmapItem(Map *map_): MetatilesPixmapItem(map_) {
93
+    }
94
+    virtual void pick(uint collision) {
95
+        map->paint_collision = collision;
96
+        draw();
97
+    }
98
+    virtual void draw() {
99
+        setPixmap(map->renderCollisionMetatiles());
100
+    }
101
+};
102
+
103
+class ElevationMetatilesPixmapItem : public MetatilesPixmapItem {
104
+public:
105
+    ElevationMetatilesPixmapItem(Map *map_): MetatilesPixmapItem(map_) {
106
+    }
107
+    virtual void pick(uint elevation) {
108
+        map->paint_elevation = elevation;
109
+        draw();
110
+    }
111
+    virtual void draw() {
112
+        setPixmap(map->renderElevationMetatiles());
113
+    }
114
+};
115
+
116
+
117
+class Editor
118
+{
119
+public:
120
+    Editor();
121
+public:
122
+    Project *project;
123
+    Map *map;
124
+    void saveProject();
125
+    void save();
126
+    void undo();
127
+    void redo();
128
+    void setMap(QString map_name);
129
+    void displayMap();
130
+    void displayMetatiles();
131
+    void displayCollisionMetatiles();
132
+    void displayElevationMetatiles();
133
+    void displayMapObjects();
134
+    void displayMapConnections();
135
+    void displayMapBorder();
136
+
137
+    void setEditingMap();
138
+    void setEditingCollision();
139
+    void setEditingObjects();
140
+
141
+    QGraphicsScene *scene;
142
+    QGraphicsPixmapItem *current_view;
143
+    MapPixmapItem *map_item;
144
+    CollisionPixmapItem *collision_item;
145
+    QGraphicsItemGroup *objects_group;
146
+
147
+    QGraphicsScene *scene_metatiles;
148
+    QGraphicsScene *scene_collision_metatiles;
149
+    QGraphicsScene *scene_elevation_metatiles;
150
+    MetatilesPixmapItem *metatiles_item;
151
+    CollisionMetatilesPixmapItem *collision_metatiles_item;
152
+    ElevationMetatilesPixmapItem *elevation_metatiles_item;
153
+};
154
+
155
+#endif // EDITOR_H

+ 52
- 0
event.cpp View File

@@ -0,0 +1,52 @@
1
+#include "event.h"
2
+
3
+Event::Event()
4
+{
5
+
6
+}
7
+
8
+ObjectEvent::ObjectEvent()
9
+{
10
+
11
+}
12
+
13
+Warp::Warp()
14
+{
15
+
16
+}
17
+
18
+CoordEvent::CoordEvent()
19
+{
20
+
21
+}
22
+
23
+BGEvent::BGEvent()
24
+{
25
+
26
+}
27
+
28
+Sign::Sign()
29
+{
30
+
31
+}
32
+
33
+Sign::Sign(const BGEvent &bg)
34
+{
35
+    x_ = bg.x_;
36
+    y_ = bg.y_;
37
+    elevation_ = bg.elevation_;
38
+    type = bg.type;
39
+}
40
+
41
+HiddenItem::HiddenItem()
42
+{
43
+
44
+}
45
+
46
+HiddenItem::HiddenItem(const BGEvent &bg)
47
+{
48
+    x_ = bg.x_;
49
+    y_ = bg.y_;
50
+    elevation_ = bg.elevation_;
51
+    type = bg.type;
52
+}

+ 100
- 0
event.h View File

@@ -0,0 +1,100 @@
1
+#ifndef EVENT_H
2
+#define EVENT_H
3
+
4
+#include <QString>
5
+#include <QPixmap>
6
+
7
+class Event
8
+{
9
+public:
10
+    Event();
11
+
12
+public:
13
+    int x() {
14
+        return x_.toInt(nullptr, 0);
15
+    }
16
+    int y() {
17
+        return y_.toInt(nullptr, 0);
18
+    }
19
+    int elevation() {
20
+        return elevation_.toInt(nullptr, 0);
21
+    }
22
+    void setX(int x) {
23
+        x_ = QString("%1").arg(x);
24
+    }
25
+    void setY(int y) {
26
+        y_ = QString("%1").arg(y);
27
+    }
28
+
29
+    QString x_;
30
+    QString y_;
31
+    QString elevation_;
32
+    QPixmap pixmap;
33
+};
34
+
35
+class ObjectEvent : public Event {
36
+public:
37
+    ObjectEvent();
38
+
39
+public:
40
+    QString sprite;
41
+    QString replacement; // ????
42
+    QString behavior;
43
+    QString radius_x;
44
+    QString radius_y;
45
+    QString property;
46
+    QString sight_radius;
47
+    QString script_label;
48
+    QString event_flag;
49
+};
50
+
51
+class Warp : public Event {
52
+public:
53
+    Warp();
54
+
55
+public:
56
+    QString destination_warp;
57
+    QString destination_map;
58
+};
59
+
60
+class CoordEvent : public Event {
61
+public:
62
+    CoordEvent();
63
+
64
+public:
65
+    QString unknown1;
66
+    QString unknown2;
67
+    QString unknown3;
68
+    QString unknown4;
69
+    QString script_label;
70
+};
71
+
72
+class BGEvent : public Event {
73
+public:
74
+    BGEvent();
75
+public:
76
+    bool is_item() {
77
+        return type.toInt(nullptr, 0) >= 5;
78
+    }
79
+    QString type;
80
+};
81
+
82
+class Sign : public BGEvent {
83
+public:
84
+    Sign();
85
+    Sign(const BGEvent&);
86
+public:
87
+    QString script_label;
88
+};
89
+
90
+class HiddenItem : public BGEvent {
91
+public:
92
+    HiddenItem();
93
+    HiddenItem(const BGEvent&);
94
+public:
95
+    QString item;
96
+    QString unknown5;
97
+    QString unknown6;
98
+};
99
+
100
+#endif // EVENT_H

+ 11
- 0
main.cpp View File

@@ -0,0 +1,11 @@
1
+#include "mainwindow.h"
2
+#include <QApplication>
3
+
4
+int main(int argc, char *argv[])
5
+{
6
+    QApplication a(argc, argv);
7
+    MainWindow w;
8
+    w.show();
9
+
10
+    return a.exec();
11
+}

+ 370
- 0
mainwindow.cpp View File

@@ -0,0 +1,370 @@
1
+#include "mainwindow.h"
2
+#include "ui_mainwindow.h"
3
+#include "project.h"
4
+
5
+#include <QDebug>
6
+#include <QFileDialog>
7
+#include <QStandardItemModel>
8
+#include <QShortcut>
9
+#include <QSettings>
10
+
11
+MainWindow::MainWindow(QWidget *parent) :
12
+    QMainWindow(parent),
13
+    ui(new Ui::MainWindow)
14
+{
15
+    QCoreApplication::setOrganizationName("pret");
16
+    QCoreApplication::setApplicationName("pretmap");
17
+
18
+    editor = new Editor;
19
+
20
+    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z), this, SLOT(redo()));
21
+    ui->setupUi(this);
22
+
23
+    QSettings settings;
24
+    QString key = "recent_projects";
25
+    if (settings.contains(key)) {
26
+        QString default_dir = settings.value(key).toStringList().last();
27
+        openProject(default_dir);
28
+    }
29
+}
30
+
31
+MainWindow::~MainWindow()
32
+{
33
+    delete ui;
34
+}
35
+
36
+void MainWindow::openProject(QString dir) {
37
+    bool already_open = (editor->project != NULL) && (editor->project->root == dir);
38
+    if (!already_open) {
39
+        editor->project = new Project;
40
+        editor->project->root = dir;
41
+        populateMapList();
42
+        setMap(getDefaultMap());
43
+    } else {
44
+        populateMapList();
45
+    }
46
+}
47
+
48
+QString MainWindow::getDefaultMap() {
49
+    QSettings settings;
50
+    QString key = "project:" + editor->project->root;
51
+    if (settings.contains(key)) {
52
+        QMap<QString, QVariant> qmap = settings.value(key).toMap();
53
+        if (qmap.contains("recent_map")) {
54
+            QString map_name = qmap.value("recent_map").toString();
55
+            return map_name;
56
+        }
57
+    }
58
+    // Failing that, just get the first map in the list.
59
+    for (int i = 0; i < editor->project->groupedMapNames->length(); i++) {
60
+        QStringList *list = editor->project->groupedMapNames->value(i);
61
+        if (list->length()) {
62
+            return list->value(0);
63
+        }
64
+    }
65
+    return NULL;
66
+}
67
+
68
+QString MainWindow::getExistingDirectory(QString dir) {
69
+    return QFileDialog::getExistingDirectory(this, "Open Directory", dir, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
70
+}
71
+
72
+void MainWindow::on_action_Open_Project_triggered()
73
+{
74
+    QSettings settings;
75
+    QString key = "recent_projects";
76
+    QString recent = ".";
77
+    if (settings.contains(key)) {
78
+        recent = settings.value(key).toStringList().last();
79
+    }
80
+    QString dir = getExistingDirectory(recent);
81
+    if (!dir.isEmpty()) {
82
+        QStringList recents;
83
+        if (settings.contains(key)) {
84
+            recents = settings.value(key).toStringList();
85
+        }
86
+        recents.removeAll(dir);
87
+        recents.append(dir);
88
+        settings.setValue(key, recents);
89
+
90
+        openProject(dir);
91
+    }
92
+}
93
+
94
+void MainWindow::setMap(QString map_name) {
95
+    if (map_name.isNull()) {
96
+        return;
97
+    }
98
+    editor->setMap(map_name);
99
+
100
+    if (ui->tabWidget->currentIndex() == 1) {
101
+        editor->setEditingObjects();
102
+    } else {
103
+        if (ui->tabWidget_2->currentIndex() == 1) {
104
+            editor->setEditingCollision();
105
+        } else {
106
+            editor->setEditingMap();
107
+        }
108
+    }
109
+
110
+    ui->graphicsView_Map->setScene(editor->scene);
111
+    ui->graphicsView_Map->setSceneRect(editor->scene->sceneRect());
112
+    ui->graphicsView_Map->setFixedSize(editor->scene->width() + 2, editor->scene->height() + 2);
113
+
114
+    ui->graphicsView_Objects_Map->setScene(editor->scene);
115
+    ui->graphicsView_Objects_Map->setSceneRect(editor->scene->sceneRect());
116
+    ui->graphicsView_Objects_Map->setFixedSize(editor->scene->width() + 2, editor->scene->height() + 2);
117
+
118
+    ui->graphicsView_Metatiles->setScene(editor->scene_metatiles);
119
+    //ui->graphicsView_Metatiles->setSceneRect(editor->scene_metatiles->sceneRect());
120
+    ui->graphicsView_Metatiles->setFixedSize(editor->metatiles_item->pixmap().width() + 2, editor->metatiles_item->pixmap().height() + 2);
121
+
122
+    ui->graphicsView_Collision->setScene(editor->scene_collision_metatiles);
123
+    //ui->graphicsView_Collision->setSceneRect(editor->scene_collision_metatiles->sceneRect());
124
+    ui->graphicsView_Collision->setFixedSize(editor->collision_metatiles_item->pixmap().width() + 2, editor->collision_metatiles_item->pixmap().height() + 2);
125
+
126
+    ui->graphicsView_Elevation->setScene(editor->scene_elevation_metatiles);
127
+    //ui->graphicsView_Elevation->setSceneRect(editor->scene_elevation_metatiles->sceneRect());
128
+    ui->graphicsView_Elevation->setFixedSize(editor->elevation_metatiles_item->pixmap().width() + 2, editor->elevation_metatiles_item->pixmap().height() + 2);
129
+
130
+    displayMapProperties();
131
+
132
+    setRecentMap(map_name);
133
+    updateMapList();
134
+}
135
+
136
+void MainWindow::setRecentMap(QString map_name) {
137
+    QSettings settings;
138
+    QString key = "project:" + editor->project->root;
139
+    QMap<QString, QVariant> qmap;
140
+    if (settings.contains(key)) {
141
+        qmap = settings.value(key).toMap();
142
+    }
143
+    qmap.insert("recent_map", map_name);
144
+    settings.setValue(key, qmap);
145
+}
146
+
147
+void MainWindow::displayMapProperties() {
148
+    Map *map = editor->map;
149
+    Project *project = editor->project;
150
+
151
+    QStringList songs = project->getSongNames();
152
+    ui->comboBox_Song->clear();
153
+    ui->comboBox_Song->addItems(songs);
154
+    QString song = map->song;
155
+    if (!songs.contains(song)) {
156
+        song = project->getSongName(song.toInt());
157
+    }
158
+    ui->comboBox_Song->setCurrentText(song);
159
+
160
+    ui->comboBox_Location->clear();
161
+    ui->comboBox_Location->addItems(project->getLocations());
162
+    ui->comboBox_Location->setCurrentText(map->location);
163
+
164
+    ui->comboBox_Visibility->clear();
165
+    ui->comboBox_Visibility->addItems(project->getVisibilities());
166
+    ui->comboBox_Visibility->setCurrentText(map->visibility);
167
+
168
+    ui->comboBox_Weather->clear();
169
+    ui->comboBox_Weather->addItems(project->getWeathers());
170
+    ui->comboBox_Weather->setCurrentText(map->weather);
171
+
172
+    ui->comboBox_Type->clear();
173
+    ui->comboBox_Type->addItems(project->getMapTypes());
174
+    ui->comboBox_Type->setCurrentText(map->type);
175
+
176
+    ui->comboBox_BattleScene->clear();
177
+    ui->comboBox_BattleScene->addItems(project->getBattleScenes());
178
+    ui->comboBox_BattleScene->setCurrentText(map->battle_scene);
179
+
180
+    ui->checkBox_ShowLocation->setChecked(map->show_location.toInt() > 0 || map->show_location == "TRUE");
181
+}
182
+
183
+void MainWindow::on_comboBox_Song_activated(const QString &song)
184
+{
185
+    editor->map->song = song;
186
+}
187
+
188
+void MainWindow::on_comboBox_Location_activated(const QString &location)
189
+{
190
+    editor->map->location = location;
191
+}
192
+
193
+void MainWindow::on_comboBox_Visibility_activated(const QString &visibility)
194
+{
195
+    editor->map->visibility = visibility;
196
+}
197
+
198
+void MainWindow::on_comboBox_Weather_activated(const QString &weather)
199
+{
200
+    editor->map->weather = weather;
201
+}
202
+
203
+void MainWindow::on_comboBox_Type_activated(const QString &type)
204
+{
205
+    editor->map->type = type;
206
+}
207
+
208
+void MainWindow::on_comboBox_BattleScene_activated(const QString &battle_scene)
209
+{
210
+    editor->map->battle_scene = battle_scene;
211
+}
212
+
213
+void MainWindow::on_checkBox_ShowLocation_clicked(bool checked)
214
+{
215
+    if (checked) {
216
+        editor->map->show_location = "TRUE";
217
+    } else {
218
+        editor->map->show_location = "FALSE";
219
+    }
220
+}
221
+
222
+
223
+void MainWindow::populateMapList() {
224
+    Project *project = editor->project;
225
+
226
+    QIcon mapFolderIcon;
227
+    mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off);
228
+    mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On);
229
+
230
+    QIcon folderIcon;
231
+    folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off);
232
+
233
+    QIcon mapIcon;
234
+    mapIcon.addFile(QStringLiteral(":/icons/map.ico"), QSize(), QIcon::Normal, QIcon::Off);
235
+    mapIcon.addFile(QStringLiteral(":/icons/image.ico"), QSize(), QIcon::Normal, QIcon::On);
236
+
237
+    QStandardItemModel *model = new QStandardItemModel;
238
+
239
+    QStandardItem *entry = new QStandardItem;
240
+    entry->setText(project->getProjectTitle());
241
+    entry->setIcon(folderIcon);
242
+    entry->setEditable(false);
243
+    model->appendRow(entry);
244
+
245
+    QStandardItem *maps = new QStandardItem;
246
+    maps->setText("maps");
247
+    maps->setIcon(folderIcon);
248
+    maps->setEditable(false);
249
+    entry->appendRow(maps);
250
+
251
+    project->readMapGroups();
252
+    for (int i = 0; i < project->groupNames->length(); i++) {
253
+        QString group_name = project->groupNames->value(i);
254
+        QStandardItem *group = new QStandardItem;
255
+        group->setText(group_name);
256
+        group->setIcon(mapFolderIcon);
257
+        group->setEditable(false);
258
+        maps->appendRow(group);
259
+        QStringList *names = project->groupedMapNames->value(i);
260
+        for (int j = 0; j < names->length(); j++) {
261
+            QString map_name = names->value(j);
262
+            QStandardItem *map = new QStandardItem;
263
+            map->setText(QString("[%1.%2] ").arg(i).arg(j, 2, 10, QLatin1Char('0')) + map_name);
264
+            map->setIcon(mapIcon);
265
+            map->setEditable(false);
266
+            map->setData(map_name, Qt::UserRole);
267
+            group->appendRow(map);
268
+            //ui->mapList->setExpanded(model->indexFromItem(map), false); // redundant
269
+        }
270
+    }
271
+
272
+    ui->mapList->setModel(model);
273
+    ui->mapList->setUpdatesEnabled(true);
274
+    ui->mapList->expandToDepth(2);
275
+    ui->mapList->repaint();
276
+}
277
+
278
+void MainWindow::on_mapList_activated(const QModelIndex &index)
279
+{
280
+    QVariant data = index.data(Qt::UserRole);
281
+    if (!data.isNull()) {
282
+        setMap(data.toString());
283
+    }
284
+    updateMapList();
285
+}
286
+
287
+void MainWindow::markAllEdited(QAbstractItemModel *model) {
288
+    QList<QModelIndex> list;
289
+    list.append(QModelIndex());
290
+    while (list.length()) {
291
+        QModelIndex parent = list.takeFirst();
292
+        for (int i = 0; i < model->rowCount(parent); i++) {
293
+            QModelIndex index = model->index(i, 0, parent);
294
+            if (model->hasChildren(index)) {
295
+                list.append(index);
296
+            }
297
+            markEdited(index);
298
+        }
299
+    }
300
+}
301
+
302
+void MainWindow::markEdited(QModelIndex index) {
303
+    QVariant data = index.data(Qt::UserRole);
304
+    if (!data.isNull()) {
305
+        QString map_name = data.toString();
306
+        if (editor->project) {
307
+            if (editor->project->map_cache->contains(map_name)) {
308
+                // Just mark anything that's been opened for now.
309
+                // TODO if (project->getMap()->saved)
310
+                ui->mapList->setExpanded(index, true);
311
+            }
312
+        }
313
+    }
314
+}
315
+
316
+void MainWindow::updateMapList() {
317
+    QAbstractItemModel *model = ui->mapList->model();
318
+    markAllEdited(model);
319
+}
320
+
321
+void MainWindow::on_action_Save_Project_triggered()
322
+{
323
+    editor->saveProject();
324
+    updateMapList();
325
+}
326
+
327
+void MainWindow::undo() {
328
+    editor->undo();
329
+}
330
+
331
+void MainWindow::redo() {
332
+    editor->redo();
333
+}
334
+
335
+void MainWindow::on_action_Save_triggered() {
336
+    editor->save();
337
+}
338
+
339
+void MainWindow::on_tabWidget_2_currentChanged(int index)
340
+{
341
+    if (index == 0) {
342
+        editor->setEditingMap();
343
+    } else if (index == 1) {
344
+        editor->setEditingCollision();
345
+    }
346
+}
347
+
348
+void MainWindow::on_action_Exit_triggered()
349
+{
350
+    QApplication::quit();
351
+}
352
+
353
+void MainWindow::on_tabWidget_currentChanged(int index)
354
+{
355
+    if (index == 0) {
356
+        on_tabWidget_2_currentChanged(ui->tabWidget_2->currentIndex());
357
+    } else if (index == 1) {
358
+        editor->setEditingObjects();
359
+    }
360
+}
361
+
362
+void MainWindow::on_actionUndo_triggered()
363
+{
364
+    undo();
365
+}
366
+
367
+void MainWindow::on_actionRedo_triggered()
368
+{
369
+    redo();
370
+}

+ 69
- 0
mainwindow.h View File

@@ -0,0 +1,69 @@
1
+#ifndef MAINWINDOW_H
2
+#define MAINWINDOW_H
3
+
4
+#include <QString>
5
+#include <QModelIndex>
6
+#include <QMainWindow>
7
+#include <QGraphicsPixmapItem>
8
+#include <QGraphicsItemGroup>
9
+#include <QGraphicsSceneMouseEvent>
10
+#include <QAbstractItemModel>
11
+#include "project.h"
12
+#include "map.h"
13
+#include "editor.h"
14
+
15
+namespace Ui {
16
+class MainWindow;
17
+}
18
+
19
+class MainWindow : public QMainWindow
20
+{
21
+    Q_OBJECT
22
+
23
+public:
24
+    explicit MainWindow(QWidget *parent = 0);
25
+    ~MainWindow();
26
+
27
+private slots:
28
+    void on_action_Open_Project_triggered();
29
+    void on_mapList_activated(const QModelIndex &index);
30
+    void on_action_Save_Project_triggered();
31
+
32
+    void undo();
33
+    void redo();
34
+
35
+    void on_action_Save_triggered();
36
+    void on_tabWidget_2_currentChanged(int index);
37
+    void on_action_Exit_triggered();
38
+    void on_comboBox_Song_activated(const QString &arg1);
39
+    void on_comboBox_Location_activated(const QString &arg1);
40
+    void on_comboBox_Visibility_activated(const QString &arg1);
41
+    void on_comboBox_Weather_activated(const QString &arg1);
42
+    void on_comboBox_Type_activated(const QString &arg1);
43
+    void on_comboBox_BattleScene_activated(const QString &arg1);
44
+    void on_checkBox_ShowLocation_clicked(bool checked);
45
+
46
+    void on_tabWidget_currentChanged(int index);
47
+
48
+    void on_actionUndo_triggered();
49
+
50
+    void on_actionRedo_triggered();
51
+
52
+private:
53
+    Ui::MainWindow *ui;
54
+    Editor *editor;
55
+    void setMap(QString);
56
+    void populateMapList();
57
+    QString getExistingDirectory(QString);
58
+    void openProject(QString dir);
59
+    QString getDefaultMap();
60
+    void setRecentMap(QString map_name);
61
+
62
+    void markAllEdited(QAbstractItemModel *model);
63
+    void markEdited(QModelIndex index);
64
+    void updateMapList();
65
+
66
+    void displayMapProperties();
67
+};
68
+
69
+#endif // MAINWINDOW_H

+ 938
- 0
mainwindow.ui View File

@@ -0,0 +1,938 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<ui version="4.0">
3
+ <class>MainWindow</class>
4
+ <widget class="QMainWindow" name="MainWindow">
5
+  <property name="geometry">
6
+   <rect>
7
+    <x>0</x>
8
+    <y>0</y>
9
+    <width>1019</width>
10
+    <height>666</height>
11
+   </rect>
12
+  </property>
13
+  <property name="sizePolicy">
14
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
15
+    <horstretch>0</horstretch>
16
+    <verstretch>0</verstretch>
17
+   </sizepolicy>
18
+  </property>
19
+  <property name="windowTitle">
20
+   <string>MainWindow</string>
21
+  </property>
22
+  <widget class="QWidget" name="centralWidget">
23
+   <layout class="QGridLayout" name="gridLayout">
24
+    <item row="0" column="0">
25
+     <widget class="QSplitter" name="splitter">
26
+      <property name="orientation">
27
+       <enum>Qt::Horizontal</enum>
28
+      </property>
29
+      <widget class="QTreeView" name="mapList">
30
+       <property name="sizePolicy">
31
+        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
32
+         <horstretch>0</horstretch>
33
+         <verstretch>0</verstretch>
34
+        </sizepolicy>
35
+       </property>
36
+       <property name="minimumSize">
37
+        <size>
38
+         <width>100</width>
39
+         <height>0</height>
40
+        </size>
41
+       </property>
42
+       <property name="selectionMode">
43
+        <enum>QAbstractItemView::SingleSelection</enum>
44
+       </property>
45
+       <property name="selectionBehavior">
46
+        <enum>QAbstractItemView::SelectItems</enum>
47
+       </property>
48
+       <attribute name="headerVisible">
49
+        <bool>false</bool>
50
+       </attribute>
51
+      </widget>
52
+      <widget class="QTabWidget" name="tabWidget">
53
+       <property name="enabled">
54
+        <bool>true</bool>
55
+       </property>
56
+       <property name="sizePolicy">
57
+        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
58
+         <horstretch>1</horstretch>
59
+         <verstretch>0</verstretch>
60
+        </sizepolicy>
61
+       </property>
62
+       <property name="currentIndex">
63
+        <number>1</number>
64
+       </property>
65
+       <property name="tabsClosable">
66
+        <bool>false</bool>
67
+       </property>
68
+       <property name="movable">
69
+        <bool>false</bool>
70
+       </property>
71
+       <widget class="QWidget" name="tab_Map">
72
+        <attribute name="icon">
73
+         <iconset resource="resources/images.qrc">
74
+          <normaloff>:/icons/map.ico</normaloff>:/icons/map.ico</iconset>
75
+        </attribute>
76
+        <attribute name="title">
77
+         <string>Map</string>
78
+        </attribute>
79
+        <layout class="QGridLayout" name="gridLayout_2">
80
+         <property name="leftMargin">
81
+          <number>0</number>
82
+         </property>
83
+         <property name="topMargin">
84
+          <number>0</number>
85
+         </property>
86
+         <property name="rightMargin">
87
+          <number>0</number>
88
+         </property>
89
+         <property name="bottomMargin">
90
+          <number>0</number>
91
+         </property>
92
+         <property name="spacing">
93
+          <number>0</number>
94
+         </property>
95
+         <item row="0" column="0">
96
+          <widget class="QSplitter" name="splitter_2">
97
+           <property name="orientation">
98
+            <enum>Qt::Horizontal</enum>
99
+           </property>
100
+           <widget class="QScrollArea" name="scrollArea">
101
+            <property name="sizePolicy">
102
+             <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
103
+              <horstretch>1</horstretch>
104
+              <verstretch>0</verstretch>
105
+             </sizepolicy>
106
+            </property>
107
+            <property name="widgetResizable">
108
+             <bool>true</bool>
109
+            </property>
110
+            <widget class="QWidget" name="scrollAreaWidgetContents">
111
+             <property name="geometry">
112
+              <rect>
113
+               <x>0</x>
114
+               <y>0</y>
115
+               <width>571</width>
116
+               <height>564</height>
117
+              </rect>
118
+             </property>
119
+             <layout class="QGridLayout" name="gridLayout_4">
120
+              <property name="leftMargin">
121
+               <number>0</number>
122
+              </property>
123
+              <property name="topMargin">
124
+               <number>0</number>
125
+              </property>
126
+              <property name="rightMargin">
127
+               <number>0</number>
128
+              </property>
129
+              <property name="bottomMargin">
130
+               <number>0</number>
131
+              </property>
132
+              <property name="spacing">
133
+               <number>0</number>
134
+              </property>
135
+              <item row="1" column="0">
136
+               <spacer name="horizontalSpacer_2">
137
+                <property name="orientation">
138
+                 <enum>Qt::Horizontal</enum>
139
+                </property>
140
+                <property name="sizeHint" stdset="0">
141
+                 <size>
142
+                  <width>166</width>
143
+                  <height>16</height>
144
+                 </size>
145
+                </property>
146
+               </spacer>
147
+              </item>
148
+              <item row="2" column="1">
149
+               <spacer name="verticalSpacer_2">
150
+                <property name="orientation">
151
+                 <enum>Qt::Vertical</enum>
152
+                </property>
153
+                <property name="sizeHint" stdset="0">
154
+                 <size>
155
+                  <width>16</width>
156
+                  <height>166</height>
157
+                 </size>
158
+                </property>
159
+               </spacer>
160
+              </item>
161
+              <item row="1" column="2">
162
+               <spacer name="horizontalSpacer">
163
+                <property name="orientation">
164
+                 <enum>Qt::Horizontal</enum>
165
+                </property>
166
+                <property name="sizeHint" stdset="0">
167
+                 <size>
168
+                  <width>166</width>
169
+                  <height>16</height>
170
+                 </size>
171
+                </property>
172
+               </spacer>
173
+              </item>
174
+              <item row="0" column="1">
175
+               <spacer name="verticalSpacer">
176
+                <property name="orientation">
177
+                 <enum>Qt::Vertical</enum>
178
+                </property>
179
+                <property name="sizeHint" stdset="0">
180
+                 <size>
181
+                  <width>16</width>
182
+                  <height>166</height>
183
+                 </size>
184
+                </property>
185
+               </spacer>
186
+              </item>
187
+              <item row="1" column="1">
188
+               <widget class="QGraphicsView" name="graphicsView_Map">
189
+                <property name="sizePolicy">
190
+                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
191
+                  <horstretch>0</horstretch>
192
+                  <verstretch>0</verstretch>
193
+                 </sizepolicy>
194
+                </property>
195
+                <property name="autoFillBackground">
196
+                 <bool>false</bool>
197
+                </property>
198
+               </widget>
199
+              </item>
200
+             </layout>
201
+            </widget>
202
+           </widget>
203
+           <widget class="QTabWidget" name="tabWidget_2">
204
+            <property name="enabled">
205
+             <bool>true</bool>
206
+            </property>
207
+            <property name="sizePolicy">
208
+             <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
209
+              <horstretch>0</horstretch>
210
+              <verstretch>0</verstretch>
211
+             </sizepolicy>
212
+            </property>
213
+            <property name="minimumSize">
214
+             <size>
215
+              <width>156</width>
216
+              <height>0</height>
217
+             </size>
218
+            </property>
219
+            <property name="currentIndex">
220
+             <number>1</number>
221
+            </property>
222
+            <widget class="QWidget" name="tab_blocks">
223
+             <property name="sizePolicy">
224
+              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
225
+               <horstretch>0</horstretch>
226
+               <verstretch>0</verstretch>
227
+              </sizepolicy>
228
+             </property>
229
+             <attribute name="title">
230
+              <string>Blocks</string>
231
+             </attribute>
232
+             <layout class="QGridLayout" name="gridLayout_3">
233
+              <property name="leftMargin">
234
+               <number>0</number>
235
+              </property>
236
+              <property name="topMargin">
237
+               <number>0</number>
238
+              </property>
239
+              <property name="rightMargin">
240
+               <number>0</number>
241
+              </property>
242
+              <property name="bottomMargin">
243
+               <number>0</number>
244
+              </property>
245
+              <property name="spacing">
246
+               <number>0</number>
247
+              </property>
248
+              <item row="0" column="0">
249
+               <widget class="QScrollArea" name="scrollArea_2">
250
+                <property name="sizePolicy">
251
+                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
252
+                  <horstretch>0</horstretch>
253
+                  <verstretch>0</verstretch>
254
+                 </sizepolicy>
255
+                </property>
256
+                <property name="verticalScrollBarPolicy">
257
+                 <enum>Qt::ScrollBarAlwaysOn</enum>
258
+                </property>
259
+                <property name="horizontalScrollBarPolicy">
260
+                 <enum>Qt::ScrollBarAsNeeded</enum>
261
+                </property>
262
+                <property name="sizeAdjustPolicy">
263
+                 <enum>QAbstractScrollArea::AdjustIgnored</enum>
264
+                </property>
265
+                <property name="widgetResizable">
266
+                 <bool>true</bool>
267
+                </property>
268
+                <widget class="QWidget" name="scrollAreaWidgetContents_2">
269
+                 <property name="enabled">
270
+                  <bool>true</bool>
271
+                 </property>
272
+                 <property name="geometry">
273
+                  <rect>
274
+                   <x>0</x>
275
+                   <y>0</y>
276
+                   <width>81</width>
277
+                   <height>28</height>
278
+                  </rect>
279
+                 </property>
280
+                 <property name="sizePolicy">
281
+                  <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
282
+                   <horstretch>0</horstretch>
283
+                   <verstretch>0</verstretch>
284
+                  </sizepolicy>
285
+                 </property>
286
+                 <layout class="QGridLayout" name="gridLayout_5" rowstretch="0" columnstretch="0">
287
+                  <property name="leftMargin">
288
+                   <number>0</number>
289
+                  </property>
290
+                  <property name="topMargin">
291
+                   <number>0</number>
292
+                  </property>
293
+                  <property name="rightMargin">
294
+                   <number>0</number>
295
+                  </property>
296
+                  <property name="bottomMargin">
297
+                   <number>0</number>
298
+                  </property>
299
+                  <property name="spacing">
300
+                   <number>0</number>
301
+                  </property>
302
+                  <item row="0" column="0">
303
+                   <widget class="QGraphicsView" name="graphicsView_Metatiles">
304
+                    <property name="enabled">
305
+                     <bool>true</bool>
306
+                    </property>
307
+                    <property name="sizePolicy">
308
+                     <sizepolicy hsizetype="Ignored" vsizetype="Ignored">
309
+                      <horstretch>0</horstretch>
310
+                      <verstretch>0</verstretch>
311
+                     </sizepolicy>
312
+                    </property>
313
+                    <property name="verticalScrollBarPolicy">
314
+                     <enum>Qt::ScrollBarAlwaysOff</enum>
315
+                    </property>
316
+                    <property name="horizontalScrollBarPolicy">
317
+                     <enum>Qt::ScrollBarAlwaysOff</enum>
318
+                    </property>
319
+                    <property name="sizeAdjustPolicy">
320
+                     <enum>QAbstractScrollArea::AdjustIgnored</enum>
321
+                    </property>
322
+                   </widget>
323
+                  </item>
324
+                 </layout>
325
+                </widget>
326
+               </widget>
327
+              </item>
328
+             </layout>
329
+            </widget>
330
+            <widget class="QWidget" name="tab_collision">
331
+             <property name="enabled">
332
+              <bool>true</bool>
333
+             </property>
334
+             <property name="sizePolicy">
335
+              <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
336
+               <horstretch>0</horstretch>
337
+               <verstretch>0</verstretch>
338
+              </sizepolicy>
339
+             </property>
340
+             <attribute name="title">
341
+              <string>Collision</string>
342
+             </attribute>
343
+             <widget class="Line" name="line">
344
+              <property name="geometry">
345
+               <rect>
346
+                <x>20</x>
347
+                <y>60</y>
348
+                <width>111</width>
349
+                <height>20</height>
350
+               </rect>
351
+              </property>
352
+              <property name="orientation">
353
+               <enum>Qt::Horizontal</enum>
354
+              </property>
355
+             </widget>
356
+             <widget class="QFrame" name="frame">
357
+              <property name="geometry">
358
+               <rect>
359
+                <x>0</x>
360
+                <y>80</y>
361
+                <width>151</width>
362
+                <height>101</height>
363
+               </rect>
364
+              </property>
365
+              <property name="frameShape">
366
+               <enum>QFrame::StyledPanel</enum>
367
+              </property>
368
+              <property name="frameShadow">
369
+               <enum>QFrame::Raised</enum>
370
+              </property>
371
+              <widget class="QLabel" name="label_2">
372
+               <property name="geometry">
373
+                <rect>
374
+                 <x>10</x>
375
+                 <y>10</y>
376
+                 <width>47</width>
377
+                 <height>13</height>
378
+                </rect>
379
+               </property>
380
+               <property name="text">
381
+                <string>Elevation</string>
382
+               </property>
383
+              </widget>
384
+              <widget class="QGraphicsView" name="graphicsView_Elevation">
385
+               <property name="geometry">
386
+                <rect>
387
+                 <x>10</x>
388
+                 <y>30</y>
389
+                 <width>131</width>
390
+                 <height>61</height>
391
+                </rect>
392
+               </property>
393
+              </widget>
394
+             </widget>
395
+             <widget class="QFrame" name="frame_2">
396
+              <property name="geometry">
397
+               <rect>
398
+                <x>0</x>
399
+                <y>0</y>
400
+                <width>151</width>
401
+                <height>61</height>
402
+               </rect>
403
+              </property>
404
+              <property name="frameShape">
405
+               <enum>QFrame::StyledPanel</enum>
406
+              </property>
407
+              <property name="frameShadow">
408
+               <enum>QFrame::Raised</enum>
409
+              </property>
410
+              <widget class="QLabel" name="label">
411
+               <property name="geometry">
412
+                <rect>
413
+                 <x>10</x>
414
+                 <y>10</y>
415
+                 <width>47</width>
416
+                 <height>13</height>
417
+                </rect>
418
+               </property>
419
+               <property name="text">
420
+                <string>Collision</string>
421
+               </property>
422
+              </widget>
423
+              <widget class="QGraphicsView" name="graphicsView_Collision">
424
+               <property name="geometry">
425
+                <rect>
426
+                 <x>40</x>
427
+                 <y>30</y>
428
+                 <width>66</width>
429
+                 <height>18</height>
430
+                </rect>
431
+               </property>
432
+              </widget>
433
+             </widget>
434
+            </widget>
435
+           </widget>
436
+          </widget>
437
+         </item>
438
+        </layout>
439
+       </widget>
440
+       <widget class="QWidget" name="tab_Objects">
441
+        <property name="enabled">
442
+         <bool>true</bool>
443
+        </property>
444
+        <attribute name="title">
445
+         <string>Objects</string>
446
+        </attribute>
447
+        <layout class="QGridLayout" name="gridLayout_10">
448
+         <property name="leftMargin">
449
+          <number>0</number>
450
+         </property>
451
+         <property name="topMargin">
452
+          <number>0</number>
453
+         </property>
454
+         <property name="rightMargin">
455
+          <number>0</number>
456
+         </property>
457
+         <property name="bottomMargin">
458
+          <number>0</number>
459
+         </property>
460
+         <item row="0" column="0">
461
+          <widget class="QSplitter" name="splitter_3">
462
+           <property name="orientation">
463
+            <enum>Qt::Horizontal</enum>
464
+           </property>
465
+           <widget class="QScrollArea" name="scrollArea_3">
466
+            <property name="sizePolicy">
467
+             <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
468
+              <horstretch>1</horstretch>
469
+              <verstretch>0</verstretch>
470
+             </sizepolicy>
471
+            </property>
472
+            <property name="widgetResizable">
473
+             <bool>true</bool>
474
+            </property>
475
+            <widget class="QWidget" name="scrollAreaWidgetContents_4">
476
+             <property name="geometry">
477
+              <rect>
478
+               <x>0</x>
479
+               <y>0</y>
480
+               <width>571</width>
481
+               <height>564</height>
482
+              </rect>
483
+             </property>
484
+             <layout class="QGridLayout" name="gridLayout_7">
485
+              <property name="leftMargin">
486
+               <number>0</number>
487
+              </property>
488
+              <property name="topMargin">
489
+               <number>0</number>
490
+              </property>
491
+              <property name="rightMargin">
492
+               <number>0</number>
493
+              </property>
494
+              <property name="bottomMargin">
495
+               <number>0</number>
496
+              </property>
497
+              <property name="spacing">
498
+               <number>0</number>
499
+              </property>
500
+              <item row="1" column="2">
501
+               <spacer name="horizontalSpacer_6">
502
+                <property name="orientation">
503
+                 <enum>Qt::Horizontal</enum>
504
+                </property>
505
+                <property name="sizeHint" stdset="0">
506
+                 <size>
507
+                  <width>166</width>
508
+                  <height>16</height>
509
+                 </size>
510
+                </property>
511
+               </spacer>
512
+              </item>
513
+              <item row="1" column="0">
514
+               <spacer name="horizontalSpacer_5">
515
+                <property name="orientation">
516
+                 <enum>Qt::Horizontal</enum>
517
+                </property>
518
+                <property name="sizeHint" stdset="0">
519
+                 <size>
520
+                  <width>166</width>
521
+                  <height>16</height>
522
+                 </size>
523
+                </property>
524
+               </spacer>
525
+              </item>
526
+              <item row="0" column="1">
527
+               <spacer name="verticalSpacer_6">
528
+                <property name="orientation">
529
+                 <enum>Qt::Vertical</enum>
530
+                </property>
531
+                <property name="sizeHint" stdset="0">
532
+                 <size>
533
+                  <width>16</width>
534
+                  <height>166</height>
535
+                 </size>
536
+                </property>
537
+               </spacer>
538
+              </item>
539
+              <item row="2" column="1">
540
+               <spacer name="verticalSpacer_5">
541
+                <property name="orientation">
542
+                 <enum>Qt::Vertical</enum>
543
+                </property>
544
+                <property name="sizeHint" stdset="0">
545
+                 <size>
546
+                  <width>16</width>
547
+                  <height>166</height>
548
+                 </size>
549
+                </property>
550
+               </spacer>
551
+              </item>
552
+              <item row="1" column="1">
553
+               <widget class="QGraphicsView" name="graphicsView_Objects_Map">
554
+                <property name="sizePolicy">
555
+                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
556
+                  <horstretch>0</horstretch>
557
+                  <verstretch>0</verstretch>
558
+                 </sizepolicy>
559
+                </property>
560
+               </widget>
561
+              </item>
562
+             </layout>
563
+            </widget>
564
+           </widget>
565
+           <widget class="QFrame" name="frame_3">
566
+            <property name="enabled">
567
+             <bool>true</bool>
568
+            </property>
569
+            <property name="sizePolicy">
570
+             <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
571
+              <horstretch>0</horstretch>
572
+              <verstretch>0</verstretch>
573
+             </sizepolicy>
574
+            </property>
575
+            <property name="minimumSize">
576
+             <size>
577
+              <width>156</width>
578
+              <height>0</height>
579
+             </size>
580
+            </property>
581
+            <layout class="QGridLayout" name="gridLayout_6">
582
+             <item row="1" column="0">
583
+              <widget class="QGroupBox" name="groupBox">
584
+               <property name="title">
585
+                <string>Selected</string>
586
+               </property>
587
+              </widget>
588
+             </item>
589
+             <item row="0" column="0">
590
+              <widget class="QFrame" name="frame_4">
591
+               <property name="maximumSize">
592
+                <size>
593
+                 <width>16777215</width>
594
+                 <height>32</height>
595
+                </size>
596
+               </property>
597
+               <property name="frameShape">
598
+                <enum>QFrame::StyledPanel</enum>
599
+               </property>
600
+               <property name="frameShadow">
601
+                <enum>QFrame::Raised</enum>
602
+               </property>
603
+               <widget class="QToolButton" name="toolButton">
604
+                <property name="geometry">
605
+                 <rect>
606
+                  <x>0</x>
607
+                  <y>0</y>
608
+                  <width>31</width>
609
+                  <height>31</height>
610
+                 </rect>
611
+                </property>
612
+                <property name="text">
613
+                 <string>New</string>
614
+                </property>
615
+               </widget>
616
+               <widget class="QToolButton" name="toolButton_2">
617
+                <property name="geometry">
618
+                 <rect>
619
+                  <x>100</x>
620
+                  <y>0</y>
621
+                  <width>31</width>
622
+                  <height>31</height>
623
+                 </rect>
624
+                </property>
625
+                <property name="text">
626
+                 <string>Delete</string>
627
+                </property>
628
+               </widget>
629
+              </widget>
630
+             </item>
631
+            </layout>
632
+           </widget>
633
+          </widget>
634
+         </item>
635
+        </layout>
636
+       </widget>
637
+       <widget class="QWidget" name="tab_Attributes">
638
+        <attribute name="title">
639
+         <string>Attributes</string>
640
+        </attribute>
641
+        <widget class="QFrame" name="frame_3">
642
+         <property name="geometry">
643
+          <rect>
644
+           <x>10</x>
645
+           <y>10</y>
646
+           <width>301</width>
647
+           <height>251</height>
648
+          </rect>
649
+         </property>
650
+         <property name="frameShape">
651
+          <enum>QFrame::StyledPanel</enum>
652
+         </property>
653
+         <property name="frameShadow">
654
+          <enum>QFrame::Raised</enum>
655
+         </property>
656
+         <widget class="QLabel" name="label_3">
657
+          <property name="geometry">
658
+           <rect>
659
+            <x>20</x>
660
+            <y>30</y>
661
+            <width>47</width>
662
+            <height>21</height>
663
+           </rect>
664
+          </property>
665
+          <property name="text">
666
+           <string>Song</string>
667
+          </property>
668
+         </widget>
669
+         <widget class="QLabel" name="label_4">
670
+          <property name="geometry">
671
+           <rect>
672
+            <x>20</x>
673
+            <y>60</y>
674
+            <width>47</width>
675
+            <height>21</height>
676
+           </rect>
677
+          </property>
678
+          <property name="text">
679
+           <string>Location</string>
680
+          </property>
681
+         </widget>
682
+         <widget class="QLabel" name="label_5">
683
+          <property name="geometry">
684
+           <rect>
685
+            <x>20</x>
686
+            <y>90</y>
687
+            <width>47</width>
688
+            <height>21</height>
689
+           </rect>
690
+          </property>
691
+          <property name="text">
692
+           <string>Visibility</string>
693
+          </property>
694
+         </widget>
695
+         <widget class="QLabel" name="label_6">
696
+          <property name="geometry">
697
+           <rect>
698
+            <x>20</x>
699
+            <y>120</y>
700
+            <width>47</width>
701
+            <height>21</height>
702
+           </rect>
703
+          </property>
704
+          <property name="text">
705
+           <string>Weather</string>
706
+          </property>
707
+         </widget>
708
+         <widget class="QLabel" name="label_7">
709
+          <property name="geometry">
710
+           <rect>
711
+            <x>20</x>
712
+            <y>150</y>
713
+            <width>47</width>
714
+            <height>21</height>
715
+           </rect>
716
+          </property>
717
+          <property name="text">
718
+           <string>Type</string>
719
+          </property>
720
+         </widget>
721
+         <widget class="QLabel" name="label_8">
722
+          <property name="geometry">
723
+           <rect>
724
+            <x>20</x>
725
+            <y>180</y>
726
+            <width>101</width>
727
+            <height>21</height>
728
+           </rect>
729
+          </property>
730
+          <property name="text">
731
+           <string>Show location name</string>
732
+          </property>
733
+         </widget>
734
+         <widget class="QLabel" name="label_9">
735
+          <property name="geometry">
736
+           <rect>
737
+            <x>20</x>
738
+            <y>210</y>
739
+            <width>81</width>
740
+            <height>21</height>
741
+           </rect>
742
+          </property>
743
+          <property name="text">
744
+           <string>Battle scene</string>
745
+          </property>
746
+         </widget>
747
+         <widget class="QComboBox" name="comboBox_Location">
748
+          <property name="geometry">
749
+           <rect>
750
+            <x>80</x>
751
+            <y>60</y>
752
+            <width>211</width>
753
+            <height>22</height>
754
+           </rect>
755
+          </property>
756
+         </widget>
757
+         <widget class="QComboBox" name="comboBox_Visibility">
758
+          <property name="geometry">
759
+           <rect>
760
+            <x>80</x>
761
+            <y>90</y>
762
+            <width>211</width>
763
+            <height>22</height>
764
+           </rect>
765
+          </property>
766
+         </widget>
767
+         <widget class="QComboBox" name="comboBox_Song">
768
+          <property name="geometry">
769
+           <rect>
770
+            <x>80</x>
771
+            <y>30</y>
772
+            <width>211</width>
773
+            <height>22</height>
774
+           </rect>
775
+          </property>
776
+         </widget>
777
+         <widget class="QComboBox" name="comboBox_Weather">
778
+          <property name="geometry">
779
+           <rect>
780
+            <x>80</x>
781
+            <y>120</y>
782
+            <width>211</width>
783
+            <height>22</height>
784
+           </rect>
785
+          </property>
786
+         </widget>
787
+         <widget class="QComboBox" name="comboBox_Type">
788
+          <property name="geometry">
789
+           <rect>
790
+            <x>80</x>
791
+            <y>150</y>
792
+            <width>211</width>
793
+            <height>22</height>
794
+           </rect>
795
+          </property>
796
+         </widget>
797
+         <widget class="QComboBox" name="comboBox_BattleScene">
798
+          <property name="geometry">
799
+           <rect>
800
+            <x>90</x>
801
+            <y>210</y>
802
+            <width>201</width>
803
+            <height>22</height>
804
+           </rect>
805
+          </property>
806
+         </widget>
807
+         <widget class="QCheckBox" name="checkBox_ShowLocation">
808
+          <property name="geometry">
809
+           <rect>
810
+            <x>130</x>
811
+            <y>180</y>
812
+            <width>161</width>
813
+            <height>21</height>
814
+           </rect>
815
+          </property>
816
+          <property name="text">
817
+           <string/>
818
+          </property>
819
+         </widget>
820
+         <widget class="QLabel" name="label_10">
821
+          <property name="geometry">
822
+           <rect>
823
+            <x>0</x>
824
+            <y>0</y>
825
+            <width>47</width>
826
+            <height>13</height>
827
+           </rect>
828
+          </property>
829
+          <property name="text">
830
+           <string>Header</string>
831
+          </property>
832
+         </widget>
833
+        </widget>
834
+       </widget>
835
+      </widget>
836
+     </widget>
837
+    </item>
838
+   </layout>
839
+  </widget>
840
+  <widget class="QMenuBar" name="menuBar">
841
+   <property name="geometry">
842
+    <rect>
843
+     <x>0</x>
844
+     <y>0</y>
845
+     <width>1019</width>
846
+     <height>21</height>
847
+    </rect>
848
+   </property>
849
+   <widget class="QMenu" name="menuFile">
850
+    <property name="title">
851
+     <string>File</string>
852
+    </property>
853
+    <addaction name="action_Open_Project"/>
854
+    <addaction name="action_Save"/>
855
+    <addaction name="action_Save_Project"/>
856
+    <addaction name="separator"/>
857
+    <addaction name="action_Exit"/>
858
+   </widget>
859
+   <widget class="QMenu" name="menuEdit">
860
+    <property name="title">
861
+     <string>Edit</string>
862
+    </property>
863
+    <addaction name="actionUndo"/>
864
+    <addaction name="actionRedo"/>
865
+   </widget>
866
+   <addaction name="menuFile"/>
867
+   <addaction name="menuEdit"/>
868
+  </widget>
869
+  <widget class="QToolBar" name="mainToolBar">
870
+   <attribute name="toolBarArea">
871
+    <enum>TopToolBarArea</enum>
872
+   </attribute>
873
+   <attribute name="toolBarBreak">
874
+    <bool>false</bool>
875
+   </attribute>
876
+  </widget>
877
+  <widget class="QStatusBar" name="statusBar"/>
878
+  <action name="action_Save_Project">
879
+   <property name="text">
880
+    <string>Save All</string>
881
+   </property>
882
+   <property name="shortcut">
883
+    <string>Ctrl+Shift+S</string>
884
+   </property>
885
+  </action>
886
+  <action name="action_Exit">
887
+   <property name="text">
888
+    <string>Exit</string>
889
+   </property>
890
+   <property name="shortcut">
891
+    <string>Ctrl+Q</string>
892
+   </property>
893
+  </action>
894
+  <action name="action_Open_Project">
895
+   <property name="text">
896
+    <string>Open Project...</string>
897
+   </property>
898
+   <property name="shortcut">
899
+    <string>Ctrl+O</string>
900
+   </property>
901
+  </action>
902
+  <action name="action_Save">
903
+   <property name="text">
904
+    <string>Save</string>
905
+   </property>
906
+   <property name="shortcut">
907
+    <string>Ctrl+S</string>
908
+   </property>
909
+  </action>
910
+  <action name="actionUndo">
911
+   <property name="text">
912
+    <string>Undo</string>
913
+   </property>
914
+   <property name="shortcut">
915
+    <string>Ctrl+Z</string>
916
+   </property>
917
+  </action>
918
+  <action name="actionRedo">
919
+   <property name="text">
920
+    <string>Redo</string>
921
+   </property>
922
+   <property name="font">
923
+    <font>
924
+     <weight>50</weight>
925
+     <bold>false</bold>
926
+    </font>
927
+   </property>
928
+   <property name="shortcut">
929
+    <string>Ctrl+Y</string>
930
+   </property>
931
+  </action>
932
+ </widget>
933
+ <layoutdefault spacing="6" margin="11"/>
934
+ <resources>
935
+  <include location="resources/images.qrc"/>
936
+ </resources>
937
+ <connections/>
938
+</ui>

+ 600
- 0
map.cpp View File

@@ -0,0 +1,600 @@
1
+#include "map.h"
2
+
3
+#include <QTime>
4
+#include <QDebug>
5
+#include <QPainter>
6
+
7
+Map::Map(QObject *parent) : QObject(parent)
8
+{
9
+    cached_blockdata = new Blockdata;
10
+    cached_collision = new Blockdata;
11
+    cached_border = new Blockdata;
12
+    paint_tile = 1;
13
+    paint_collision = 0;
14
+    paint_elevation = 3;
15
+}
16
+
17
+int Map::getWidth() {
18
+    return width.toInt(nullptr, 0);
19
+}
20
+
21
+int Map::getHeight() {
22
+    return height.toInt(nullptr, 0);
23
+}
24
+
25
+Tileset* Map::getBlockTileset(uint metatile_index) {
26
+    uint primary_size = 0x200;//tileset_primary->metatiles->length();
27
+    if (metatile_index < primary_size) {
28
+        return tileset_primary;
29
+    } else {
30
+        return tileset_secondary;
31
+    }
32
+}
33
+
34
+QImage Map::getMetatileTile(uint tile) {
35
+    uint primary_size = 0x200;//tileset_primary->metatiles->length();
36
+    if (tile < primary_size) {
37
+        return tileset_primary->tiles->value(tile);
38
+    } else {
39
+        return tileset_secondary->tiles->value(tile - primary_size);
40
+    }
41
+}
42
+
43
+Metatile* Map::getMetatile(uint index) {
44
+    uint primary_size = 0x200;//tileset_primary->metatiles->length();
45
+    if (index < primary_size) {
46
+        return tileset_primary->metatiles->value(index);
47
+    } else {
48
+        //qDebug() << QString("secondary tileset: %1").arg(index - primary_size, 0, 16);
49
+        return tileset_secondary->metatiles->value(index - primary_size);
50
+    }
51
+}
52
+
53
+QImage Map::getCollisionMetatileImage(Block block) {
54
+    return getCollisionMetatileImage(block.collision);
55
+}
56
+
57
+QImage Map::getCollisionMetatileImage(int collision) {
58
+    QImage metatile_image(16, 16, QImage::Format_RGBA8888);
59
+    QColor color;
60
+    if (collision == 0) {
61
+        color.setGreen(0xff);
62
+    } else if (collision == 1) {
63
+        color.setRed(0xff);
64
+    } else if (collision == 2) {
65
+        color.setBlue(0xff);
66
+    } else if (collision == 3) {
67
+        // black
68
+    }
69
+    metatile_image.fill(color);
70
+    return metatile_image;
71
+}
72
+
73
+QImage Map::getElevationMetatileImage(Block block) {
74
+    return getElevationMetatileImage(block.elevation);
75
+}
76
+
77
+QImage Map::getElevationMetatileImage(int elevation) {
78
+    QImage metatile_image(16, 16, QImage::Format_RGBA8888);
79
+    QColor color;
80
+    if (elevation < 15) {
81
+        uint saturation = (elevation + 1) * 16 + 15;
82
+        color.setGreen(saturation);
83
+        color.setRed(saturation);
84
+        color.setBlue(saturation);
85
+    } else {
86
+        color.setGreen(0xd0);
87
+        color.setBlue(0xd0);
88
+        color.setRed(0);
89
+    }
90
+    metatile_image.fill(color);
91
+    //QPainter painter(&metatile_image);
92
+    //painter.end();
93
+    return metatile_image;
94
+}
95
+
96
+QImage Map::getMetatileImage(uint tile) {
97
+
98
+    QImage metatile_image(16, 16, QImage::Format_RGBA8888);
99
+
100
+    Metatile* metatile = getMetatile(tile);
101
+    if (metatile == NULL) {
102
+        metatile_image.fill(0xffffffff);
103
+        return metatile_image;
104
+    }
105
+
106
+    Tileset* blockTileset = getBlockTileset(tile);
107
+
108
+    for (int layer = 0; layer < 2; layer++)
109
+    for (int y = 0; y < 2; y++)
110
+    for (int x = 0; x < 2; x++) {
111
+        //qDebug() << QString("x=%1 y=%2 layer=%3").arg(x).arg(y).arg(layer);
112
+        Tile tile = metatile->tiles->value((y * 2) + x + (layer * 4));
113
+        QImage tile_image = getMetatileTile(tile.tile);
114
+        QList<QRgb> palette = blockTileset->palettes->value(tile.palette);
115
+        for (int j = 0; j < palette.length(); j++) {
116
+            tile_image.setColor(j, palette.value(j));
117
+        }
118
+        //QVector<QRgb> vector = palette.toVector();
119
+        //tile_image.setColorTable(vector);
120
+        if (layer > 0) {
121
+            QColor color(tile_image.color(15));
122
+            color.setAlpha(0);
123
+            tile_image.setColor(15, color.rgba());
124
+        }
125
+        QPainter metatile_painter(&metatile_image);
126
+        QPoint origin = QPoint(x*8, y*8);
127
+        metatile_painter.drawImage(origin, tile_image.mirrored(tile.xflip == 1, tile.yflip == 1));
128
+        metatile_painter.end();
129
+    }
130
+
131
+    return metatile_image;
132
+}
133
+
134
+bool Map::blockChanged(int i, Blockdata *cache) {
135
+    if (cache->blocks->length() <= i) {
136
+        return true;
137
+    }
138
+    return blockdata->blocks->value(i) != cache->blocks->value(i);
139
+}
140
+
141
+void Map::cacheBorder() {
142
+    cached_border = new Blockdata;
143
+    for (int i = 0; i < border->blocks->length(); i++) {
144
+        Block block = border->blocks->value(i);
145
+        cached_border->blocks->append(block);
146
+    }
147
+}
148
+
149
+void Map::cacheBlockdata() {
150
+    cached_blockdata = new Blockdata;
151
+    for (int i = 0; i < blockdata->blocks->length(); i++) {
152
+        Block block = blockdata->blocks->value(i);
153
+        cached_blockdata->blocks->append(block);
154
+    }
155
+}
156
+
157
+void Map::cacheCollision() {
158
+    cached_collision = new Blockdata;
159
+    for (int i = 0; i < blockdata->blocks->length(); i++) {
160
+        Block block = blockdata->blocks->value(i);
161
+        cached_collision->blocks->append(block);
162
+    }
163
+}
164
+
165
+QPixmap Map::renderCollision() {
166
+    bool changed_any = false;
167
+    int width_ = getWidth();
168
+    int height_ = getHeight();
169
+    if (
170
+            collision_image.isNull()
171
+            || collision_image.width() != width_ * 16
172
+            || collision_image.height() != height_ * 16
173
+    ) {
174
+        collision_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
175
+        changed_any = true;
176
+    }
177
+    QPainter painter(&collision_image);
178
+    for (int i = 0; i < blockdata->blocks->length(); i++) {
179
+        if (!blockChanged(i, cached_collision)) {
180
+            continue;
181
+        }
182
+        changed_any = true;
183
+        Block block = blockdata->blocks->value(i);
184
+        QImage metatile_image = getMetatileImage(block.tile);
185
+        QImage collision_metatile_image = getCollisionMetatileImage(block);
186
+        QImage elevation_metatile_image = getElevationMetatileImage(block);
187
+        int map_y = i / width_;
188
+        int map_x = i % width_;
189
+        QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
190
+        painter.setOpacity(1);
191
+        painter.drawImage(metatile_origin, metatile_image);
192
+
193
+        painter.save();
194
+        if (block.elevation == 15) {
195
+            painter.setOpacity(0.5);
196
+        } else if (block.elevation == 0) {
197
+            painter.setOpacity(0);
198
+        } else {
199
+            painter.setOpacity(1);//(block.elevation / 16.0) * 0.8);
200
+            painter.setCompositionMode(QPainter::CompositionMode_Overlay);
201
+        }
202
+        painter.drawImage(metatile_origin, elevation_metatile_image);
203
+        painter.restore();
204
+
205
+        painter.save();
206
+        if (block.collision == 0) {
207
+            painter.setOpacity(0.1);
208
+        } else {
209
+            painter.setOpacity(0.4);
210
+        }
211
+        painter.drawImage(metatile_origin, collision_metatile_image);
212
+        painter.restore();
213
+
214
+        painter.save();
215
+        painter.setOpacity(0.6);
216
+        painter.setPen(QColor(255, 255, 255, 192));
217
+        painter.setFont(QFont("Helvetica", 8));
218
+        painter.drawText(QPoint(metatile_origin.x(), metatile_origin.y() + 8), QString("%1").arg(block.elevation));
219
+        painter.restore();
220
+    }
221
+    painter.end();
222
+    cacheCollision();
223
+    if (changed_any) {
224
+        collision_pixmap = collision_pixmap.fromImage(collision_image);
225
+    }
226
+    return collision_pixmap;
227
+}
228
+
229
+QPixmap Map::render() {
230
+    bool changed_any = false;
231
+    int width_ = getWidth();
232
+    int height_ = getHeight();
233
+    if (
234
+            image.isNull()
235
+            || image.width() != width_ * 16
236
+            || image.height() != height_ * 16
237
+    ) {
238
+        image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
239
+        changed_any = true;
240
+    }
241
+    QPainter painter(&image);
242
+    for (int i = 0; i < blockdata->blocks->length(); i++) {
243
+        if (!blockChanged(i, cached_blockdata)) {
244
+            continue;
245
+        }
246
+        changed_any = true;
247
+        Block block = blockdata->blocks->value(i);
248
+        QImage metatile_image = getMetatileImage(block.tile);
249
+        int map_y = i / width_;
250
+        int map_x = i % width_;
251
+        QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
252
+        painter.drawImage(metatile_origin, metatile_image);
253
+    }
254
+    painter.end();
255
+    if (changed_any) {
256
+        cacheBlockdata();
257
+        pixmap = pixmap.fromImage(image);
258
+    }
259
+    return pixmap;
260
+}
261
+
262
+QPixmap Map::renderBorder() {
263
+    bool changed_any = false;
264
+    int width_ = 2;
265
+    int height_ = 2;
266
+    if (border_image.isNull()) {
267
+        border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
268
+        changed_any = true;
269
+    }
270
+    QPainter painter(&border_image);
271
+    for (int i = 0; i < border->blocks->length(); i++) {
272
+        if (!blockChanged(i, cached_border)) {
273
+            continue;
274
+        }
275
+        changed_any = true;
276
+        Block block = border->blocks->value(i);
277
+        QImage metatile_image = getMetatileImage(block.tile);
278
+        int map_y = i / width_;
279
+        int map_x = i % width_;
280
+        painter.drawImage(QPoint(map_x * 16, map_y * 16), metatile_image);
281
+    }
282
+    painter.end();
283
+    if (changed_any) {
284
+        cacheBorder();
285
+        border_pixmap = border_pixmap.fromImage(border_image);
286
+    }
287
+    return border_pixmap;
288
+}
289
+
290
+QPixmap Map::renderConnection(Connection connection) {
291
+    render();
292
+    int x, y, w, h;
293
+    if (connection.direction == "up") {
294
+        x = 0;
295
+        y = getHeight() - 6;
296
+        w = getWidth();
297
+        h = 6;
298
+    } else if (connection.direction == "down") {
299
+        x = 0;
300
+        y = 0;
301
+        w = getWidth();
302
+        h = 6;
303
+    } else if (connection.direction == "left") {
304
+        x = getWidth() - 6;
305
+        y = 0;
306
+        w = 6;
307
+        h = getHeight();
308
+    } else if (connection.direction == "right") {
309
+        x = 0;
310
+        y = 0;
311
+        w = 6;
312
+        h = getHeight();
313
+    } else {
314
+        // this should not happen
315
+        x = 0;
316
+        y = 0;
317
+        w = getWidth();
318
+        h = getHeight();
319
+    }
320
+    QImage connection_image = image.copy(x * 16, y * 16, w * 16, h * 16);
321
+    //connection_image = connection_image.convertToFormat(QImage::Format_Grayscale8);
322
+    return QPixmap::fromImage(connection_image);
323
+}
324
+
325
+QPixmap Map::renderCollisionMetatiles() {
326
+    int length_ = 4;
327
+    int height_ = 1;
328
+    int width_ = length_ / height_;
329
+    QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
330
+    QPainter painter(&image);
331
+    for (int i = 0; i < length_; i++) {
332
+        int y = i / width_;
333
+        int x = i % width_;
334
+        QPoint origin(x * 16, y * 16);
335
+        QImage metatile_image = getCollisionMetatileImage(i);
336
+        painter.drawImage(origin, metatile_image);
337
+    }
338
+    drawSelection(paint_collision, width_, &painter);
339
+    painter.end();
340
+    return QPixmap::fromImage(image);
341
+}
342
+
343
+QPixmap Map::renderElevationMetatiles() {
344
+    int length_ = 16;
345
+    int height_ = 2;
346
+    int width_ = length_ / height_;
347
+    QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
348
+    QPainter painter(&image);
349
+    for (int i = 0; i < length_; i++) {
350
+        int y = i / width_;
351
+        int x = i % width_;
352
+        QPoint origin(x * 16, y * 16);
353
+        QImage metatile_image = getElevationMetatileImage(i);
354
+        painter.drawImage(origin, metatile_image);
355
+    }
356
+    drawSelection(paint_elevation, width_, &painter);
357
+    painter.end();
358
+    return QPixmap::fromImage(image);
359
+}
360
+
361
+void Map::drawSelection(int i, int w, QPainter *painter) {
362
+    int x = i % w;
363
+    int y = i / w;
364
+    painter->save();
365
+    painter->setPen(QColor(0xff, 0xff, 0xff));
366
+    painter->drawRect(x * 16, y * 16, 15, 15);
367
+    painter->setPen(QColor(0, 0, 0));
368
+    painter->drawRect(x * 16 - 1, y * 16 - 1, 17, 17);
369
+    painter->drawRect(x * 16 + 1, y * 16 + 1, 13, 13);
370
+    painter->restore();
371
+}
372
+
373
+QPixmap Map::renderMetatiles() {
374
+    int primary_length = tileset_primary->metatiles->length();
375
+    int length_ = primary_length + tileset_secondary->metatiles->length();
376
+    int width_ = 8;
377
+    int height_ = length_ / width_;
378
+    QImage image(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
379
+    QPainter painter(&image);
380
+    for (int i = 0; i < length_; i++) {
381
+        uint tile = i;
382
+        if (i >= primary_length) {
383
+            tile += 0x200 - primary_length;
384
+        }
385
+        QImage metatile_image = getMetatileImage(tile);
386
+        int map_y = i / width_;
387
+        int map_x = i % width_;
388
+        QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
389
+        painter.drawImage(metatile_origin, metatile_image);
390
+    }
391
+
392
+    drawSelection(paint_tile, width_, &painter);
393
+
394
+    painter.end();
395
+    return QPixmap::fromImage(image);
396
+}
397
+
398
+Block* Map::getBlock(int x, int y) {
399
+    if (x >= 0 && x < getWidth())
400
+    if (y >= 0 && y < getHeight()) {
401
+        int i = y * getWidth() + x;
402
+        return new Block(blockdata->blocks->value(i));
403
+    }
404
+    return NULL;
405
+}
406
+
407
+void Map::_setBlock(int x, int y, Block block) {
408
+    int i = y * getWidth() + x;
409
+    blockdata->blocks->replace(i, block);
410
+}
411
+
412
+void Map::_floodFill(int x, int y, uint tile) {
413
+    QList<QPoint> todo;
414
+    todo.append(QPoint(x, y));
415
+    while (todo.length()) {
416
+            QPoint point = todo.takeAt(0);
417
+            x = point.x();
418
+            y = point.y();
419
+            Block *block = getBlock(x, y);
420
+            if (block == NULL) {
421
+                continue;
422
+            }
423
+            uint old_tile = block->tile;
424
+            if (old_tile == tile) {
425
+                continue;
426
+            }
427
+            block->tile = tile;
428
+            _setBlock(x, y, *block);
429
+            if ((block = getBlock(x + 1, y)) && block->tile == old_tile) {
430
+                todo.append(QPoint(x + 1, y));
431
+            }
432
+            if ((block = getBlock(x - 1, y)) && block->tile == old_tile) {
433
+                todo.append(QPoint(x - 1, y));
434
+            }
435
+            if ((block = getBlock(x, y + 1)) && block->tile == old_tile) {
436
+                todo.append(QPoint(x, y + 1));
437
+            }
438
+            if ((block = getBlock(x, y - 1)) && block->tile == old_tile) {
439
+                todo.append(QPoint(x, y - 1));
440
+            }
441
+    }
442
+}
443
+
444
+void Map::_floodFillCollision(int x, int y, uint collision) {
445
+    QList<QPoint> todo;
446
+    todo.append(QPoint(x, y));
447
+    while (todo.length()) {
448
+            QPoint point = todo.takeAt(0);
449
+            x = point.x();
450
+            y = point.y();
451
+            Block *block = getBlock(x, y);
452
+            if (block == NULL) {
453
+                continue;
454
+            }
455
+            uint old_coll = block->collision;
456
+            if (old_coll == collision) {
457
+                continue;
458
+            }
459
+            block->collision = collision;
460
+            _setBlock(x, y, *block);
461
+            if ((block = getBlock(x + 1, y)) && block->collision == old_coll) {
462
+                todo.append(QPoint(x + 1, y));
463
+            }
464
+            if ((block = getBlock(x - 1, y)) && block->collision == old_coll) {
465
+                todo.append(QPoint(x - 1, y));
466
+            }
467
+            if ((block = getBlock(x, y + 1)) && block->collision == old_coll) {
468
+                todo.append(QPoint(x, y + 1));
469
+            }
470
+            if ((block = getBlock(x, y - 1)) && block->collision == old_coll) {
471
+                todo.append(QPoint(x, y - 1));
472
+            }
473
+    }
474
+}
475
+
476
+void Map::_floodFillElevation(int x, int y, uint elevation) {
477
+    QList<QPoint> todo;
478
+    todo.append(QPoint(x, y));
479
+    while (todo.length()) {
480
+            QPoint point = todo.takeAt(0);
481
+            x = point.x();
482
+            y = point.y();
483
+            Block *block = getBlock(x, y);
484
+            if (block == NULL) {
485
+                continue;
486
+            }
487
+            uint old_z = block->elevation;
488
+            if (old_z == elevation) {
489
+                continue;
490
+            }
491
+            Block block_(*block);
492
+            block_.elevation = elevation;
493
+            _setBlock(x, y, block_);
494
+            if ((block = getBlock(x + 1, y)) && block->elevation == old_z) {
495
+                todo.append(QPoint(x + 1, y));
496
+            }
497
+            if ((block = getBlock(x - 1, y)) && block->elevation == old_z) {
498
+                todo.append(QPoint(x - 1, y));
499
+            }
500
+            if ((block = getBlock(x, y + 1)) && block->elevation == old_z) {
501
+                todo.append(QPoint(x, y + 1));
502
+            }
503
+            if ((block = getBlock(x, y - 1)) && block->elevation == old_z) {
504
+                todo.append(QPoint(x, y - 1));
505
+            }
506
+    }
507
+}
508
+
509
+void Map::_floodFillCollisionElevation(int x, int y, uint collision, uint elevation) {
510
+    QList<QPoint> todo;
511
+    todo.append(QPoint(x, y));
512
+    while (todo.length()) {
513
+            QPoint point = todo.takeAt(0);
514
+            x = point.x();
515
+            y = point.y();
516
+            Block *block = getBlock(x, y);
517
+            if (block == NULL) {
518
+                continue;
519
+            }
520
+            uint old_coll = block->collision;
521
+            uint old_elev = block->elevation;
522
+            if (old_coll == collision && old_elev == elevation) {
523
+                continue;
524
+            }
525
+            block->collision = collision;
526
+            block->elevation = elevation;
527
+            _setBlock(x, y, *block);
528
+            if ((block = getBlock(x + 1, y)) && block->collision == old_coll && block->elevation == old_elev) {
529
+                todo.append(QPoint(x + 1, y));
530
+            }
531
+            if ((block = getBlock(x - 1, y)) && block->collision == old_coll && block->elevation == old_elev) {
532
+                todo.append(QPoint(x - 1, y));
533
+            }
534
+            if ((block = getBlock(x, y + 1)) && block->collision == old_coll && block->elevation == old_elev) {
535
+                todo.append(QPoint(x, y + 1));
536
+            }
537
+            if ((block = getBlock(x, y - 1)) && block->collision == old_coll && block->elevation == old_elev) {
538
+                todo.append(QPoint(x, y - 1));
539
+            }
540
+    }
541
+}
542
+
543
+
544
+void Map::undo() {
545
+    Blockdata *commit = history.pop();
546
+    if (commit != NULL) {
547
+        blockdata->copyFrom(commit);
548
+    }
549
+}
550
+
551
+void Map::redo() {
552
+    Blockdata *commit = history.next();
553
+    if (commit != NULL) {
554
+        blockdata->copyFrom(commit);
555
+    }
556
+}
557
+
558
+void Map::commit() {
559
+    Blockdata* commit = blockdata->copy();
560
+    history.push(commit);
561
+}
562
+
563
+void Map::setBlock(int x, int y, Block block) {
564
+    Block *old_block = getBlock(x, y);
565
+    if (old_block && (*old_block) != block) {
566
+        _setBlock(x, y, block);
567
+        commit();
568
+    }
569
+}
570
+
571
+void Map::floodFill(int x, int y, uint tile) {
572
+    Block *block = getBlock(x, y);
573
+    if (block && block->tile != tile) {
574
+        _floodFill(x, y, tile);
575
+        commit();
576
+    }
577
+}
578
+
579
+void Map::floodFillCollision(int x, int y, uint collision) {
580
+    Block *block = getBlock(x, y);
581
+    if (block && block->collision != collision) {
582
+        _floodFillCollision(x, y, collision);
583
+        commit();
584
+    }
585
+}
586
+
587
+void Map::floodFillElevation(int x, int y, uint elevation) {
588
+    Block *block = getBlock(x, y);
589
+    if (block && block->elevation != elevation) {
590
+        _floodFillElevation(x, y, elevation);
591
+        commit();
592
+    }
593
+}
594
+void Map::floodFillCollisionElevation(int x, int y, uint collision, uint elevation) {
595
+    Block *block = getBlock(x, y);
596
+    if (block && (block->collision != collision || block->elevation != elevation)) {
597
+        _floodFillCollisionElevation(x, y, collision, elevation);
598
+        commit();
599
+    }
600
+}

+ 165
- 0
map.h View File

@@ -0,0 +1,165 @@
1
+#ifndef MAP_H
2
+#define MAP_H
3
+
4
+#include "tileset.h"
5
+#include "blockdata.h"
6
+#include "event.h"
7
+
8
+#include <QPixmap>
9
+#include <QObject>
10
+#include <QDebug>
11
+
12
+
13
+template <typename T>
14
+class History {
15
+public:
16
+    QList<T> history;
17
+    int head;
18
+
19
+    History() {
20
+        head = -1;
21
+    }
22
+    T pop() {
23
+        if (head > 0) {
24
+            return history.at(--head);
25
+        }
26
+        return NULL;
27
+    }
28
+    T next() {
29
+        if (head + 1 < history.length()) {
30
+            return history.at(++head);
31
+        }
32
+        return NULL;
33
+    }
34
+    void push(T commit) {
35
+        while (head + 1 < history.length()) {
36
+            history.removeLast();
37
+        }
38
+        history.append(commit);
39
+        head++;
40
+    }
41
+};
42
+
43
+class Connection {
44
+public:
45
+    Connection() {
46
+    }
47
+public:
48
+    QString direction;
49
+    QString offset;
50
+    QString map_name;
51
+};
52
+
53
+class Map : public QObject
54
+{
55
+    Q_OBJECT
56
+public:
57
+    explicit Map(QObject *parent = 0);
58
+
59
+public:
60
+    QString name;
61
+    QString attributes_label;
62
+    QString events_label;
63
+    QString scripts_label;
64
+    QString connections_label;
65
+    QString song;
66
+    QString index;
67
+    QString location;
68
+    QString visibility;
69
+    QString weather;
70
+    QString type;
71
+    QString unknown;
72
+    QString show_location;
73
+    QString battle_scene;
74
+
75
+    QString width;
76
+    QString height;
77
+    QString border_label;
78
+    QString blockdata_label;
79
+    QString tileset_primary_label;
80
+    QString tileset_secondary_label;
81
+
82
+    Tileset *tileset_primary;
83
+    Tileset *tileset_secondary;
84
+
85
+    Blockdata* blockdata;
86
+
87
+public:
88
+    int getWidth();
89
+    int getHeight();
90
+    Tileset* getBlockTileset(uint);
91
+    Metatile* getMetatile(uint);
92
+    QImage getMetatileImage(uint);
93
+    QImage getMetatileTile(uint);
94
+    QPixmap render();
95
+    QPixmap renderMetatiles();
96
+
97
+    QPixmap renderCollision();
98
+    QImage collision_image;
99
+    QPixmap collision_pixmap;
100
+    QImage getCollisionMetatileImage(Block);
101
+    QImage getElevationMetatileImage(Block);
102
+    QImage getCollisionMetatileImage(int);
103
+    QImage getElevationMetatileImage(int);
104
+
105
+    QPixmap renderCollisionMetatiles();
106
+    QPixmap renderElevationMetatiles();
107
+    void drawSelection(int i, int w, QPainter *painter);
108
+
109
+    bool blockChanged(int, Blockdata*);
110
+    Blockdata* cached_blockdata;
111
+    void cacheBlockdata();
112
+    Blockdata* cached_collision;
113
+    void cacheCollision();
114
+    QImage image;
115
+    QPixmap pixmap;
116
+    QList<QImage> metatile_images;
117
+    int paint_tile;
118
+    int paint_collision;
119
+    int paint_elevation;
120
+
121
+    Block *getBlock(int x, int y);
122
+    void setBlock(int x, int y, Block block);
123
+    void _setBlock(int x, int y, Block block);
124
+
125
+    void floodFill(int x, int y, uint tile);
126
+    void _floodFill(int x, int y, uint tile);
127
+    void floodFillCollision(int x, int y, uint collision);
128
+    void _floodFillCollision(int x, int y, uint collision);
129
+    void floodFillElevation(int x, int y, uint elevation);
130
+    void _floodFillElevation(int x, int y, uint elevation);
131
+    void floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
132
+    void _floodFillCollisionElevation(int x, int y, uint collision, uint elevation);
133
+
134
+    History<Blockdata*> history;
135
+    void undo();
136
+    void redo();
137
+    void commit();
138
+
139
+    QString object_events_label;
140
+    QString warps_label;
141
+    QString coord_events_label;
142
+    QString bg_events_label;
143
+
144
+    QList<ObjectEvent*> object_events;
145
+    QList<Warp*> warps;
146
+    QList<CoordEvent*> coord_events;
147
+    QList<Sign*> signs;
148
+    QList<HiddenItem*> hidden_items;
149
+
150
+    QList<Connection*> connections;
151
+    QPixmap renderConnection(Connection);
152
+
153
+    QImage border_image;
154
+    QPixmap border_pixmap;
155
+    Blockdata *border;
156
+    Blockdata *cached_border;
157
+    QPixmap renderBorder();
158
+    void cacheBorder();
159
+
160
+signals:
161
+
162
+public slots:
163
+};
164
+
165
+#endif // MAP_H

+ 6
- 0
metatile.cpp View File

@@ -0,0 +1,6 @@
1
+#include "metatile.h"
2
+
3
+Metatile::Metatile()
4
+{
5
+    tiles = new QList<Tile>;
6
+}

+ 16
- 0
metatile.h View File

@@ -0,0 +1,16 @@
1
+#ifndef METATILE_H
2
+#define METATILE_H
3
+
4
+#include "tile.h"
5
+#include <QList>
6
+
7
+class Metatile
8
+{
9
+public:
10
+    Metatile();
11
+public:
12
+    QList<Tile> *tiles;
13
+    int attr;
14
+};
15
+
16
+#endif // METATILE_H

+ 43
- 0
pretmap.pro View File

@@ -0,0 +1,43 @@
1
+#-------------------------------------------------
2
+#
3
+# Project created by QtCreator 2016-08-31T15:19:13
4
+#
5
+#-------------------------------------------------
6
+
7
+QT       += core gui
8
+
9
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10
+
11
+TARGET = pretmap
12
+TEMPLATE = app
13
+
14
+
15
+SOURCES += main.cpp\
16
+        mainwindow.cpp \
17
+    project.cpp \
18
+    asm.cpp \
19
+    map.cpp \
20
+    blockdata.cpp \
21
+    block.cpp \
22
+    tileset.cpp \
23
+    metatile.cpp \
24
+    tile.cpp \
25
+    event.cpp \
26
+    editor.cpp
27
+
28
+HEADERS  += mainwindow.h \
29
+    project.h \
30
+    asm.h \
31
+    map.h \
32
+    blockdata.h \
33
+    block.h \
34
+    tileset.h \
35
+    metatile.h \
36
+    tile.h \
37
+    event.h \
38
+    editor.h
39
+
40
+FORMS    += mainwindow.ui
41
+
42
+RESOURCES += \
43
+    resources/images.qrc

+ 787
- 0
project.cpp View File

@@ -0,0 +1,787 @@
1
+#include "asm.h"
2
+#include "project.h"
3
+#include "tile.h"
4
+#include "tileset.h"
5
+#include "metatile.h"
6
+#include "event.h"
7
+
8
+#include <QDebug>
9
+#include <QFile>
10
+#include <QTextStream>
11
+#include <QMessageBox>
12
+#include <QRegularExpression>
13
+
14
+Project::Project()
15
+{
16
+    groupNames = new QStringList;
17
+    groupedMapNames = new QList<QStringList*>;
18
+    map_cache = new QMap<QString, Map*>;
19
+    tileset_cache = new QMap<QString, Tileset*>;
20
+}
21
+
22
+QString Project::getProjectTitle() {
23
+    return root.section('/', -1);
24
+}
25
+
26
+Map* Project::loadMap(QString map_name) {
27
+    Map *map = new Map;
28
+
29
+    map->name = map_name;
30
+    readMapHeader(map);
31
+    readMapAttributes(map);
32
+    getTilesets(map);
33
+    loadBlockdata(map);
34
+    loadMapBorder(map);
35
+    readMapEvents(map);
36
+    loadMapConnections(map);
37
+    map->commit();
38
+
39
+    map_cache->insert(map_name, map);
40
+    return map;
41
+}
42
+
43
+void Project::loadMapConnections(Map *map) {
44
+    map->connections.clear();
45
+    if (!map->connections_label.isNull()) {
46
+        QString path = root + QString("/data/maps/%1/connections.s").arg(map->name);
47
+        QString text = readTextFile(path);
48
+        if (text != NULL) {
49
+            QList<QStringList> *commands = parse(text);
50
+            QStringList *list = getLabelValues(commands, map->connections_label);
51
+
52
+            //// Avoid using this value. It ought to be generated instead.
53
+            //int num_connections = list->value(0).toInt(nullptr, 0);
54
+
55
+            QString connections_list_label = list->value(1);
56
+            QList<QStringList> *connections = getLabelMacros(commands, connections_list_label);
57
+            for (QStringList command : *connections) {
58
+                QString macro = command.value(0);
59
+                if (macro == "connection") {
60
+                    Connection *connection = new Connection;
61
+                    connection->direction = command.value(1);
62
+                    connection->offset = command.value(2);
63
+                    connection->map_name = command.value(3);
64
+                    map->connections.append(connection);
65
+                }
66
+            }
67
+        }
68
+    }
69
+}
70
+
71
+QList<QStringList>* Project::getLabelMacros(QList<QStringList> *list, QString label) {
72
+    bool in_label = false;
73
+    QList<QStringList> *new_list = new QList<QStringList>;
74
+    for (int i = 0; i < list->length(); i++) {
75
+        QStringList params = list->value(i);
76
+        QString macro = params.value(0);
77
+        if (macro == ".label") {
78
+            if (params.value(1) == label) {
79
+                in_label = true;
80
+            } else if (in_label) {
81
+                // If nothing has been read yet, assume the label
82
+                // we're looking for is in a stack of labels.
83
+                if (new_list->length() > 0) {
84
+                    break;
85
+                }
86
+            }
87
+        } else if (in_label) {
88
+            new_list->append(params);
89
+        }
90
+    }
91
+    return new_list;
92
+}
93
+
94
+// For if you don't care about filtering by macro,
95
+// and just want all values associated with some label.
96
+QStringList* Project::getLabelValues(QList<QStringList> *list, QString label) {
97
+    list = getLabelMacros(list, label);
98
+    QStringList *values = new QStringList;
99
+    for (int i = 0; i < list->length(); i++) {
100
+        QStringList params = list->value(i);
101
+        QString macro = params.value(0);
102
+        // Ignore .align
103
+        if (macro == ".align") {
104
+            continue;
105
+        }
106
+        for (int j = 1; j < params.length(); j++) {
107
+            values->append(params.value(j));
108
+        }
109
+    }
110
+    return values;
111
+}
112
+
113
+void Project::readMapHeader(Map* map) {
114
+    QString label = map->name;
115
+    Asm *parser = new Asm;
116
+
117
+    QString header_text = readTextFile(root + "/data/maps/" + label + "/header.s");
118
+    QStringList *header = getLabelValues(parser->parse(header_text), label);
119
+    map->attributes_label = header->value(0);
120
+    map->events_label = header->value(1);
121
+    map->scripts_label = header->value(2);
122
+    map->connections_label = header->value(3);
123
+    map->song = header->value(4);
124
+    map->index = header->value(5);
125
+    map->location = header->value(6);
126
+    map->visibility = header->value(7);
127
+    map->weather = header->value(8);
128
+    map->type = header->value(9);
129
+    map->unknown = header->value(10);
130
+    map->show_location = header->value(11);
131
+    map->battle_scene = header->value(12);
132
+}
133
+
134
+void Project::saveMapHeader(Map *map) {
135
+    QString label = map->name;
136
+    QString header_path = root + "/data/maps/" + label + "/header.s";
137
+    QString text = "";
138
+    text += QString("%1::\n").arg(label);
139
+    text += QString("\t.4byte %1\n").arg(map->attributes_label);
140
+    text += QString("\t.4byte %1\n").arg(map->events_label);
141
+    text += QString("\t.4byte %1\n").arg(map->scripts_label);
142
+    text += QString("\t.4byte %1\n").arg(map->connections_label);
143
+    text += QString("\t.2byte %1\n").arg(map->song);
144
+    text += QString("\t.2byte %1\n").arg(map->index);
145
+    text += QString("\t.byte %1\n").arg(map->location);
146
+    text += QString("\t.byte %1\n").arg(map->visibility);
147
+    text += QString("\t.byte %1\n").arg(map->weather);
148
+    text += QString("\t.byte %1\n").arg(map->type);
149
+    text += QString("\t.2byte %1\n").arg(map->unknown);
150
+    text += QString("\t.byte %1\n").arg(map->show_location);
151
+    text += QString("\t.byte %1\n").arg(map->battle_scene);
152
+    saveTextFile(header_path, text);
153
+}
154
+
155
+void Project::readMapAttributes(Map* map) {
156
+    Asm *parser = new Asm;
157
+
158
+    QString assets_text = readTextFile(root + "/data/maps/_assets.s");
159
+    QStringList *attributes = getLabelValues(parser->parse(assets_text), map->attributes_label);
160
+    map->width = attributes->value(0);
161
+    map->height = attributes->value(1);
162
+    map->border_label = attributes->value(2);
163
+    map->blockdata_label = attributes->value(3);
164
+    map->tileset_primary_label = attributes->value(4);
165
+    map->tileset_secondary_label = attributes->value(5);
166
+}
167
+
168
+void Project::getTilesets(Map* map) {
169
+    map->tileset_primary = getTileset(map->tileset_primary_label);
170
+    map->tileset_secondary = getTileset(map->tileset_secondary_label);
171
+}
172
+
173
+Tileset* Project::loadTileset(QString label) {
174
+    Asm *parser = new Asm;
175
+
176
+    QString headers_text = readTextFile(root + "/data/tilesets/headers.s");
177
+    QStringList *values = getLabelValues(parser->parse(headers_text), label);
178
+    Tileset *tileset = new Tileset;
179
+    tileset->name = label;
180
+    tileset->is_compressed = values->value(0);
181
+    tileset->is_secondary = values->value(1);
182
+    tileset->padding = values->value(2);
183
+    tileset->tiles_label = values->value(3);
184
+    tileset->palettes_label = values->value(4);
185
+    tileset->metatiles_label = values->value(5);
186
+    tileset->metatile_attrs_label = values->value(6);
187
+    tileset->callback_label = values->value(7);
188
+
189
+    loadTilesetAssets(tileset);
190
+
191
+    tileset_cache->insert(label, tileset);
192
+    return tileset;
193
+}
194
+
195
+QString Project::getBlockdataPath(Map* map) {
196
+    QString text = readTextFile(root + "/data/maps/_assets.s");
197
+    QStringList *values = getLabelValues(parse(text), map->blockdata_label);
198
+    QString path;
199
+    if (!values->isEmpty()) {
200
+        path = root + "/" + values->value(0).section('"', 1, 1);
201
+    } else {
202
+        path = root + "/data/maps/" + map->name + "/map.bin";
203
+    }
204
+    return path;
205
+}
206
+
207
+QString Project::getMapBorderPath(Map *map) {
208
+    QString text = readTextFile(root + "/data/maps/_assets.s");
209
+    QStringList *values = getLabelValues(parse(text), map->border_label);
210
+    QString path;
211
+    if (!values->isEmpty()) {
212
+        path = root + "/" + values->value(0).section('"', 1, 1);
213
+    } else {
214
+        path = root + "/data/maps/" + map->name + "/border.bin";
215
+    }
216
+    return path;
217
+}
218
+
219
+void Project::loadBlockdata(Map* map) {
220
+    QString path = getBlockdataPath(map);
221
+    map->blockdata = readBlockdata(path);
222
+}
223
+
224
+void Project::loadMapBorder(Map *map) {
225
+    QString path = getMapBorderPath(map);
226
+    map->border = readBlockdata(path);
227
+}
228
+
229
+void Project::saveBlockdata(Map* map) {
230
+    QString path = getBlockdataPath(map);
231
+    writeBlockdata(path, map->blockdata);
232
+}
233
+
234
+void Project::writeBlockdata(QString path, Blockdata *blockdata) {
235
+    QFile file(path);
236
+    if (file.open(QIODevice::WriteOnly)) {
237
+        QByteArray data = blockdata->serialize();
238
+        file.write(data);
239
+    }
240
+}
241
+
242
+void Project::saveAllMaps() {
243
+    QList<QString> keys = map_cache->keys();
244
+    for (int i = 0; i < keys.length(); i++) {
245
+        QString key = keys.value(i);
246
+        Map* map = map_cache->value(key);
247
+        saveMap(map);
248
+    }
249
+}
250
+
251
+void Project::saveMap(Map *map) {
252
+    saveBlockdata(map);
253
+    saveMapHeader(map);
254
+}
255
+
256
+void Project::loadTilesetAssets(Tileset* tileset) {
257
+    Asm* parser = new Asm;
258
+    QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
259
+    QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower();
260
+
261
+    QString graphics_text = readTextFile(root + "/data/tilesets/graphics.s");
262
+    QList<QStringList> *graphics = parser->parse(graphics_text);
263
+    QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
264
+    QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
265
+
266
+    QString tiles_path;
267
+    if (!tiles_values->isEmpty()) {
268
+        tiles_path = root + "/" + tiles_values->value(0).section('"', 1, 1);
269
+    } else {
270
+        tiles_path = dir_path + "/tiles.4bpp";
271
+        if (tileset->is_compressed == "TRUE") {
272
+            tiles_path += ".lz";
273
+        }
274
+    }
275
+
276
+    QStringList *palette_paths = new QStringList;
277
+    if (!palettes_values->isEmpty()) {
278
+        for (int i = 0; i < palettes_values->length(); i++) {
279
+            QString value = palettes_values->value(i);
280
+            palette_paths->append(root + "/" + value.section('"', 1, 1));
281
+        }
282
+    } else {
283
+        QString palettes_dir_path = dir_path + "/palettes";
284
+        for (int i = 0; i < 16; i++) {
285
+            palette_paths->append(palettes_dir_path + "/" + QString("%1").arg(i, 2, 10, QLatin1Char('0')) + ".gbapal");
286
+        }
287
+    }
288
+
289
+    QString metatiles_path;
290
+    QString metatile_attrs_path;
291
+    QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.s");
292
+    QList<QStringList> *metatiles_macros = parser->parse(metatiles_text);
293
+    QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
294
+    if (!metatiles_values->isEmpty()) {
295
+        metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
296
+    } else {
297
+        metatiles_path = dir_path + "/metatiles.bin";
298
+    }
299
+    QStringList *metatile_attrs_values = getLabelValues(metatiles_macros, tileset->metatile_attrs_label);
300
+    if (!metatile_attrs_values->isEmpty()) {
301
+        metatile_attrs_path = root + "/" + metatile_attrs_values->value(0).section('"', 1, 1);
302
+    } else {
303
+        metatile_attrs_path = dir_path + "/metatile_attributes.bin";
304
+    }
305
+
306
+    // tiles
307
+    tiles_path = fixGraphicPath(tiles_path);
308
+    QImage *image = new QImage(tiles_path);
309
+    //image->setColor(0, qRgb(0xff, 0, 0)); // debug
310
+
311
+    QList<QImage> *tiles = new QList<QImage>;
312
+    int w = 8;
313
+    int h = 8;
314
+    for (int y = 0; y < image->height(); y += h)
315
+    for (int x = 0; x < image->width(); x += w) {
316
+        QImage tile = image->copy(x, y, w, h);
317
+        tiles->append(tile);
318
+    }
319
+    tileset->tiles = tiles;
320
+
321
+    // metatiles
322
+    //qDebug() << metatiles_path;
323
+    QFile metatiles_file(metatiles_path);
324
+    if (metatiles_file.open(QIODevice::ReadOnly)) {
325
+        QByteArray data = metatiles_file.readAll();
326
+        int num_metatiles = data.length() / 16;
327
+        int num_layers = 2;
328
+        QList<Metatile*> *metatiles = new QList<Metatile*>;
329
+        for (int i = 0; i < num_metatiles; i++) {
330
+            Metatile *metatile = new Metatile;
331
+            int index = i * 16;
332
+            for (int j = 0; j < 4 * num_layers; j++) {
333
+                uint16_t word = data[index++] & 0xff;
334
+                word += (data[index++] & 0xff) << 8;
335
+                Tile tile;
336
+                tile.tile = word & 0x3ff;
337
+                tile.xflip = (word >> 10) & 1;
338
+                tile.yflip = (word >> 11) & 1;
339
+                tile.palette = (word >> 12) & 0xf;
340
+                metatile->tiles->append(tile);
341
+            }
342
+            metatiles->append(metatile);
343
+        }
344
+        tileset->metatiles = metatiles;
345
+    }
346
+
347
+    QFile attrs_file(metatile_attrs_path);
348
+    //qDebug() << metatile_attrs_path;
349
+    if (attrs_file.open(QIODevice::ReadOnly)) {
350
+        QByteArray data = attrs_file.readAll();
351
+        int num_metatiles = data.length() / 2;
352
+        for (int i = 0; i < num_metatiles; i++) {
353
+            uint16_t word = data[i*2] & 0xff;
354
+            word += (data[i*2 + 1] & 0xff) << 8;
355
+            tileset->metatiles->value(i)->attr = word;
356
+        }
357
+    }
358
+
359
+    // palettes
360
+    QList<QList<QRgb>> *palettes = new QList<QList<QRgb>>;
361
+    for (int i = 0; i < palette_paths->length(); i++) {
362
+        QString path = palette_paths->value(i);
363
+        // the palettes are not compressed. this should never happen. it's only a precaution.
364
+        path = path.replace(QRegExp("\\.lz$"), "");
365
+        // TODO default to .pal (JASC-PAL)
366
+        // just use .gbapal for now
367
+        QFile file(path);
368
+        QList<QRgb> palette;
369
+        if (file.open(QIODevice::ReadOnly)) {
370
+            QByteArray data = file.readAll();
371
+            for (int j = 0; j < 16; j++) {
372
+                uint16_t word = data[j*2] & 0xff;
373
+                word += (data[j*2 + 1] & 0xff) << 8;
374
+                int red = word & 0x1f;
375
+                int green = (word >> 5) & 0x1f;
376
+                int blue = (word >> 10) & 0x1f;
377
+                QRgb color = qRgb(red * 8, green * 8, blue * 8);
378
+                palette.prepend(color);
379
+            }
380
+        }
381
+        //qDebug() << path;
382
+        palettes->append(palette);
383
+    }
384
+    tileset->palettes = palettes;
385
+}
386
+
387
+Blockdata* Project::readBlockdata(QString path) {
388
+    Blockdata *blockdata = new Blockdata;
389
+    //qDebug() << path;
390
+    QFile file(path);
391
+    if (file.open(QIODevice::ReadOnly)) {
392
+        QByteArray data = file.readAll();
393
+        for (int i = 0; (i + 1) < data.length(); i += 2) {
394
+            uint16_t word = (data[i] & 0xff) + ((data[i + 1] & 0xff) << 8);
395
+            blockdata->addBlock(word);
396
+        }
397
+    }
398
+    return blockdata;
399
+}
400
+
401
+Map* Project::getMap(QString map_name) {
402
+    if (map_cache->contains(map_name)) {
403
+        return map_cache->value(map_name);
404
+    } else {
405
+        Map *map = loadMap(map_name);
406
+        return map;
407
+    }
408
+}
409
+
410
+Tileset* Project::getTileset(QString label) {
411
+    if (tileset_cache->contains(label)) {
412
+        return tileset_cache->value(label);
413
+    } else {
414
+        Tileset *tileset = loadTileset(label);
415
+        return tileset;
416
+    }
417
+}
418
+
419
+QString Project::readTextFile(QString path) {
420
+    QFile file(path);
421
+    if (!file.open(QIODevice::ReadOnly)) {
422
+        //QMessageBox::information(0, "Error", QString("Could not open '%1': ").arg(path) + file.errorString());
423
+        return NULL;
424
+    }
425
+    QTextStream in(&file);
426
+    QString text = "";
427
+    while (!in.atEnd()) {
428
+        text += in.readLine() + "\n";
429
+    }
430
+    return text;
431
+}
432
+
433
+void Project::saveTextFile(QString path, QString text) {
434
+    QFile file(path);
435
+    if (file.open(QIODevice::WriteOnly)) {
436
+        file.write(text.toUtf8());
437
+    }
438
+}
439
+
440
+void Project::readMapGroups() {
441
+    QString text = readTextFile(root + "/data/maps/_groups.s");
442
+    if (text == NULL) {
443
+        return;
444
+    }
445
+    Asm *parser = new Asm;
446
+    QList<QStringList> *commands = parser->parse(text);
447
+
448
+    bool in_group_pointers = false;
449
+    QStringList *groups = new QStringList;
450
+    for (int i = 0; i < commands->length(); i++) {
451
+        QStringList params = commands->value(i);
452
+        QString macro = params.value(0);
453
+        if (macro == ".label") {
454
+            if (in_group_pointers) {
455
+                break;
456
+            }
457
+            if (params.value(1) == "gMapGroups") {
458
+                in_group_pointers = true;
459
+            }
460
+        } else if (macro == ".4byte") {
461
+            if (in_group_pointers) {
462
+                for (int j = 1; j < params.length(); j++) {
463
+                    groups->append(params.value(j));
464
+                }
465
+            }
466
+        }
467
+    }
468
+
469
+    QList<QStringList*> *maps = new QList<QStringList*>;
470
+    for (int i = 0; i < groups->length(); i++) {
471
+        QStringList *list = new QStringList;
472
+        maps->append(list);
473
+    }
474
+
475
+    int group = -1;
476
+    for (int i = 0; i < commands->length(); i++) {
477
+        QStringList params = commands->value(i);
478
+        QString macro = params.value(0);
479
+        if (macro == ".label") {
480
+            group = groups->indexOf(params.value(1));
481
+        } else if (macro == ".4byte") {
482
+            if (group != -1) {
483
+                for (int j = 1; j < params.length(); j++) {
484
+                    QStringList *list = maps->value(group);
485
+                    list->append(params.value(j));
486
+                }
487
+            }
488
+        }
489
+    }
490
+
491
+    groupNames = groups;
492
+    groupedMapNames = maps;
493
+}
494
+
495
+QList<QStringList>* Project::parse(QString text) {
496
+    Asm *parser = new Asm;
497
+    return parser->parse(text);
498
+}
499
+
500
+QStringList Project::getLocations() {
501
+    // TODO
502
+    QStringList names;
503
+    for (int i = 0; i < 88; i++) {
504
+        names.append(QString("%1").arg(i));
505
+    }
506
+    return names;
507
+}
508
+
509
+QStringList Project::getVisibilities() {
510
+    // TODO
511
+    QStringList names;
512
+    for (int i = 0; i < 16; i++) {
513
+        names.append(QString("%1").arg(i));
514
+    }
515
+    return names;
516
+}
517
+
518
+QStringList Project::getWeathers() {
519
+    // TODO
520
+    QStringList names;
521
+    for (int i = 0; i < 16; i++) {
522
+        names.append(QString("%1").arg(i));
523
+    }
524
+    return names;
525
+}
526
+
527
+QStringList Project::getMapTypes() {
528
+    // TODO
529
+    QStringList names;
530
+    for (int i = 0; i < 16; i++) {
531
+        names.append(QString("%1").arg(i));
532
+    }
533
+    return names;
534
+}
535
+
536
+QStringList Project::getBattleScenes() {
537
+    // TODO
538
+    QStringList names;
539
+    for (int i = 0; i < 16; i++) {
540
+        names.append(QString("%1").arg(i));
541
+    }
542
+    return names;
543
+}
544
+
545
+QStringList Project::getSongNames() {
546
+    QStringList names;
547
+    QString text = readTextFile(root + "/constants/songs.s");
548
+    if (text != NULL) {
549
+        QList<QStringList> *commands = parse(text);
550
+        for (int i = 0; i < commands->length(); i++) {
551
+            QStringList params = commands->value(i);
552
+            QString macro = params.value(0);
553
+            if (macro == ".equiv") {
554
+                names.append(params.value(1));
555
+            }
556
+        }
557
+    }
558
+    return names;
559
+}
560
+
561
+QString Project::getSongName(int value) {
562
+    QStringList names;
563
+    QString text = readTextFile(root + "/constants/songs.s");
564
+    if (text != NULL) {
565
+        QList<QStringList> *commands = parse(text);
566
+        for (int i = 0; i < commands->length(); i++) {
567
+            QStringList params = commands->value(i);
568
+            QString macro = params.value(0);
569
+            if (macro == ".equiv") {
570
+                if (value == ((QString)(params.value(2))).toInt(nullptr, 0)) {
571
+                    return params.value(1);
572
+                }
573
+            }
574
+        }
575
+    }
576
+    return "";
577
+}
578
+
579
+QMap<QString, int> Project::getMapObjGfxConstants() {
580
+    QMap<QString, int> constants;
581
+    QString text = readTextFile(root + "/constants/map_object_constants.s");
582
+    if (text != NULL) {
583
+        QList<QStringList> *commands = parse(text);
584
+        for (int i = 0; i < commands->length(); i++) {
585
+            QStringList params = commands->value(i);
586
+            QString macro = params.value(0);
587
+            if (macro == ".set") {
588
+                QString constant = params.value(1);
589
+                if (constant.startsWith("MAP_OBJ_GFX_")) {
590
+                    int value = params.value(2).toInt(nullptr, 0);
591
+                    constants.insert(constant, value);
592
+                }
593
+            }
594
+        }
595
+    }
596
+    return constants;
597
+}
598
+
599
+QString Project::fixGraphicPath(QString path) {
600
+    path = path.replace(QRegExp("\\.lz$"), "");
601
+    path = path.replace(QRegExp("\\.[1248]bpp$"), ".png");
602
+    return path;
603
+}
604
+
605
+void Project::loadObjectPixmaps(QList<ObjectEvent*> objects) {
606
+    bool needs_update = false;
607
+    for (ObjectEvent *object : objects) {
608
+        if (object->pixmap.isNull()) {
609
+            needs_update = true;
610
+            break;
611
+        }
612
+    }
613
+    if (!needs_update) {
614
+        return;
615
+    }
616
+
617
+    QMap<QString, int> constants = getMapObjGfxConstants();
618
+
619
+    QString pointers_path = root + "/data/graphics/field_objects/map_object_graphics_info_pointers.s";
620
+    QString pointers_text = readTextFile(pointers_path);
621
+    if (pointers_text == NULL) {
622
+        return;
623
+    }
624
+    QString info_path = root + "/data/graphics/field_objects/map_object_graphics_info.s";
625
+    QString info_text = readTextFile(info_path);
626
+    if (info_text == NULL) {
627
+        return;
628
+    }
629
+    QString pic_path = root + "/data/graphics/field_objects/map_object_pic_tables.s";
630
+    QString pic_text = readTextFile(pic_path);
631
+    if (pic_text == NULL) {
632
+        return;
633
+    }
634
+    QString assets_path = root + "/data/graphics/field_objects/map_object_graphics.s";
635
+    QString assets_text = readTextFile(assets_path);
636
+    if (assets_text == NULL) {
637
+        return;
638
+    }
639
+
640
+    QStringList *pointers = getLabelValues(parse(pointers_text), "gMapObjectGraphicsInfoPointers");
641
+    QList<QStringList> *info_commands = parse(info_text);
642
+    QList<QStringList> *asset_commands = parse(assets_text);
643
+    QList<QStringList> *pic_commands = parse(pic_text);
644
+
645
+    for (ObjectEvent *object : objects) {
646
+        if (!object->pixmap.isNull()) {
647
+            continue;
648
+        }
649
+        int id = constants.value(object->sprite);
650
+        QString info_label = pointers->value(id);
651
+        QStringList *info = getLabelValues(info_commands, info_label);
652
+        QString pic_label = info->value(12);
653
+
654
+        QList<QStringList> *pic = getLabelMacros(pic_commands, pic_label);
655
+        for (int i = 0; i < pic->length(); i++) {
656
+            QStringList command = pic->value(i);
657
+            QString macro = command.value(0);
658
+            if (macro == "obj_frame_tiles") {
659
+                QString label = command.value(1);
660
+                QStringList *incbins = getLabelValues(asset_commands, label);
661
+                QString path = incbins->value(0).section('"', 1, 1);
662
+                path = fixGraphicPath(path);
663
+                QPixmap pixmap(root + "/" + path);
664
+                object->pixmap = pixmap;
665
+                break;
666
+            }
667
+        }
668
+    }
669
+}
670
+
671
+void Project::readMapEvents(Map *map) {
672
+    // lazy
673
+    QString path = root + QString("/data/maps/events/%1.s").arg(map->name);
674
+    QString text = readTextFile(path);
675
+
676
+    QStringList *labels = getLabelValues(parse(text), map->events_label);
677
+    map->object_events_label = labels->value(0);
678
+    map->warps_label = labels->value(1);
679
+    map->coord_events_label = labels->value(2);
680
+    map->bg_events_label = labels->value(3);
681
+
682
+    QList<QStringList> *object_events = getLabelMacros(parse(text), map->object_events_label);
683
+    map->object_events.clear();
684
+    for (QStringList command : *object_events) {
685
+        if (command.value(0) == "object_event") {
686
+            ObjectEvent *object = new ObjectEvent;
687
+            // This macro is not fixed as of writing, but it should take fewer args.
688
+            bool old_macro = false;
689
+            if (command.length() >= 20) {
690
+                command.removeAt(19);
691
+                command.removeAt(18);
692
+                command.removeAt(15);
693
+                command.removeAt(13);
694
+                command.removeAt(11);
695
+                command.removeAt(7);
696
+                command.removeAt(5);
697
+                command.removeAt(1); // id. not 0, but is just the index in the list of objects
698
+                old_macro = true;
699
+            }
700
+            int i = 1;
701
+            object->sprite = command.value(i++);
702
+            object->replacement = command.value(i++);
703
+            object->x_ = command.value(i++);
704
+            object->y_ = command.value(i++);
705
+            object->elevation_ = command.value(i++);
706
+            object->behavior = command.value(i++);
707
+            if (old_macro) {
708
+                int radius = command.value(i++).toInt(nullptr, 0);
709
+                object->radius_x = QString("%1").arg(radius & 0xf);
710
+                object->radius_y = QString("%1").arg((radius >> 4) & 0xf);
711
+            } else {
712
+                object->radius_x = command.value(i++);
713
+                object->radius_y = command.value(i++);
714
+            }
715
+            object->property = command.value(i++);
716
+            object->sight_radius = command.value(i++);
717
+            object->script_label = command.value(i++);
718
+            object->event_flag = command.value(i++);
719
+
720
+            map->object_events.append(object);
721
+        }
722
+    }
723
+
724
+    QList<QStringList> *warps = getLabelMacros(parse(text), map->warps_label);
725
+    map->warps.clear();
726
+    for (QStringList command : *warps) {
727
+        if (command.value(0) == "warp_def") {
728
+            Warp *warp = new Warp;
729
+            int i = 1;
730
+            warp->x_ = command.value(i++);
731
+            warp->y_ = command.value(i++);
732
+            warp->elevation_ = command.value(i++);
733
+            warp->destination_warp = command.value(i++);
734
+            warp->destination_map = command.value(i++);
735
+            map->warps.append(warp);
736
+        }
737
+    }
738
+
739
+    QList<QStringList> *coords = getLabelMacros(parse(text), map->coord_events_label);
740
+    map->coord_events.clear();
741
+    for (QStringList command : *coords) {
742
+        if (command.value(0) == "coord_event") {
743
+            CoordEvent *coord = new CoordEvent;
744
+            bool old_macro = false;
745
+            if (command.length() >= 9) {
746
+                command.removeAt(7);
747
+                command.removeAt(6);
748
+                command.removeAt(4);
749
+                old_macro = true;
750
+            }
751
+            int i = 1;
752
+            coord->x_ = command.value(i++);
753
+            coord->y_ = command.value(i++);
754
+            coord->elevation_ = command.value(i++);
755
+            coord->unknown1 = command.value(i++);
756
+            coord->script_label = command.value(i++);
757
+            map->coord_events.append(coord);
758
+        }
759
+    }
760
+
761
+    QList<QStringList> *bgs = getLabelMacros(parse(text), map->warps_label);
762
+    map->hidden_items.clear();
763
+    map->signs.clear();
764
+    for (QStringList command : *bgs) {
765
+        if (command.value(0) == "bg_event") {
766
+            BGEvent *bg = new BGEvent;
767
+            int i = 1;
768
+            bg->x_ = command.value(i++);
769
+            bg->y_ = command.value(i++);
770
+            bg->elevation_ = command.value(i++);
771
+            bg->type = command.value(i++);
772
+            i++;
773
+            if (bg->is_item()) {
774
+                HiddenItem *item = new HiddenItem(*bg);
775
+                item->item = command.value(i++);
776
+                item->unknown5 = command.value(i++);
777
+                item->unknown6 = command.value(i++);
778
+                map->hidden_items.append(item);
779
+            } else {
780
+                Sign *sign = new Sign(*bg);
781
+                sign->script_label = command.value(i++);
782
+                map->signs.append(sign);
783
+            }
784
+        }
785
+    }
786
+
787
+}

+ 69
- 0
project.h View File

@@ -0,0 +1,69 @@
1
+#ifndef PROJECT_H
2
+#define PROJECT_H
3
+
4
+#include "map.h"
5
+#include "blockdata.h"
6
+
7
+#include <QStringList>
8
+#include <QList>
9
+
10
+class Project
11
+{
12
+public:
13
+    Project();
14
+    QString root;
15
+    QStringList *groupNames;
16
+    QList<QStringList*> *groupedMapNames;
17
+
18
+    QMap<QString, Map*> *map_cache;
19
+    Map* loadMap(QString);
20
+    Map* getMap(QString);
21
+
22
+    QMap<QString, Tileset*> *tileset_cache;
23
+    Tileset* loadTileset(QString);
24
+    Tileset* getTileset(QString);
25
+
26
+    Blockdata* readBlockdata(QString);
27
+    void loadBlockdata(Map*);
28
+
29
+    QString readTextFile(QString path);
30
+    void saveTextFile(QString path, QString text);
31
+
32
+    void readMapGroups();
33
+    QString getProjectTitle();
34
+
35
+    QList<QStringList>* getLabelMacros(QList<QStringList>*, QString);
36
+    QStringList* getLabelValues(QList<QStringList>*, QString);
37
+    void readMapHeader(Map*);
38
+    void readMapAttributes(Map*);
39
+    void getTilesets(Map*);
40
+    void loadTilesetAssets(Tileset*);
41
+
42
+    QString getBlockdataPath(Map*);
43
+    void saveBlockdata(Map*);
44
+    void writeBlockdata(QString, Blockdata*);
45
+    void saveAllMaps();
46
+    void saveMap(Map*);
47
+    void saveMapHeader(Map*);
48
+
49
+    QList<QStringList>* parse(QString text);
50
+    QStringList getSongNames();
51
+    QString getSongName(int);
52
+    QStringList getLocations();
53
+    QStringList getVisibilities();
54
+    QStringList getWeathers();
55
+    QStringList getMapTypes();
56
+    QStringList getBattleScenes();
57
+
58
+    void loadObjectPixmaps(QList<ObjectEvent*> objects);
59
+    QMap<QString, int> getMapObjGfxConstants();
60
+    QString fixGraphicPath(QString path);
61
+
62
+    void readMapEvents(Map *map);
63
+    void loadMapConnections(Map *map);
64
+
65
+    void loadMapBorder(Map *map);
66
+    QString getMapBorderPath(Map *map);
67
+};
68
+
69
+#endif // PROJECT_H

BIN
resources/icons/folder.ico View File


BIN
resources/icons/folder_closed.ico View File


BIN
resources/icons/folder_closed_map.ico View File


BIN
resources/icons/folder_image.ico View File


BIN
resources/icons/folder_map.ico View File


BIN
resources/icons/image.ico View File


BIN
resources/icons/map.ico View File


+ 11
- 0
resources/images.qrc View File

@@ -0,0 +1,11 @@
1
+<RCC>
2
+    <qresource prefix="/">
3
+        <file>icons/folder.ico</file>
4
+        <file>icons/folder_closed.ico</file>
5
+        <file>icons/folder_closed_map.ico</file>
6
+        <file>icons/folder_image.ico</file>
7
+        <file>icons/folder_map.ico</file>
8
+        <file>icons/image.ico</file>
9
+        <file>icons/map.ico</file>
10
+    </qresource>
11
+</RCC>

+ 6
- 0
tile.cpp View File

@@ -0,0 +1,6 @@
1
+#include "tile.h"
2
+
3
+Tile::Tile()
4
+{
5
+
6
+}

+ 16
- 0
tile.h View File

@@ -0,0 +1,16 @@
1
+#ifndef TILE_H
2
+#define TILE_H
3
+
4
+
5
+class Tile
6
+{
7
+public:
8
+    Tile();
9
+public:
10
+    int tile;
11
+    int xflip;
12
+    int yflip;
13
+    int palette;
14
+};
15
+
16
+#endif // TILE_H

+ 6
- 0
tileset.cpp View File

@@ -0,0 +1,6 @@
1
+#include "tileset.h"
2
+
3
+Tileset::Tileset()
4
+{
5
+
6
+}

+ 27
- 0
tileset.h View File

@@ -0,0 +1,27 @@
1
+#ifndef TILESET_H
2
+#define TILESET_H
3
+
4
+#include "metatile.h"
5
+#include <QImage>
6
+
7
+class Tileset
8
+{
9
+public:
10
+    Tileset();
11
+public:
12
+    QString name;
13
+    QString is_compressed;
14
+    QString is_secondary;
15
+    QString padding;
16
+    QString tiles_label;
17
+    QString palettes_label;
18
+    QString metatiles_label;
19
+    QString callback_label;
20
+    QString metatile_attrs_label;
21
+
22
+    QList<QImage> *tiles;
23
+    QList<Metatile*> *metatiles;
24
+    QList<QList<QRgb>> *palettes;
25
+};
26
+
27
+#endif // TILESET_H