Merge pull request #217 from huderlem/scripting

Add Scripting API
This commit is contained in:
huderlem 2020-05-10 09:50:40 -05:00 committed by GitHub
commit 73b5e2b272
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1206 additions and 118 deletions

View file

@ -113,6 +113,7 @@ public:
this->baseGameVersion = BaseGameVersion::pokeemerald;
this->useEncounterJson = true;
this->useCustomBorderSize = false;
this->customScripts.clear();
}
void setBaseGameVersion(BaseGameVersion baseGameVersion);
BaseGameVersion getBaseGameVersion();
@ -121,8 +122,11 @@ public:
void setUsePoryScript(bool usePoryScript);
bool getUsePoryScript();
void setProjectDir(QString projectDir);
QString getProjectDir();
void setUseCustomBorderSize(bool enable);
bool getUseCustomBorderSize();
void setCustomScripts(QList<QString> scripts);
QList<QString> getCustomScripts();
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
@ -134,6 +138,7 @@ private:
bool useEncounterJson;
bool usePoryScript;
bool useCustomBorderSize;
QList<QString> customScripts;
};
extern ProjectConfig projectConfig;

View file

@ -8,6 +8,7 @@ class Block
public:
Block();
Block(uint16_t);
Block(uint16_t tile, uint16_t collision, uint16_t elevation);
Block(const Block&);
bool operator ==(Block);
bool operator !=(Block);

View file

@ -74,8 +74,7 @@ public:
void cacheBlockdata();
void cacheCollision();
Block *getBlock(int x, int y);
void setBlock(int x, int y, Block block);
void _setBlock(int x, int y, Block block);
void setBlock(int x, int y, Block block, bool enableScriptCallback = false);
void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void magicFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
@ -86,7 +85,7 @@ public:
void removeEvent(Event*);
void addEvent(Event*);
QPixmap renderConnection(MapConnection, MapLayout *);
QPixmap renderBorder();
QPixmap renderBorder(bool ignoreCache = false);
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true);
void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true);
void cacheBorder();

View file

@ -28,13 +28,14 @@ public:
QList<QImage> *tiles = nullptr;
QList<Metatile*> *metatiles = nullptr;
QList<QList<QRgb>> *palettes = nullptr;
QList<QList<QRgb>> *palettePreviews = nullptr;
Tileset* copy();
static Tileset* getBlockTileset(int, Tileset*, Tileset*);
static Metatile* getMetatile(int, Tileset*, Tileset*);
static QList<QList<QRgb>> getBlockPalettes(Tileset*, Tileset*);
static QList<QRgb> getPalette(int, Tileset*, Tileset*);
static QList<QList<QRgb>> getBlockPalettes(Tileset*, Tileset*, bool useTruePalettes = false);
static QList<QRgb> getPalette(int, Tileset*, Tileset*, bool useTruePalettes = false);
static bool metatileIsValid(uint16_t metatileId, Tileset *, Tileset *);
bool appendToHeaders(QString headerFile, QString friendlyName);

View file

@ -66,6 +66,9 @@ public:
void displayMapGrid();
void displayWildMonTables();
void updateMapBorder();
void updateMapConnections();
void setEditingMap();
void setEditingCollision();
void setEditingObjects();

View file

@ -10,6 +10,7 @@
#include <QGraphicsSceneMouseEvent>
#include <QCloseEvent>
#include <QAbstractItemModel>
#include <QJSValue>
#include "project.h"
#include "config.h"
#include "map.h"
@ -37,6 +38,74 @@ public:
MainWindow(const MainWindow &) = delete;
MainWindow & operator = (const MainWindow &) = delete;
// Scripting API
Q_INVOKABLE QJSValue getBlock(int x, int y);
void tryRedrawMapArea(bool forceRedraw);
void tryCommitMapChanges(bool commitChanges);
Q_INVOKABLE void setBlock(int x, int y, int tile, int collision, int elevation, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void setBlocksFromSelection(int x, int y, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE int getMetatileId(int x, int y);
Q_INVOKABLE void setMetatileId(int x, int y, int metatileId, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE int getCollision(int x, int y);
Q_INVOKABLE void setCollision(int x, int y, int collision, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE int getElevation(int x, int y);
Q_INVOKABLE void setElevation(int x, int y, int elevation, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void bucketFill(int x, int y, int metatileId, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void bucketFillFromSelection(int x, int y, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void magicFill(int x, int y, int metatileId, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void magicFillFromSelection(int x, int y, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void shift(int xDelta, int yDelta, bool forceRedraw = true, bool commitChanges = true);
Q_INVOKABLE void redraw();
Q_INVOKABLE void commit();
Q_INVOKABLE QJSValue getDimensions();
Q_INVOKABLE int getWidth();
Q_INVOKABLE int getHeight();
Q_INVOKABLE void setDimensions(int width, int height);
Q_INVOKABLE void setWidth(int width);
Q_INVOKABLE void setHeight(int height);
Q_INVOKABLE void clearOverlay();
Q_INVOKABLE void addText(QString text, int x, int y, QString color = "#000000", int fontSize = 12);
Q_INVOKABLE void addRect(int x, int y, int width, int height, QString color = "#000000");
Q_INVOKABLE void addFilledRect(int x, int y, int width, int height, QString color = "#000000");
Q_INVOKABLE void addImage(int x, int y, QString filepath);
void refreshAfterPaletteChange(Tileset *tileset);
void setTilesetPalette(Tileset *tileset, int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes);
Q_INVOKABLE void setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes);
QJSValue getTilesetPalette(QList<QList<QRgb>> *palettes, int paletteIndex);
QJSValue getTilesetPalettes(QList<QList<QRgb>> *palettes);
Q_INVOKABLE QJSValue getPrimaryTilesetPalette(int paletteIndex);
Q_INVOKABLE QJSValue getPrimaryTilesetPalettes();
Q_INVOKABLE QJSValue getSecondaryTilesetPalette(int paletteIndex);
Q_INVOKABLE QJSValue getSecondaryTilesetPalettes();
void refreshAfterPalettePreviewChange();
void setTilesetPalettePreview(Tileset *tileset, int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes);
Q_INVOKABLE void setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes);
Q_INVOKABLE QJSValue getPrimaryTilesetPalettePreview(int paletteIndex);
Q_INVOKABLE QJSValue getPrimaryTilesetPalettesPreview();
Q_INVOKABLE QJSValue getSecondaryTilesetPalettePreview(int paletteIndex);
Q_INVOKABLE QJSValue getSecondaryTilesetPalettesPreview();
Q_INVOKABLE QString getPrimaryTileset();
Q_INVOKABLE QString getSecondaryTileset();
Q_INVOKABLE void setPrimaryTileset(QString tileset);
Q_INVOKABLE void setSecondaryTileset(QString tileset);
Q_INVOKABLE void setGridVisibility(bool visible);
Q_INVOKABLE bool getGridVisibility();
Q_INVOKABLE void setBorderVisibility(bool visible);
Q_INVOKABLE bool getBorderVisibility();
Q_INVOKABLE void setSmartPathsEnabled(bool visible);
Q_INVOKABLE bool getSmartPathsEnabled();
Q_INVOKABLE void registerAction(QString functionName, QString actionName, QString shortcut = "");
Q_INVOKABLE void setTimeout(QJSValue callback, int milliseconds);
void invokeCallback(QJSValue callback);
Q_INVOKABLE void log(QString message);
public slots:
void scaleMapView(int);
@ -189,6 +258,8 @@ private:
DraggablePixmapItem *selectedBG;
DraggablePixmapItem *selectedHealspot;
QList<QAction *> registeredActions;
bool isProgrammaticEventTabChange;
bool projectHasUnsavedChanges;
@ -205,6 +276,7 @@ private:
QString getDefaultMap();
void setRecentMap(QString map_name);
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
static bool mapDimensionsValid(int width, int height);
void drawMapListIcons(QAbstractItemModel *model);
void updateMapList();

View file

@ -142,7 +142,7 @@ public:
void saveTilesetMetatileAttributes(Tileset*);
void saveTilesetMetatiles(Tileset*);
void saveTilesetTilesImage(Tileset*);
void saveTilesetPalettes(Tileset*, bool);
void saveTilesetPalettes(Tileset*);
QString defaultSong;
QStringList getSongNames();

43
include/scripting.h Normal file
View file

@ -0,0 +1,43 @@
#ifndef SCRIPTING_H
#define SCRIPTING_H
#include "mainwindow.h"
#include "block.h"
#include <QStringList>
#include <QJSEngine>
enum CallbackType {
OnProjectOpened,
OnProjectClosed,
OnBlockChanged,
OnMapOpened,
};
class Scripting
{
public:
Scripting(MainWindow *mainWindow);
static QJSValue fromBlock(Block block);
static QJSValue dimensions(int width, int height);
static QJSEngine *getEngine();
static void init(MainWindow *mainWindow);
static void registerAction(QString functionName, QString actionName);
static int numRegisteredActions();
static void invokeAction(QString actionName);
static void cb_ProjectOpened(QString projectPath);
static void cb_ProjectClosed(QString projectPath);
static void cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock);
static void cb_MapOpened(QString mapName);
private:
QJSEngine *engine;
QStringList filepaths;
QList<QJSValue> modules;
QMap<QString, QString> registeredActions;
void loadModules(QStringList moduleFiles);
void invokeCallback(CallbackType type, QJSValueList args);
};
#endif // SCRIPTING_H

View file

@ -1,6 +1,7 @@
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include "overlay.h"
#include <QGraphicsView>
#include <QMouseEvent>
@ -15,10 +16,12 @@ public:
public:
// GraphicsView_Object object;
Editor *editor;
Overlay overlay;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void drawForeground(QPainter *painter, const QRectF &rect);
};
//Q_DECLARE_METATYPE(GraphicsView)

View file

@ -8,9 +8,9 @@
QImage getCollisionMetatileImage(Block);
QImage getCollisionMetatileImage(int, int);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*, bool useTruePalettes = false);
QImage getTileImage(uint16_t, Tileset*, Tileset*);
QImage getPalettedTileImage(uint16_t, Tileset*, Tileset*, int);
QImage getPalettedTileImage(uint16_t, Tileset*, Tileset*, int, bool useTruePalettes = false);
QImage getGreyscaleTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset);
static QList<QRgb> greyscalePalette({

View file

@ -38,17 +38,34 @@ public:
virtual void paint(QGraphicsSceneMouseEvent*);
virtual void floodFill(QGraphicsSceneMouseEvent*);
virtual void magicFill(QGraphicsSceneMouseEvent*);
void _floodFill(int x, int y);
void _floodFillSmartPath(int initialX, int initialY);
void magicFill(int x, int y, uint16_t metatileId, bool fromScriptCall = false);
void magicFill(int x, int y, bool fromScriptCall = false);
void magicFill(
int initialX,
int initialY,
QPoint selectionDimensions,
QList<uint16_t> *selectedMetatiles,
QList<QPair<uint16_t, uint16_t>> *selectedCollisions,
bool fromScriptCall = false);
void floodFill(int x, int y, bool fromScriptCall = false);
void floodFill(int x, int y, uint16_t metatileId, bool fromScriptCall = false);
void floodFill(int initialX,
int initialY,
QPoint selectionDimensions,
QList<uint16_t> *selectedMetatiles,
QList<QPair<uint16_t, uint16_t>> *selectedCollisions,
bool fromScriptCall = false);
void floodFillSmartPath(int initialX, int initialY, bool fromScriptCall = false);
virtual void pick(QGraphicsSceneMouseEvent*);
virtual void select(QGraphicsSceneMouseEvent*);
virtual void shift(QGraphicsSceneMouseEvent*);
void shift(int xDelta, int yDelta);
virtual void draw(bool ignoreCache = false);
void updateMetatileSelection(QGraphicsSceneMouseEvent *event);
void paintNormal(int x, int y, bool fromScriptCall = false);
private:
void paintNormal(int x, int y);
void paintSmartPath(int x, int y);
void paintSmartPath(int x, int y, bool fromScriptCall = false);
static QList<int> smartPathTable;
signals:

87
include/ui/overlay.h Normal file
View file

@ -0,0 +1,87 @@
#ifndef OVERLAY_H
#define OVERLAY_H
#include <QList>
#include <QString>
#include <QColor>
#include <QPainter>
class OverlayItem {
public:
OverlayItem() {}
virtual ~OverlayItem() {};
virtual void render(QPainter *painter) {};
};
class OverlayText : public OverlayItem {
public:
OverlayText(QString text, int x, int y, QColor color, int fontSize) {
this->text = text;
this->x = x;
this->y = y;
this->color = color;
this->fontSize = fontSize;
}
~OverlayText() {}
virtual void render(QPainter *painter);
private:
QString text;
int x;
int y;
QColor color;
int fontSize;
};
class OverlayRect : public OverlayItem {
public:
OverlayRect(int x, int y, int width, int height, QColor color, bool filled) {
this->x = x;
this->y = y;
this->width = width;
this->height = height;
this->color = color;
this->filled = filled;
}
~OverlayRect() {}
virtual void render(QPainter *painter);
private:
int x;
int y;
int width;
int height;
QColor color;
bool filled;
};
class OverlayImage : public OverlayItem {
public:
OverlayImage(int x, int y, QImage image) {
this->x = x;
this->y = y;
this->image = image;
}
~OverlayImage() {}
virtual void render(QPainter *painter);
private:
int x;
int y;
QImage image;
};
class Overlay
{
public:
Overlay() {}
~Overlay() {
this->clearItems();
}
QList<OverlayItem*> getItems();
void clearItems();
void addText(QString text, int x, int y, QString color = "#000000", int fontSize = 12);
void addRect(int x, int y, int width, int height, QString color = "#000000", bool filled = false);
void addImage(int x, int y, QString filepath);
private:
QList<OverlayItem*> items;
};
#endif // OVERLAY_H

View file

@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core gui
QT += core gui qml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@ -31,11 +31,13 @@ SOURCES += src/core/block.cpp \
src/core/regionmap.cpp \
src/core/wildmoninfo.cpp \
src/lib/orderedjson.cpp \
src/mainwindow_scriptapi.cpp \
src/ui/aboutporymap.cpp \
src/ui/bordermetatilespixmapitem.cpp \
src/ui/collisionpixmapitem.cpp \
src/ui/connectionpixmapitem.cpp \
src/ui/currentselectedmetatilespixmapitem.cpp \
src/ui/overlay.cpp \
src/ui/regionmaplayoutpixmapitem.cpp \
src/ui/regionmapentriespixmapitem.cpp \
src/ui/cursortilerect.cpp \
@ -70,6 +72,7 @@ SOURCES += src/core/block.cpp \
src/main.cpp \
src/mainwindow.cpp \
src/project.cpp \
src/scripting.cpp \
src/settings.cpp \
src/log.cpp \
src/ui/newtilesetdialog.cpp
@ -94,7 +97,7 @@ HEADERS += include/core/block.h \
include/core/wildmoninfo.h \
include/lib/orderedmap.h \
include/lib/orderedjson.h \
include/ui/aboutporymap.h \
include/ui/aboutporymap.h \
include/ui/bordermetatilespixmapitem.h \
include/ui/collisionpixmapitem.h \
include/ui/connectionpixmapitem.h \
@ -133,9 +136,11 @@ HEADERS += include/core/block.h \
include/editor.h \
include/mainwindow.h \
include/project.h \
include/scripting.h \
include/settings.h \
include/log.h \
include/ui/newtilesetdialog.h
include/ui/newtilesetdialog.h \
include/ui/overlay.h
FORMS += forms/mainwindow.ui \
forms/eventpropertiesframe.ui \

View file

@ -36,7 +36,7 @@ void KeyValueConfigBase::load() {
QTextStream in(&file);
in.setCodec("UTF-8");
QList<QString> configLines;
QRegularExpression re("^(?<key>.+)=(?<value>.+)$");
QRegularExpression re("^(?<key>.+)=(?<value>.*)$");
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
int commentIndex = line.indexOf("#");
@ -380,6 +380,15 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
if (!ok) {
logWarn(QString("Invalid config value for use_custom_border_size: '%1'. Must be 0 or 1.").arg(value));
}
} else if (key == "custom_scripts") {
this->customScripts.clear();
QList<QString> paths = value.split(",");
paths.removeDuplicates();
for (QString script : paths) {
if (!script.isEmpty()) {
this->customScripts.append(script);
}
}
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
}
@ -391,6 +400,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
map.insert("use_encounter_json", QString::number(this->useEncounterJson));
map.insert("use_poryscript", QString::number(this->usePoryScript));
map.insert("use_custom_border_size", QString::number(this->useCustomBorderSize));
map.insert("custom_scripts", this->customScripts.join(","));
return map;
}
@ -423,12 +433,17 @@ void ProjectConfig::onNewConfigFileCreated() {
this->useCustomBorderSize = this->baseGameVersion == BaseGameVersion::pokefirered;
this->useEncounterJson = true;
this->usePoryScript = false;
this->customScripts.clear();
}
void ProjectConfig::setProjectDir(QString projectDir) {
this->projectDir = projectDir;
}
QString ProjectConfig::getProjectDir() {
return this->projectDir;
}
void ProjectConfig::setBaseGameVersion(BaseGameVersion baseGameVersion) {
this->baseGameVersion = baseGameVersion;
this->save();
@ -464,3 +479,12 @@ void ProjectConfig::setUseCustomBorderSize(bool enable) {
bool ProjectConfig::getUseCustomBorderSize() {
return this->useCustomBorderSize;
}
void ProjectConfig::setCustomScripts(QList<QString> scripts) {
this->customScripts = scripts;
this->save();
}
QList<QString> ProjectConfig::getCustomScripts() {
return this->customScripts;
}

View file

@ -3,6 +3,12 @@
Block::Block() : tile(0), collision(0), elevation(0) {
}
Block::Block(uint16_t tile, uint16_t collision, uint16_t elevation) {
this->tile = tile;
this->collision = collision;
this->elevation = elevation;
}
Block::Block(uint16_t word)
{
tile = word & 0x3ff;

View file

@ -2,6 +2,7 @@
#include "historyitem.h"
#include "map.h"
#include "imageproviders.h"
#include "scripting.h"
#include <QTime>
#include <QPainter>
@ -220,7 +221,7 @@ QPixmap Map::render(bool ignoreCache = false, MapLayout * fromLayout) {
return pixmap;
}
QPixmap Map::renderBorder() {
QPixmap Map::renderBorder(bool ignoreCache) {
bool changed_any = false, border_resized = false;
int width_ = getBorderWidth();
int height_ = getBorderHeight();
@ -238,7 +239,7 @@ QPixmap Map::renderBorder() {
}
QPainter painter(&layout->border_image);
for (int i = 0; i < layout->border->blocks->length(); i++) {
if (!border_resized && !borderBlockChanged(i, layout->cached_border)) {
if (!ignoreCache && (!border_resized && !borderBlockChanged(i, layout->cached_border))) {
continue;
}
@ -363,10 +364,14 @@ Block* Map::getBlock(int x, int y) {
return nullptr;
}
void Map::_setBlock(int x, int y, Block block) {
void Map::setBlock(int x, int y, Block block, bool enableScriptCallback) {
int i = y * getWidth() + x;
if (layout->blockdata && layout->blockdata->blocks) {
if (layout->blockdata && layout->blockdata->blocks && i < layout->blockdata->blocks->size()) {
Block prevBlock = layout->blockdata->blocks->value(i);
layout->blockdata->blocks->replace(i, block);
if (enableScriptCallback) {
Scripting::cb_MetatileChanged(x, y, prevBlock, block);
}
}
}
@ -390,7 +395,7 @@ void Map::_floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_
block->collision = collision;
block->elevation = elevation;
_setBlock(x, y, *block);
setBlock(x, y, *block, true);
if ((block = getBlock(x + 1, y)) && block->collision == old_coll && block->elevation == old_elev) {
todo.append(QPoint(x + 1, y));
}
@ -495,14 +500,6 @@ void Map::commit() {
}
}
void Map::setBlock(int x, int y, Block block) {
Block *old_block = getBlock(x, y);
if (old_block && (*old_block) != block) {
_setBlock(x, y, block);
commit();
}
}
void Map::floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation) {
Block *block = getBlock(x, y);
if (block && (block->collision != collision || block->elevation != elevation)) {
@ -523,7 +520,7 @@ void Map::magicFillCollisionElevation(int initialX, int initialY, uint16_t colli
if (block && block->collision == old_coll && block->elevation == old_elev) {
block->collision = collision;
block->elevation = elevation;
_setBlock(x, y, *block);
setBlock(x, y, *block, true);
}
}
}

View file

@ -46,6 +46,14 @@ Tileset* Tileset::copy() {
}
copy->palettes->append(copyPalette);
}
copy->palettePreviews = new QList<QList<QRgb>>;
for (QList<QRgb> palette : *this->palettePreviews) {
QList<QRgb> copyPalette;
for (QRgb color : palette) {
copyPalette.append(color);
}
copy->palettePreviews->append(copyPalette);
}
return copy;
}
@ -80,24 +88,27 @@ bool Tileset::metatileIsValid(uint16_t metatileId, Tileset *primaryTileset, Tile
return true;
}
QList<QList<QRgb>> Tileset::getBlockPalettes(Tileset *primaryTileset, Tileset *secondaryTileset) {
QList<QList<QRgb>> Tileset::getBlockPalettes(Tileset *primaryTileset, Tileset *secondaryTileset, bool useTruePalettes) {
QList<QList<QRgb>> palettes;
auto primaryPalettes = useTruePalettes ? primaryTileset->palettes : primaryTileset->palettePreviews;
for (int i = 0; i < Project::getNumPalettesPrimary(); i++) {
palettes.append(primaryTileset->palettes->at(i));
palettes.append(primaryPalettes->at(i));
}
auto secondaryPalettes = useTruePalettes ? secondaryTileset->palettes : secondaryTileset->palettePreviews;
for (int i = Project::getNumPalettesPrimary(); i < Project::getNumPalettesTotal(); i++) {
palettes.append(secondaryTileset->palettes->at(i));
palettes.append(secondaryPalettes->at(i));
}
return palettes;
}
QList<QRgb> Tileset::getPalette(int paletteId, Tileset *primaryTileset, Tileset *secondaryTileset) {
QList<QRgb> Tileset::getPalette(int paletteId, Tileset *primaryTileset, Tileset *secondaryTileset, bool useTruePalettes) {
QList<QRgb> paletteTable;
Tileset *tileset = paletteId < Project::getNumPalettesPrimary()
? primaryTileset
: secondaryTileset;
for (int i = 0; i < tileset->palettes->at(paletteId).length(); i++) {
paletteTable.append(tileset->palettes->at(paletteId).at(i));
auto palettes = useTruePalettes ? tileset->palettes : tileset->palettePreviews;
for (int i = 0; i < palettes->at(paletteId).length(); i++) {
paletteTable.append(palettes->at(paletteId).at(i));
}
return paletteTable;
}

View file

@ -1444,6 +1444,29 @@ void Editor::displayMapBorder() {
}
}
void Editor::updateMapBorder() {
QPixmap pixmap = this->map->renderBorder(true);
for (auto item : this->borderItems) {
item->setPixmap(pixmap);
}
}
void Editor::updateMapConnections() {
if (connection_items.size() != connection_edit_items.size())
return;
for (int i = 0; i < connection_items.size(); i++) {
Map *connected_map = project->getMap(connection_edit_items[i]->connection->map_name);
if (!connected_map)
continue;
QPixmap pixmap = connected_map->renderConnection(*(connection_edit_items[i]->connection), map->layout);
connection_items[i]->setPixmap(pixmap);
connection_edit_items[i]->basePixmap = pixmap;
connection_edit_items[i]->setPixmap(pixmap);
}
}
int Editor::getBorderDrawDistance(int dimension) {
// Draw sufficient border blocks to fill the player's view (BORDER_DISTANCE)
if (dimension >= BORDER_DISTANCE) {

View file

@ -8,6 +8,8 @@
#include "ui_eventpropertiesframe.h"
#include "bordermetatilespixmapitem.h"
#include "currentselectedmetatilespixmapitem.h"
#include "customattributestable.h"
#include "scripting.h"
#include "adjustingstackedwidget.h"
#include <QFileDialog>
@ -346,6 +348,14 @@ bool MainWindow::openProject(QString dir) {
}
if (success) {
for (auto action : this->registeredActions) {
this->ui->menuTools->removeAction(action);
}
Scripting::init(this);
Scripting::cb_ProjectOpened(dir);
}
return success;
}
@ -389,6 +399,7 @@ void MainWindow::on_action_Open_Project_triggered()
}
QString dir = getExistingDirectory(recent);
if (!dir.isEmpty()) {
Scripting::cb_ProjectClosed(this->editor->project->root);
porymapConfig.setRecentProject(dir);
if (!openProject(dir)) {
this->initWindow();
@ -444,6 +455,8 @@ bool MainWindow::setMap(QString map_name, bool scrollTreeView) {
setRecentMap(map_name);
updateMapList();
updateTilesetEditor();
Scripting::cb_MapOpened(map_name);
return true;
}
@ -1052,6 +1065,7 @@ void MainWindow::on_actionNew_Tileset_triggered() {
newSet->metatiles->append(mt);
}
newSet->palettes = new QList<QList<QRgb>>();
newSet->palettePreviews = new QList<QList<QRgb>>();
newSet->palettePaths = *new QList<QString>();
for(int i = 0; i < 16; ++i) {
QList<QRgb> *currentPal = new QList<QRgb>();
@ -1059,17 +1073,19 @@ void MainWindow::on_actionNew_Tileset_triggered() {
currentPal->append(qRgb(0,0,0));
}
newSet->palettes->append(*currentPal);
newSet->palettePreviews->append(*currentPal);
QString fileName;
fileName.sprintf("%02d.pal", i);
newSet->palettePaths.append(fullDirectoryPath+"/palettes/" + fileName);
}
(*newSet->palettes)[0][1] = qRgb(255,0,255);
(*newSet->palettePreviews)[0][1] = qRgb(255,0,255);
newSet->is_compressed = "TRUE";
newSet->padding = "0";
editor->project->saveTilesetTilesImage(newSet);
editor->project->saveTilesetMetatiles(newSet);
editor->project->saveTilesetMetatileAttributes(newSet);
editor->project->saveTilesetPalettes(newSet, !createTilesetDialog->isSecondary);
editor->project->saveTilesetPalettes(newSet);
//append to tileset specific files
@ -2303,7 +2319,7 @@ void MainWindow::on_pushButton_ChangeDimensions_clicked()
int realWidth = widthSpinBox->value() + 15;
int realHeight = heightSpinBox->value() + 14;
int numMetatiles = realWidth * realHeight;
if (numMetatiles <= 0x2800) {
if (MainWindow::mapDimensionsValid(widthSpinBox->value(), heightSpinBox->value())) {
dialog.accept();
} else {
QString errorText = QString("Error: The specified width and height are too large.\n"
@ -2328,6 +2344,17 @@ void MainWindow::on_pushButton_ChangeDimensions_clicked()
}
}
bool MainWindow::mapDimensionsValid(int width, int height) {
// Ensure width and height are an acceptable size.
// The maximum number of metatiles in a map is the following:
// max = (width + 15) * (height + 14)
// This limit can be found in fieldmap.c in pokeruby/pokeemerald.
int realWidth = width + 15;
int realHeight = height + 14;
int numMetatiles = realWidth * realHeight;
return numMetatiles <= 0x2800;
}
void MainWindow::on_checkBox_smartPaths_stateChanged(int selected)
{
bool enabled = selected == Qt::Checked;

View file

@ -0,0 +1,509 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "scripting.h"
QJSValue MainWindow::getBlock(int x, int y) {
if (!this->editor || !this->editor->map)
return QJSValue();
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return Scripting::fromBlock(Block());
}
return Scripting::fromBlock(*block);
}
void MainWindow::tryRedrawMapArea(bool forceRedraw) {
if (forceRedraw) {
this->editor->map_item->draw();
this->editor->collision_item->draw();
}
}
void MainWindow::tryCommitMapChanges(bool commitChanges) {
if (commitChanges) {
this->editor->map->commit();
}
}
void MainWindow::setBlock(int x, int y, int tile, int collision, int elevation, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
this->editor->map->setBlock(x, y, Block(tile, collision, elevation));
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::setBlocksFromSelection(int x, int y, bool forceRedraw, bool commitChanges) {
if (this->editor && this->editor->map_item) {
this->editor->map_item->paintNormal(x, y, true);
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
}
int MainWindow::getMetatileId(int x, int y) {
if (!this->editor || !this->editor->map)
return 0;
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return 0;
}
return block->tile;
}
void MainWindow::setMetatileId(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return;
}
this->editor->map->setBlock(x, y, Block(metatileId, block->collision, block->elevation));
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
int MainWindow::getCollision(int x, int y) {
if (!this->editor || !this->editor->map)
return 0;
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return 0;
}
return block->collision;
}
void MainWindow::setCollision(int x, int y, int collision, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return;
}
this->editor->map->setBlock(x, y, Block(block->tile, collision, block->elevation));
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
int MainWindow::getElevation(int x, int y) {
if (!this->editor || !this->editor->map)
return 0;
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return 0;
}
return block->elevation;
}
void MainWindow::setElevation(int x, int y, int elevation, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
Block *block = this->editor->map->getBlock(x, y);
if (!block) {
return;
}
this->editor->map->setBlock(x, y, Block(block->tile, block->collision, elevation));
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::bucketFill(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->floodFill(x, y, metatileId, true);
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::bucketFillFromSelection(int x, int y, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->floodFill(x, y, true);
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::magicFill(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->magicFill(x, y, metatileId, true);
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::magicFillFromSelection(int x, int y, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->magicFill(x, y, true);
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::shift(int xDelta, int yDelta, bool forceRedraw, bool commitChanges) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->shift(xDelta, yDelta);
this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw);
}
void MainWindow::redraw() {
this->tryRedrawMapArea(true);
}
void MainWindow::commit() {
this->tryCommitMapChanges(true);
}
QJSValue MainWindow::getDimensions() {
if (!this->editor || !this->editor->map)
return QJSValue();
return Scripting::dimensions(this->editor->map->getWidth(), this->editor->map->getHeight());
}
int MainWindow::getWidth() {
if (!this->editor || !this->editor->map)
return 0;
return this->editor->map->getWidth();
}
int MainWindow::getHeight() {
if (!this->editor || !this->editor->map)
return 0;
return this->editor->map->getHeight();
}
void MainWindow::setDimensions(int width, int height) {
if (!this->editor || !this->editor->map)
return;
if (!MainWindow::mapDimensionsValid(width, height))
return;
this->editor->map->setDimensions(width, height);
this->editor->map->commit();
this->onMapNeedsRedrawing();
}
void MainWindow::setWidth(int width) {
if (!this->editor || !this->editor->map)
return;
if (!MainWindow::mapDimensionsValid(width, this->editor->map->getHeight()))
return;
this->editor->map->setDimensions(width, this->editor->map->getHeight());
this->editor->map->commit();
this->onMapNeedsRedrawing();
}
void MainWindow::setHeight(int height) {
if (!this->editor || !this->editor->map)
return;
if (!MainWindow::mapDimensionsValid(this->editor->map->getWidth(), height))
return;
this->editor->map->setDimensions(this->editor->map->getWidth(), height);
this->editor->map->commit();
this->onMapNeedsRedrawing();
}
void MainWindow::clearOverlay() {
if (!this->ui || !this->ui->graphicsView_Map)
return;
this->ui->graphicsView_Map->overlay.clearItems();
this->ui->graphicsView_Map->scene()->update();
}
void MainWindow::addText(QString text, int x, int y, QString color, int fontSize) {
if (!this->ui || !this->ui->graphicsView_Map)
return;
this->ui->graphicsView_Map->overlay.addText(text, x, y, color, fontSize);
this->ui->graphicsView_Map->scene()->update();
}
void MainWindow::addRect(int x, int y, int width, int height, QString color) {
if (!this->ui || !this->ui->graphicsView_Map)
return;
this->ui->graphicsView_Map->overlay.addRect(x, y, width, height, color, false);
this->ui->graphicsView_Map->scene()->update();
}
void MainWindow::addFilledRect(int x, int y, int width, int height, QString color) {
if (!this->ui || !this->ui->graphicsView_Map)
return;
this->ui->graphicsView_Map->overlay.addRect(x, y, width, height, color, true);
this->ui->graphicsView_Map->scene()->update();
}
void MainWindow::addImage(int x, int y, QString filepath) {
if (!this->ui || !this->ui->graphicsView_Map)
return;
this->ui->graphicsView_Map->overlay.addImage(x, y, filepath);
this->ui->graphicsView_Map->scene()->update();
}
void MainWindow::refreshAfterPaletteChange(Tileset *tileset) {
if (this->tilesetEditor) {
this->tilesetEditor->setTilesets(this->editor->map->layout->tileset_primary_label, this->editor->map->layout->tileset_secondary_label);
}
this->editor->metatile_selector_item->draw();
this->editor->selected_border_metatiles_item->draw();
this->editor->map_item->draw(true);
this->editor->updateMapBorder();
this->editor->updateMapConnections();
this->editor->project->saveTilesetPalettes(tileset);
}
void MainWindow::setTilesetPalette(Tileset *tileset, int paletteIndex, QList<QList<int>> colors) {
if (!this->editor || !this->editor->map || !this->editor->map->layout)
return;
if (paletteIndex >= tileset->palettes->size())
return;
if (colors.size() != 16)
return;
for (int i = 0; i < 16; i++) {
if (colors[i].size() != 3)
continue;
(*tileset->palettes)[paletteIndex][i] = qRgb(colors[i][0], colors[i][1], colors[i][2]);
(*tileset->palettePreviews)[paletteIndex][i] = qRgb(colors[i][0], colors[i][1], colors[i][2]);
}
}
void MainWindow::setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
this->setTilesetPalette(this->editor->map->layout->tileset_primary, paletteIndex, colors);
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary);
}
void MainWindow::setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalette(this->editor->map->layout->tileset_primary, i, palettes[i]);
}
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary);
}
void MainWindow::setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
this->setTilesetPalette(this->editor->map->layout->tileset_secondary, paletteIndex, colors);
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary);
}
void MainWindow::setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalette(this->editor->map->layout->tileset_secondary, i, palettes[i]);
}
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary);
}
QJSValue MainWindow::getTilesetPalette(QList<QList<QRgb>> *palettes, int paletteIndex) {
if (paletteIndex >= palettes->size())
return QJSValue();
QList<QList<int>> palette;
for (auto color : palettes->value(paletteIndex)) {
palette.append(QList<int>({qRed(color), qGreen(color), qBlue(color)}));
}
return Scripting::getEngine()->toScriptValue(palette);
}
QJSValue MainWindow::getTilesetPalettes(QList<QList<QRgb>> *palettes) {
QList<QList<QList<int>>> outPalettes;
for (int i = 0; i < palettes->size(); i++) {
QList<QList<int>> colors;
for (auto color : palettes->value(i)) {
colors.append(QList<int>({qRed(color), qGreen(color), qBlue(color)}));
}
outPalettes.append(colors);
}
return Scripting::getEngine()->toScriptValue(outPalettes);
}
QJSValue MainWindow::getPrimaryTilesetPalette(int paletteIndex) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return QJSValue();
return this->getTilesetPalette(this->editor->map->layout->tileset_primary->palettes, paletteIndex);
}
QJSValue MainWindow::getPrimaryTilesetPalettes() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return QJSValue();
return this->getTilesetPalettes(this->editor->map->layout->tileset_primary->palettes);
}
QJSValue MainWindow::getSecondaryTilesetPalette(int paletteIndex) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return QJSValue();
return this->getTilesetPalette(this->editor->map->layout->tileset_secondary->palettes, paletteIndex);
}
QJSValue MainWindow::getSecondaryTilesetPalettes() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return QJSValue();
return this->getTilesetPalettes(this->editor->map->layout->tileset_secondary->palettes);
}
void MainWindow::refreshAfterPalettePreviewChange() {
this->editor->metatile_selector_item->draw();
this->editor->selected_border_metatiles_item->draw();
this->editor->map_item->draw(true);
this->editor->updateMapBorder();
this->editor->updateMapConnections();
}
void MainWindow::setTilesetPalettePreview(Tileset *tileset, int paletteIndex, QList<QList<int>> colors) {
if (!this->editor || !this->editor->map || !this->editor->map->layout)
return;
if (paletteIndex >= tileset->palettePreviews->size())
return;
if (colors.size() != 16)
return;
for (int i = 0; i < 16; i++) {
if (colors[i].size() != 3)
continue;
auto palettes = tileset->palettePreviews;
(*palettes)[paletteIndex][i] = qRgb(colors[i][0], colors[i][1], colors[i][2]);
}
}
void MainWindow::setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, paletteIndex, colors);
this->refreshAfterPalettePreviewChange();
}
void MainWindow::setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, i, palettes[i]);
}
this->refreshAfterPalettePreviewChange();
}
void MainWindow::setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, paletteIndex, colors);
this->refreshAfterPalettePreviewChange();
}
void MainWindow::setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, i, palettes[i]);
}
this->refreshAfterPalettePreviewChange();
}
QJSValue MainWindow::getPrimaryTilesetPalettePreview(int paletteIndex) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return QJSValue();
return this->getTilesetPalette(this->editor->map->layout->tileset_primary->palettePreviews, paletteIndex);
}
QJSValue MainWindow::getPrimaryTilesetPalettesPreview() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return QJSValue();
return this->getTilesetPalettes(this->editor->map->layout->tileset_primary->palettePreviews);
}
QJSValue MainWindow::getSecondaryTilesetPalettePreview(int paletteIndex) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return QJSValue();
return this->getTilesetPalette(this->editor->map->layout->tileset_secondary->palettePreviews, paletteIndex);
}
QJSValue MainWindow::getSecondaryTilesetPalettesPreview() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return QJSValue();
return this->getTilesetPalettes(this->editor->map->layout->tileset_secondary->palettePreviews);
}
QString MainWindow::getPrimaryTileset() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return QString();
return this->editor->map->layout->tileset_primary->name;
}
QString MainWindow::getSecondaryTileset() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return QString();
return this->editor->map->layout->tileset_secondary->name;
}
void MainWindow::setPrimaryTileset(QString tileset) {
this->on_comboBox_PrimaryTileset_currentTextChanged(tileset);
}
void MainWindow::setSecondaryTileset(QString tileset) {
this->on_comboBox_SecondaryTileset_currentTextChanged(tileset);
}
void MainWindow::setGridVisibility(bool visible) {
this->ui->checkBox_ToggleGrid->setChecked(visible);
}
bool MainWindow::getGridVisibility() {
return this->ui->checkBox_ToggleGrid->isChecked();
}
void MainWindow::setBorderVisibility(bool visible) {
this->editor->toggleBorderVisibility(visible);
}
bool MainWindow::getBorderVisibility() {
return this->ui->checkBox_ToggleBorder->isChecked();
}
void MainWindow::setSmartPathsEnabled(bool visible) {
this->ui->checkBox_smartPaths->setChecked(visible);
}
bool MainWindow::getSmartPathsEnabled() {
return this->ui->checkBox_smartPaths->isChecked();
}
void MainWindow::registerAction(QString functionName, QString actionName, QString shortcut) {
if (!this->ui || !this->ui->menuTools)
return;
Scripting::registerAction(functionName, actionName);
if (Scripting::numRegisteredActions() == 1) {
QAction *section = this->ui->menuTools->addSection("Custom Actions");
this->registeredActions.append(section);
}
QAction *action = this->ui->menuTools->addAction(actionName, [actionName](){
Scripting::invokeAction(actionName);
});
if (!shortcut.isEmpty()) {
action->setShortcut(QKeySequence(shortcut));
}
this->registeredActions.append(action);
}
void MainWindow::setTimeout(QJSValue callback, int milliseconds) {
if (!callback.isCallable() || milliseconds < 0)
return;
QTimer *timer = new QTimer(0);
connect(timer, &QTimer::timeout, [=](){
this->invokeCallback(callback);
});
connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));
timer->setSingleShot(true);
timer->start(milliseconds);
}
void MainWindow::invokeCallback(QJSValue callback) {
callback.call();
}
void MainWindow::log(QString message) {
logInfo(message);
}

View file

@ -1013,8 +1013,8 @@ void Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
saveTilesetMetatiles(secondaryTileset);
saveTilesetTilesImage(primaryTileset);
saveTilesetTilesImage(secondaryTileset);
saveTilesetPalettes(primaryTileset, true);
saveTilesetPalettes(secondaryTileset, false);
saveTilesetPalettes(primaryTileset);
saveTilesetPalettes(secondaryTileset);
}
void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *secondaryTileset) {
@ -1151,7 +1151,7 @@ void Project::saveTilesetTilesImage(Tileset *tileset) {
exportIndexed4BPPPng(tileset->tilesImage, tileset->tilesImagePath);
}
void Project::saveTilesetPalettes(Tileset *tileset, bool /*primary*/) {
void Project::saveTilesetPalettes(Tileset *tileset) {
PaletteUtil paletteParser;
for (int i = 0; i < Project::getNumPalettesTotal(); i++) {
QString filepath = tileset->palettePaths.at(i);
@ -1586,6 +1586,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
// palettes
QList<QList<QRgb>> *palettes = new QList<QList<QRgb>>;
QList<QList<QRgb>> *palettePreviews = new QList<QList<QRgb>>;
for (int i = 0; i < tileset->palettePaths.length(); i++) {
QList<QRgb> palette;
QString path = tileset->palettePaths.value(i);
@ -1620,8 +1621,10 @@ void Project::loadTilesetAssets(Tileset* tileset) {
}
palettes->append(palette);
palettePreviews->append(palette);
}
tileset->palettes = palettes;
tileset->palettePreviews = palettePreviews;
}
void Project::loadTilesetTiles(Tileset *tileset, QImage image) {

156
src/scripting.cpp Normal file
View file

@ -0,0 +1,156 @@
#include "scripting.h"
#include "log.h"
QMap<CallbackType, QString> callbackFunctions = {
{OnProjectOpened, "onProjectOpened"},
{OnProjectClosed, "onProjectClosed"},
{OnBlockChanged, "onBlockChanged"},
{OnMapOpened, "onMapOpened"},
};
Scripting *instance = nullptr;
void Scripting::init(MainWindow *mainWindow) {
if (instance) {
instance->engine->setInterrupted(true);
delete instance;
}
instance = new Scripting(mainWindow);
}
Scripting::Scripting(MainWindow *mainWindow) {
this->engine = new QJSEngine(mainWindow);
this->engine->installExtensions(QJSEngine::ConsoleExtension);
this->engine->globalObject().setProperty("map", this->engine->newQObject(mainWindow));
for (QString script : projectConfig.getCustomScripts()) {
this->filepaths.append(script);
}
this->loadModules(this->filepaths);
}
void Scripting::loadModules(QStringList moduleFiles) {
for (QString filepath : moduleFiles) {
QJSValue module = this->engine->importModule(filepath);
if (module.isError()) {
QString relativePath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath);
module = this->engine->importModule(relativePath);
if (module.isError()) {
logError(QString("Failed to load custom script file '%1'\nName: %2\nMessage: %3\nFile: %4\nLine Number: %5\nStack: %6")
.arg(filepath)
.arg(module.property("name").toString())
.arg(module.property("message").toString())
.arg(module.property("fileName").toString())
.arg(module.property("lineNumber").toString())
.arg(module.property("stack").toString()));
continue;
}
}
logInfo(QString("Successfully loaded custom script file '%1'").arg(filepath));
this->modules.append(module);
}
}
void Scripting::invokeCallback(CallbackType type, QJSValueList args) {
for (QJSValue module : this->modules) {
QString functionName = callbackFunctions[type];
QJSValue callbackFunction = module.property(functionName);
if (callbackFunction.isError()) {
continue;
}
QJSValue result = callbackFunction.call(args);
if (result.isError()) {
logError(QString("Module %1 encountered an error when calling '%2'").arg(module.toString()).arg(functionName));
continue;
}
}
}
void Scripting::registerAction(QString functionName, QString actionName) {
if (!instance) return;
instance->registeredActions.insert(actionName, functionName);
}
int Scripting::numRegisteredActions() {
if (!instance) return 0;
return instance->registeredActions.size();
}
void Scripting::invokeAction(QString actionName) {
if (!instance) return;
if (!instance->registeredActions.contains(actionName)) return;
QString functionName = instance->registeredActions.value(actionName);
for (QJSValue module : instance->modules) {
QJSValue callbackFunction = module.property(functionName);
if (callbackFunction.isError()) {
continue;
}
QJSValue result = callbackFunction.call(QJSValueList());
if (result.isError()) {
logError(QString("Module %1 encountered an error when calling '%2'").arg(module.toString()).arg(functionName));
continue;
}
}
}
void Scripting::cb_ProjectOpened(QString projectPath) {
if (!instance) return;
QJSValueList args {
projectPath,
};
instance->invokeCallback(OnProjectOpened, args);
}
void Scripting::cb_ProjectClosed(QString projectPath) {
if (!instance) return;
QJSValueList args {
projectPath,
};
instance->invokeCallback(OnProjectClosed, args);
}
void Scripting::cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock) {
if (!instance) return;
QJSValueList args {
x,
y,
instance->fromBlock(prevBlock),
instance->fromBlock(newBlock),
};
instance->invokeCallback(OnBlockChanged, args);
}
void Scripting::cb_MapOpened(QString mapName) {
if (!instance) return;
QJSValueList args {
mapName,
};
instance->invokeCallback(OnMapOpened, args);
}
QJSValue Scripting::fromBlock(Block block) {
QJSValue obj = instance->engine->newObject();
obj.setProperty("metatileId", block.tile);
obj.setProperty("collision", block.collision);
obj.setProperty("elevation", block.elevation);
obj.setProperty("rawValue", block.rawValue());
return obj;
}
QJSValue Scripting::dimensions(int width, int height) {
QJSValue obj = instance->engine->newObject();
obj.setProperty("width", width);
obj.setProperty("height", height);
return obj;
}
QJSEngine *Scripting::getEngine() {
return instance->engine;
}

View file

@ -39,7 +39,7 @@ void CollisionPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
if (block) {
block->collision = this->movementPermissionsSelector->getSelectedCollision();
block->elevation = this->movementPermissionsSelector->getSelectedElevation();
map->_setBlock(x, y, *block);
map->setBlock(x, y, *block, true);
}
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
map->commit();

View file

@ -15,3 +15,9 @@ void GraphicsView::mouseMoveEvent(QMouseEvent *event) {
void GraphicsView::mouseReleaseEvent(QMouseEvent *event) {
QGraphicsView::mouseReleaseEvent(event);
}
void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect) {
for (auto item : this->overlay.getItems()) {
item->render(painter);
}
}

View file

@ -13,7 +13,7 @@ QImage getCollisionMetatileImage(int collision, int elevation) {
return collisionImage.toImage();
}
QImage getMetatileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
QImage getMetatileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset, bool useTruePalettes) {
QImage metatile_image(16, 16, QImage::Format_RGBA8888);
Metatile* metatile = Tileset::getMetatile(tile, primaryTileset, secondaryTileset);
@ -27,7 +27,7 @@ QImage getMetatileImage(uint16_t tile, Tileset *primaryTileset, Tileset *seconda
metatile_image.fill(Qt::magenta);
return metatile_image;
}
QList<QList<QRgb>> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset);
QList<QList<QRgb>> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset, useTruePalettes);
QPainter metatile_painter(&metatile_image);
for (int layer = 0; layer < 2; layer++)
@ -95,8 +95,8 @@ QImage getColoredTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *seco
return tileImage;
}
QImage getPalettedTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId) {
QList<QRgb> palette = Tileset::getPalette(paletteId, primaryTileset, secondaryTileset);
QImage getPalettedTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId, bool useTruePalettes) {
QList<QRgb> palette = Tileset::getPalette(paletteId, primaryTileset, secondaryTileset, useTruePalettes);
return getColoredTileImage(tile, primaryTileset, secondaryTileset, palette);
}

View file

@ -42,24 +42,7 @@ void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) {
if (x != selection_origin.x() || y != selection_origin.y()) {
int xDelta = x - selection_origin.x();
int yDelta = y - selection_origin.y();
Blockdata *backupBlockdata = map->layout->blockdata->copy();
for (int i = 0; i < map->getWidth(); i++)
for (int j = 0; j < map->getHeight(); j++) {
int destX = i + xDelta;
int destY = j + yDelta;
if (destX < 0)
do { destX += map->getWidth(); } while (destX < 0);
if (destY < 0)
do { destY += map->getHeight(); } while (destY < 0);
destX %= map->getWidth();
destY %= map->getHeight();
int blockIndex = j * map->getWidth() + i;
Block srcBlock = backupBlockdata->blocks->at(blockIndex);
map->_setBlock(destX, destY, srcBlock);
}
delete backupBlockdata;
this->shift(xDelta, yDelta);
selection_origin = QPoint(x, y);
selection.clear();
draw();
@ -69,20 +52,43 @@ void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) {
}
}
void MapPixmapItem::paintNormal(int x, int y) {
void MapPixmapItem::shift(int xDelta, int yDelta) {
Blockdata *backupBlockdata = map->layout->blockdata->copy();
for (int i = 0; i < map->getWidth(); i++)
for (int j = 0; j < map->getHeight(); j++) {
int destX = i + xDelta;
int destY = j + yDelta;
if (destX < 0)
do { destX += map->getWidth(); } while (destX < 0);
if (destY < 0)
do { destY += map->getHeight(); } while (destY < 0);
destX %= map->getWidth();
destY %= map->getHeight();
int blockIndex = j * map->getWidth() + i;
Block srcBlock = backupBlockdata->blocks->at(blockIndex);
map->setBlock(destX, destY, srcBlock);
}
delete backupBlockdata;
}
void MapPixmapItem::paintNormal(int x, int y, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
int initialX = fromScriptCall ? x : this->paint_tile_initial_x;
int initialY = fromScriptCall ? y : this->paint_tile_initial_y;
// Snap the selected position to the top-left of the block boundary.
// This allows painting via dragging the mouse to tile the painted region.
int xDiff = x - this->paint_tile_initial_x;
int yDiff = y - this->paint_tile_initial_y;
int xDiff = x - initialX;
int yDiff = y - initialY;
if (xDiff < 0 && xDiff % selectionDimensions.x() != 0) xDiff -= selectionDimensions.x();
if (yDiff < 0 && yDiff % selectionDimensions.y() != 0) yDiff -= selectionDimensions.y();
x = this->paint_tile_initial_x + (xDiff / selectionDimensions.x()) * selectionDimensions.x();
y = this->paint_tile_initial_y + (yDiff / selectionDimensions.y()) * selectionDimensions.y();
x = initialX + (xDiff / selectionDimensions.x()) * selectionDimensions.x();
y = initialY + (yDiff / selectionDimensions.y()) * selectionDimensions.y();
for (int i = 0; i < selectionDimensions.x() && i + x < map->getWidth(); i++)
for (int j = 0; j < selectionDimensions.y() && j + y < map->getHeight(); j++) {
@ -96,7 +102,7 @@ void MapPixmapItem::paintNormal(int x, int y) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->_setBlock(actualX, actualY, *block);
map->setBlock(actualX, actualY, *block, !fromScriptCall);
}
}
}
@ -125,7 +131,7 @@ QList<int> MapPixmapItem::smartPathTable = QList<int>({
#define IS_SMART_PATH_TILE(block) (selectedMetatiles->contains(block->tile))
void MapPixmapItem::paintSmartPath(int x, int y) {
void MapPixmapItem::paintSmartPath(int x, int y, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
@ -159,7 +165,7 @@ void MapPixmapItem::paintSmartPath(int x, int y) {
block->collision = openTileCollision;
block->elevation = openTileElevation;
}
map->_setBlock(actualX, actualY, *block);
map->setBlock(actualX, actualY, *block, !fromScriptCall);
}
}
@ -203,7 +209,7 @@ void MapPixmapItem::paintSmartPath(int x, int y) {
block->collision = selectedCollisions->at(smartPathTable[id]).first;
block->elevation = selectedCollisions->at(smartPathTable[id]).second;
}
map->_setBlock(actualX, actualY, *block);
map->setBlock(actualX, actualY, *block, !fromScriptCall);
}
}
@ -269,9 +275,9 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
if (selectedMetatiles->count() > 1 || (block && block->tile != tile)) {
bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier;
if ((this->settings->smartPathsEnabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3)
this->_floodFillSmartPath(x, y);
this->floodFillSmartPath(x, y);
else
this->_floodFill(x, y);
this->floodFill(x, y);
}
}
@ -287,46 +293,80 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos();
int initialX = static_cast<int>(pos.x()) / 16;
int initialY = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(initialX, initialY);
if (block) {
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length();
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
uint16_t tile = block->tile;
for (int y = 0; y < map->getHeight(); y++) {
for (int x = 0; x < map->getWidth(); x++) {
block = map->getBlock(x, y);
if (block && block->tile == tile) {
int xDiff = x - initialX;
int yDiff = y - initialY;
int i = xDiff % selectionDimensions.x();
int j = yDiff % selectionDimensions.y();
if (i < 0) i = selectionDimensions.x() + i;
if (j < 0) j = selectionDimensions.y() + j;
int index = j * selectionDimensions.x() + i;
block->tile = selectedMetatiles->at(index);
if (setCollisions) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->_setBlock(x, y, *block);
}
}
}
}
this->magicFill(initialX, initialY);
}
draw();
}
}
void MapPixmapItem::_floodFill(int initialX, int initialY) {
void MapPixmapItem::magicFill(int x, int y, uint16_t metatileId, bool fromScriptCall) {
QPoint selectionDimensions(1, 1);
QList<uint16_t> *selectedMetatiles = new QList<uint16_t>({ metatileId });
this->magicFill(x, y, selectionDimensions, selectedMetatiles, nullptr, fromScriptCall);
}
void MapPixmapItem::magicFill(int x, int y, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
this->magicFill(x, y, selectionDimensions, selectedMetatiles, selectedCollisions, fromScriptCall);
}
void MapPixmapItem::magicFill(
int initialX,
int initialY,
QPoint selectionDimensions,
QList<uint16_t> *selectedMetatiles,
QList<QPair<uint16_t, uint16_t>> *selectedCollisions,
bool fromScriptCall) {
Block *block = map->getBlock(initialX, initialY);
if (block) {
bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length();
uint16_t tile = block->tile;
for (int y = 0; y < map->getHeight(); y++) {
for (int x = 0; x < map->getWidth(); x++) {
block = map->getBlock(x, y);
if (block && block->tile == tile) {
int xDiff = x - initialX;
int yDiff = y - initialY;
int i = xDiff % selectionDimensions.x();
int j = yDiff % selectionDimensions.y();
if (i < 0) i = selectionDimensions.x() + i;
if (j < 0) j = selectionDimensions.y() + j;
int index = j * selectionDimensions.x() + i;
block->tile = selectedMetatiles->at(index);
if (setCollisions) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->setBlock(x, y, *block, !fromScriptCall);
}
}
}
}
}
void MapPixmapItem::floodFill(int initialX, int initialY, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
this->floodFill(initialX, initialY, selectionDimensions, selectedMetatiles, selectedCollisions, fromScriptCall);
}
void MapPixmapItem::floodFill(int initialX, int initialY, uint16_t metatileId, bool fromScriptCall) {
QPoint selectionDimensions(1, 1);
QList<uint16_t> *selectedMetatiles = new QList<uint16_t>({ metatileId });
this->floodFill(initialX, initialY, selectionDimensions, selectedMetatiles, nullptr, fromScriptCall);
}
void MapPixmapItem::floodFill(
int initialX,
int initialY,
QPoint selectionDimensions,
QList<uint16_t> *selectedMetatiles,
QList<QPair<uint16_t, uint16_t>> *selectedCollisions,
bool fromScriptCall) {
bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length();
int numMetatiles = map->getWidth() * map->getHeight();
@ -362,7 +402,7 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->_setBlock(x, y, *block);
map->setBlock(x, y, *block, !fromScriptCall);
}
if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x + 1, y));
@ -385,7 +425,7 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
delete[] visited;
}
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
void MapPixmapItem::floodFillSmartPath(int initialX, int initialY, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
@ -427,7 +467,7 @@ void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
block->collision = openTileCollision;
block->elevation = openTileElevation;
}
map->_setBlock(x, y, *block);
map->setBlock(x, y, *block, !fromScriptCall);
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x + 1, y));
}
@ -482,7 +522,7 @@ void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
block->collision = selectedCollisions->at(smartPathTable[id]).first;
block->elevation = selectedCollisions->at(smartPathTable[id]).second;
}
map->_setBlock(x, y, *block);
map->setBlock(x, y, *block, !fromScriptCall);
// Visit neighbors if they are smart-path tiles, and don't revisit any.
if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && IS_SMART_PATH_TILE(block)) {

View file

@ -18,7 +18,7 @@ void MetatileLayersItem::draw() {
QPainter painter(&pixmap);
for (int i = 0; i < 8; i++) {
Tile tile = this->metatile->tiles->at(i);
QImage tileImage = getPalettedTileImage(tile.tile, this->primaryTileset, this->secondaryTileset, tile.palette)
QImage tileImage = getPalettedTileImage(tile.tile, this->primaryTileset, this->secondaryTileset, tile.palette, true)
.mirrored(tile.xflip, tile.yflip)
.scaled(16, 16);
painter.drawImage(tileCoords.at(i), tileImage);

45
src/ui/overlay.cpp Normal file
View file

@ -0,0 +1,45 @@
#include "overlay.h"
void OverlayText::render(QPainter *painter) {
QFont font = painter->font();
font.setPixelSize(this->fontSize);
painter->setFont(font);
painter->setPen(this->color);
painter->drawText(this->x, this->y, this->text);
}
void OverlayRect::render(QPainter *painter) {
if (this->filled) {
painter->fillRect(this->x, this->y, this->width, this->height, this->color);
} else {
painter->setPen(this->color);
painter->drawRect(this->x, this->y, this->width, this->height);
}
}
void OverlayImage::render(QPainter *painter) {
painter->drawImage(this->x, this->y, this->image);
}
void Overlay::clearItems() {
for (auto item : this->items) {
delete item;
}
this->items.clear();
}
QList<OverlayItem*> Overlay::getItems() {
return this->items;
}
void Overlay::addText(QString text, int x, int y, QString color, int fontSize) {
this->items.append(new OverlayText(text, x, y, QColor(color), fontSize));
}
void Overlay::addRect(int x, int y, int width, int height, QString color, bool filled) {
this->items.append(new OverlayRect(x, y, width, height, QColor(color), filled));
}
void Overlay::addImage(int x, int y, QString filepath) {
this->items.append(new OverlayImage(x, y, QImage(filepath)));
}

View file

@ -203,6 +203,7 @@ void PaletteEditor::setColor(int colorIndex) {
? this->primaryTileset
: this->secondaryTileset;
(*tileset->palettes)[paletteNum][colorIndex] = qRgb(red, green, blue);
(*tileset->palettePreviews)[paletteNum][colorIndex] = qRgb(red, green, blue);
this->refreshColor(colorIndex);
this->commitEditHistory(paletteNum);
emit this->changedPaletteColor();
@ -246,8 +247,10 @@ void PaletteEditor::setColorsFromHistory(PaletteHistoryItem *history, int palett
for (int i = 0; i < 16; i++) {
if (paletteId < Project::getNumPalettesPrimary()) {
(*this->primaryTileset->palettes)[paletteId][i] = history->colors.at(i);
(*this->primaryTileset->palettePreviews)[paletteId][i] = history->colors.at(i);
} else {
(*this->secondaryTileset->palettes)[paletteId][i] = history->colors.at(i);
(*this->secondaryTileset->palettePreviews)[paletteId][i] = history->colors.at(i);
}
}
@ -296,8 +299,10 @@ void PaletteEditor::on_actionImport_Palette_triggered()
for (int i = 0; i < 16; i++) {
if (paletteId < Project::getNumPalettesPrimary()) {
(*this->primaryTileset->palettes)[paletteId][i] = palette.at(i);
(*this->primaryTileset->palettePreviews)[paletteId][i] = palette.at(i);
} else {
(*this->secondaryTileset->palettes)[paletteId][i] = palette.at(i);
(*this->secondaryTileset->palettePreviews)[paletteId][i] = palette.at(i);
}
}

View file

@ -177,7 +177,7 @@ void TilesetEditor::drawSelectedTiles() {
int tileIndex = 0;
for (int j = 0; j < dimensions.y(); j++) {
for (int i = 0; i < dimensions.x(); i++) {
QImage tileImage = getPalettedTileImage(tiles.at(tileIndex).tile, this->primaryTileset, this->secondaryTileset, tiles.at(tileIndex).palette)
QImage tileImage = getPalettedTileImage(tiles.at(tileIndex).tile, this->primaryTileset, this->secondaryTileset, tiles.at(tileIndex).palette, true)
.mirrored(tiles.at(tileIndex).xflip, tiles.at(tileIndex).yflip)
.scaled(16, 16);
tileIndex++;

View file

@ -22,7 +22,7 @@ void TilesetEditorMetatileSelector::draw() {
if (i >= primaryLength) {
tile += Project::getNumMetatilesPrimary() - primaryLength;
}
QImage metatile_image = getMetatileImage(tile, this->primaryTileset, this->secondaryTileset).scaled(32, 32);
QImage metatile_image = getMetatileImage(tile, this->primaryTileset, this->secondaryTileset, true).scaled(32, 32);
int map_y = i / this->numMetatilesWide;
int map_x = i % this->numMetatilesWide;
QPoint metatile_origin = QPoint(map_x * 32, map_y * 32);

View file

@ -22,19 +22,19 @@ void TilesetEditorTileSelector::draw() {
int primaryLength = this->primaryTileset->tiles->length();
int secondaryLength = this->secondaryTileset->tiles->length();
int height = totalTiles / this->numTilesWide;
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset);
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset, true);
QImage image(this->numTilesWide * 16, height * 16, QImage::Format_RGBA8888);
QPainter painter(&image);
for (uint16_t tile = 0; tile < totalTiles; tile++) {
QImage tileImage;
if (tile < primaryLength) {
tileImage = getPalettedTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId).scaled(16, 16);
tileImage = getPalettedTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId, true).scaled(16, 16);
} else if (tile < Project::getNumTilesPrimary()) {
tileImage = QImage(16, 16, QImage::Format_RGBA8888);
tileImage.fill(palette.at(0));
} else if (tile < Project::getNumTilesPrimary() + secondaryLength) {
tileImage = getPalettedTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId).scaled(16, 16);
tileImage = getPalettedTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId, true).scaled(16, 16);
} else {
tileImage = QImage(16, 16, QImage::Format_RGBA8888);
QPainter painter(&tileImage);
@ -224,7 +224,7 @@ QImage TilesetEditorTileSelector::buildPrimaryTilesIndexedImage() {
// Image is first converted using greyscale so that palettes with duplicate colors
// are properly represented in the final image.
QImage indexedImage = image.convertToFormat(QImage::Format::Format_Indexed8, greyscalePalette.toVector());
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset);
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset, true);
indexedImage.setColorTable(palette.toVector());
return indexedImage;
}
@ -261,7 +261,7 @@ QImage TilesetEditorTileSelector::buildSecondaryTilesIndexedImage() {
// Image is first converted using greyscale so that palettes with duplicate colors
// are properly represented in the final image.
QImage indexedImage = image.convertToFormat(QImage::Format::Format_Indexed8, greyscalePalette.toVector());
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset);
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset, true);
indexedImage.setColorTable(palette.toVector());
return indexedImage;
}