diff --git a/docsrc/manual/scripting-capabilities.rst b/docsrc/manual/scripting-capabilities.rst index cee4b9a1..630634a3 100644 --- a/docsrc/manual/scripting-capabilities.rst +++ b/docsrc/manual/scripting-capabilities.rst @@ -118,6 +118,15 @@ Callbacks :param object prevBlock: the block's state before it was modified. The object's shape is ``{metatileId, collision, elevation, rawValue}`` :param object newBlock: the block's new state after it was modified. The object's shape is ``{metatileId, collision, elevation, rawValue}`` +.. js:function:: onBorderMetatileChanged(x, y, prevMetatileId, newMetatileId) + + Called when a border metatile is changed. + + :param number x: x coordinate of the block + :param number y: y coordinate of the block + :param number prevMetatileId: the metatile id of the border block before it was modified + :param number newMetatileId: the metatile id of the border block after it was modified + .. js:function:: onBlockHoverChanged(x, y) Called when the mouse enters a new map block. @@ -138,6 +147,15 @@ Callbacks :param number newWidth: the width of the map after the change :param number newHeight: the height of the map after the change +.. js:function:: onBorderResized(oldWidth, oldHeight, newWidth, newHeight) + + Called when the dimensions of the border are changed. + + :param number oldWidth: the width of the border before the change + :param number oldHeight: the height of the border before the change + :param number newWidth: the width of the border after the change + :param number newHeight: the height of the border after the change + .. js:function:: onMapShifted(xDelta, yDelta) Called when the map is updated by use of the Map Shift tool. @@ -165,6 +183,12 @@ Callbacks :param number oldTab: the index of the previously selected tab :param number newTab: the index of the newly selected tab +.. js:function:: onBorderVisibilityToggled(visible) + + Called when the visibility of the border and connecting maps is toggled on or off. + + :param boolean visible: whether the border is now visible + Functions ~~~~~~~~~ @@ -213,6 +237,24 @@ The following functions are related to editing the map's blocks or retrieving in :param boolean forceRedraw: Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``. :param boolean commitChanges: Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``. +.. js:function:: map.getBorderMetatileId(x, y) + + Gets the metatile id of a block in the border of the currently-opened map. + + :param number x: x coordinate of the block + :param number y: y coordinate of the block + :returns number: the metatile id of the block + +.. js:function:: map.setBorderMetatileId(x, y, metatileId, forceRedraw = true, commitChanges = true) + + Sets the metatile id of a block in the border of the currently-opened map. + + :param number x: x coordinate of the block + :param number y: y coordinate of the block + :param number metatileId: the metatile id of the block + :param boolean forceRedraw: Force the map view to refresh. Defaults to ``true``. Redrawing the map view is expensive, so set to ``false`` when making many consecutive map edits, and then redraw the map once using ``map.redraw()``. + :param boolean commitChanges: Commit the changes to the map's edit/undo history. Defaults to ``true``. When making many related map edits, it can be useful to set this to ``false``, and then commit all of them together with ``map.commit()``. + .. js:function:: map.getCollision(x, y) Gets the collision of a block in the currently-opened map. (``0`` = passable, ``1`` = impassable) @@ -323,6 +365,24 @@ The following functions are related to editing the map's blocks or retrieving in :returns number: the height of the map +.. js:function:: map.getBorderDimensions() + + Gets the dimensions of the border of the currently-opened map. + + :returns {width, height}: the dimensions of the border + +.. js:function:: map.getBorderWidth() + + Gets the width of the border of the currently-opened map. + + :returns number: the width of the border + +.. js:function:: map.getBorderHeight() + + Gets the height of the border of the currently-opened map. + + :returns number: the height of the border + .. js:function:: map.setDimensions(width, height) Sets the dimensions of the currently-opened map. @@ -342,6 +402,25 @@ The following functions are related to editing the map's blocks or retrieving in :param number height: height in blocks +.. js:function:: map.setBorderDimensions(width, height) + + Sets the dimensions of the border of the currently-opened map. If the config setting ``use_custom_border_size`` is set to ``0`` then this does nothing. + + :param number width: width in blocks + :param number height: height in blocks + +.. js:function:: map.setBorderWidth(width) + + Sets the width of the border of the currently-opened map. If the config setting ``use_custom_border_size`` is set to ``0`` then this does nothing. + + :param number width: width in blocks + +.. js:function:: map.setBorderHeight(height) + + Sets the height of the border of the currently-opened map. If the config setting ``use_custom_border_size`` is set to ``0`` then this does nothing. + + :param number height: height in blocks + .. js:function:: map.redraw() Redraws the entire map area. Useful when delaying map redraws using ``forceRedraw = false`` in certain map editing functions. diff --git a/include/core/editcommands.h b/include/core/editcommands.h index 142636cc..ea66b722 100644 --- a/include/core/editcommands.h +++ b/include/core/editcommands.h @@ -343,12 +343,14 @@ public: /// Implements a command to commit map edits from the scripting API. -/// The scripting api can edit metatiles and map dimensions. +/// The scripting api can edit map/border blocks and dimensions. class ScriptEditMap : public QUndoCommand { public: ScriptEditMap(Map *map, QSize oldMapDimensions, QSize newMapDimensions, const Blockdata &oldMetatiles, const Blockdata &newMetatiles, + QSize oldBorderDimensions, QSize newBorderDimensions, + const Blockdata &oldBorder, const Blockdata &newBorder, QUndoCommand *parent = nullptr); void undo() override; @@ -363,10 +365,18 @@ private: Blockdata newMetatiles; Blockdata oldMetatiles; + Blockdata newBorder; + Blockdata oldBorder; + int oldMapWidth; int oldMapHeight; int newMapWidth; int newMapHeight; + + int oldBorderWidth; + int oldBorderHeight; + int newBorderWidth; + int newBorderHeight; }; #endif // EDITCOMMANDS_H diff --git a/include/core/map.h b/include/core/map.h index 8122659c..2ea85eec 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -17,6 +17,10 @@ #define DEFAULT_BORDER_WIDTH 2 #define DEFAULT_BORDER_HEIGHT 2 +// Maximum based only on data type (u8) of map border width/height +#define MAX_BORDER_WIDTH 255 +#define MAX_BORDER_HEIGHT 255 + // Number of metatiles to draw out from edge of map. Could allow modification of this in the future. // porymap will reflect changes to it, but the value is hard-coded in the projects at the moment #define BORDER_DISTANCE 7 @@ -82,6 +86,9 @@ public: bool getBlock(int x, int y, Block *out); void setBlock(int x, int y, Block block, bool enableScriptCallback = false); void setBlockdata(Blockdata blockdata); + uint16_t getBorderMetatileId(int x, int y); + void setBorderMetatileId(int x, int y, uint16_t metatileId, bool enableScriptCallback = false); + void setBorderBlockData(Blockdata blockdata); 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); @@ -96,6 +103,7 @@ public: void cacheBorder(); bool hasUnsavedChanges(); bool isWithinBounds(int x, int y); + bool isWithinBorderBounds(int x, int y); // for memory management QVector ownedEvents; diff --git a/include/core/maplayout.h b/include/core/maplayout.h index 630bdeae..888e5372 100644 --- a/include/core/maplayout.h +++ b/include/core/maplayout.h @@ -33,8 +33,10 @@ public: Blockdata cached_border; struct { Blockdata blocks; - QSize dimensions; - } lastCommitMapBlocks; // to track map changes + QSize mapDimensions; + Blockdata border; + QSize borderDimensions; + } lastCommitBlocks; // to track map changes int getWidth(); int getHeight(); diff --git a/include/editor.h b/include/editor.h index c44fd960..03573ae1 100644 --- a/include/editor.h +++ b/include/editor.h @@ -88,7 +88,7 @@ public: void setSelectedConnectionFromMap(QString mapName); void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false); void updateSecondaryTileset(QString tilesetLabel, bool forceLoad = false); - void toggleBorderVisibility(bool visible); + void toggleBorderVisibility(bool visible, bool enableScriptCallback = true); void updateCustomMapHeaderValues(QTableWidget *); void configureEncounterJSON(QWidget *); Tileset *getCurrentMapPrimaryTileset(); @@ -158,6 +158,7 @@ public slots: void openScript(const QString &scriptLabel) const; void openProjectInTextEditor() const; void maskNonVisibleConnectionTiles(); + void onBorderMetatilesChanged(); private: void setConnectionItemsVisible(bool); @@ -192,7 +193,6 @@ private slots: void onConnectionItemSelected(ConnectionPixmapItem* connectionItem); void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem); void onConnectionDirectionChanged(QString newDirection); - void onBorderMetatilesChanged(); void onHoveredMovementPermissionChanged(uint16_t, uint16_t); void onHoveredMovementPermissionCleared(); void onHoveredMetatileSelectionChanged(uint16_t); diff --git a/include/mainwindow.h b/include/mainwindow.h index 851a3e07..55fb14e8 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -50,6 +50,8 @@ public: 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 getBorderMetatileId(int x, int y); + Q_INVOKABLE void setBorderMetatileId(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); @@ -64,9 +66,15 @@ public: Q_INVOKABLE QJSValue getDimensions(); Q_INVOKABLE int getWidth(); Q_INVOKABLE int getHeight(); + Q_INVOKABLE QJSValue getBorderDimensions(); + Q_INVOKABLE int getBorderWidth(); + Q_INVOKABLE int getBorderHeight(); Q_INVOKABLE void setDimensions(int width, int height); Q_INVOKABLE void setWidth(int width); Q_INVOKABLE void setHeight(int height); + Q_INVOKABLE void setBorderDimensions(int width, int height); + Q_INVOKABLE void setBorderWidth(int width); + Q_INVOKABLE void setBorderHeight(int height); Q_INVOKABLE void clearOverlay(int layer = 0); Q_INVOKABLE void clearOverlays(); Q_INVOKABLE void hideOverlay(int layer = 0); diff --git a/include/scripting.h b/include/scripting.h index b73e4049..91163f96 100644 --- a/include/scripting.h +++ b/include/scripting.h @@ -12,14 +12,17 @@ enum CallbackType { OnProjectOpened, OnProjectClosed, OnBlockChanged, + OnBorderMetatileChanged, OnBlockHoverChanged, OnBlockHoverCleared, OnMapOpened, OnMapResized, + OnBorderResized, OnMapShifted, OnTilesetUpdated, OnMainTabChanged, OnMapViewTabChanged, + OnBorderVisibilityToggled, }; class Scripting @@ -41,14 +44,17 @@ public: 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_BorderMetatileChanged(int x, int y, uint16_t prevMetatileId, uint16_t newMetatileId); static void cb_BlockHoverChanged(int x, int y); static void cb_BlockHoverCleared(); static void cb_MapOpened(QString mapName); static void cb_MapResized(int oldWidth, int oldHeight, int newWidth, int newHeight); + static void cb_BorderResized(int oldWidth, int oldHeight, int newWidth, int newHeight); static void cb_MapShifted(int xDelta, int yDelta); static void cb_TilesetUpdated(QString tilesetName); static void cb_MainTabChanged(int oldTab, int newTab); static void cb_MapViewTabChanged(int oldTab, int newTab); + static void cb_BorderVisibilityToggled(bool visible); static bool tryErrorJS(QJSValue js); private: diff --git a/src/core/editcommands.cpp b/src/core/editcommands.cpp index f755da6e..24e7b86c 100644 --- a/src/core/editcommands.cpp +++ b/src/core/editcommands.cpp @@ -49,7 +49,7 @@ void PaintMetatile::redo() { map->setBlockdata(newMetatiles); - map->layout->lastCommitMapBlocks.blocks = map->layout->blockdata; + map->layout->lastCommitBlocks.blocks = map->layout->blockdata; renderMapBlocks(map); } @@ -59,7 +59,7 @@ void PaintMetatile::undo() { map->setBlockdata(oldMetatiles); - map->layout->lastCommitMapBlocks.blocks = map->layout->blockdata; + map->layout->lastCommitBlocks.blocks = map->layout->blockdata; renderMapBlocks(map); @@ -101,7 +101,9 @@ void PaintBorder::redo() { if (!map) return; - map->layout->border = newBorder; + map->setBorderBlockData(newBorder); + + map->layout->lastCommitBlocks.border = map->layout->border; map->borderItem->draw(); } @@ -109,7 +111,9 @@ void PaintBorder::redo() { void PaintBorder::undo() { if (!map) return; - map->layout->border = oldBorder; + map->setBorderBlockData(oldBorder); + + map->layout->lastCommitBlocks.border = map->layout->border; map->borderItem->draw(); @@ -139,7 +143,7 @@ void ShiftMetatiles::redo() { map->setBlockdata(newMetatiles); - map->layout->lastCommitMapBlocks.blocks = map->layout->blockdata; + map->layout->lastCommitBlocks.blocks = map->layout->blockdata; renderMapBlocks(map, true); } @@ -149,7 +153,7 @@ void ShiftMetatiles::undo() { map->setBlockdata(oldMetatiles); - map->layout->lastCommitMapBlocks.blocks = map->layout->blockdata; + map->layout->lastCommitBlocks.blocks = map->layout->blockdata; renderMapBlocks(map, true); @@ -213,7 +217,8 @@ void ResizeMap::redo() { map->layout->border = newBorder; map->setBorderDimensions(newBorderWidth, newBorderHeight, false); - map->layout->lastCommitMapBlocks.dimensions = QSize(map->getWidth(), map->getHeight()); + map->layout->lastCommitBlocks.mapDimensions = QSize(map->getWidth(), map->getHeight()); + map->layout->lastCommitBlocks.borderDimensions = QSize(map->getBorderWidth(), map->getBorderHeight()); map->mapNeedsRedrawing(); } @@ -227,7 +232,8 @@ void ResizeMap::undo() { map->layout->border = oldBorder; map->setBorderDimensions(oldBorderWidth, oldBorderHeight, false); - map->layout->lastCommitMapBlocks.dimensions = QSize(map->getWidth(), map->getHeight()); + map->layout->lastCommitBlocks.mapDimensions = QSize(map->getWidth(), map->getHeight()); + map->layout->lastCommitBlocks.borderDimensions = QSize(map->getBorderWidth(), map->getBorderHeight()); map->mapNeedsRedrawing(); @@ -484,6 +490,8 @@ int EventPaste::id() const { ScriptEditMap::ScriptEditMap(Map *map, QSize oldMapDimensions, QSize newMapDimensions, const Blockdata &oldMetatiles, const Blockdata &newMetatiles, + QSize oldBorderDimensions, QSize newBorderDimensions, + const Blockdata &oldBorder, const Blockdata &newBorder, QUndoCommand *parent) : QUndoCommand(parent) { setText("Script Edit Map"); @@ -496,6 +504,14 @@ ScriptEditMap::ScriptEditMap(Map *map, this->oldMapHeight = oldMapDimensions.height(); this->newMapWidth = newMapDimensions.width(); this->newMapHeight = newMapDimensions.height(); + + this->oldBorder = oldBorder; + this->newBorder = newBorder; + + this->oldBorderWidth = oldBorderDimensions.width(); + this->oldBorderHeight = oldBorderDimensions.height(); + this->newBorderWidth = newBorderDimensions.width(); + this->newBorderHeight = newBorderDimensions.height(); } void ScriptEditMap::redo() { @@ -510,10 +526,19 @@ void ScriptEditMap::redo() { map->setBlockdata(newMetatiles); } - map->layout->lastCommitMapBlocks.blocks = newMetatiles; - map->layout->lastCommitMapBlocks.dimensions = QSize(newMapWidth, newMapHeight); + if (newBorderWidth != map->getBorderWidth() || newBorderHeight != map->getBorderHeight()) { + map->layout->border = newBorder; + map->setBorderDimensions(newBorderWidth, newBorderHeight, false); + } else { + map->setBorderBlockData(newBorder); + } - renderMapBlocks(map); + map->layout->lastCommitBlocks.blocks = newMetatiles; + map->layout->lastCommitBlocks.mapDimensions = QSize(newMapWidth, newMapHeight); + map->layout->lastCommitBlocks.border = newBorder; + map->layout->lastCommitBlocks.borderDimensions = QSize(newBorderWidth, newBorderHeight); + + map->mapNeedsRedrawing(); } void ScriptEditMap::undo() { @@ -526,10 +551,19 @@ void ScriptEditMap::undo() { map->setBlockdata(oldMetatiles); } - map->layout->lastCommitMapBlocks.blocks = oldMetatiles; - map->layout->lastCommitMapBlocks.dimensions = QSize(oldMapWidth, oldMapHeight); + if (oldBorderWidth != map->getBorderWidth() || oldBorderHeight != map->getBorderHeight()) { + map->layout->border = oldBorder; + map->setBorderDimensions(oldBorderWidth, oldBorderHeight, false); + } else { + map->setBorderBlockData(oldBorder); + } - renderMapBlocks(map); + map->layout->lastCommitBlocks.blocks = oldMetatiles; + map->layout->lastCommitBlocks.mapDimensions = QSize(oldMapWidth, oldMapHeight); + map->layout->lastCommitBlocks.border = oldBorder; + map->layout->lastCommitBlocks.borderDimensions = QSize(oldBorderWidth, oldBorderHeight); + + map->mapNeedsRedrawing(); QUndoCommand::undo(); } diff --git a/src/core/map.cpp b/src/core/map.cpp index baee10a3..95bd6def 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -328,9 +328,15 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata) setNewBorderDimensionsBlockdata(newWidth, newHeight); } + int oldWidth = layout->border_width.toInt(); + int oldHeight = layout->border_height.toInt(); layout->border_width = QString::number(newWidth); layout->border_height = QString::number(newHeight); + if (oldWidth != newWidth || oldHeight != newHeight) { + Scripting::cb_BorderResized(oldWidth, oldHeight, newWidth, newHeight); + } + emit mapChanged(this); } @@ -367,6 +373,35 @@ void Map::setBlockdata(Blockdata blockdata) { } } +uint16_t Map::getBorderMetatileId(int x, int y) { + int i = y * getBorderWidth() + x; + return layout->border[i].metatileId; +} + +void Map::setBorderMetatileId(int x, int y, uint16_t metatileId, bool enableScriptCallback) { + int i = y * getBorderWidth() + x; + if (i < layout->border.size()) { + uint16_t prevMetatileId = layout->border[i].metatileId; + layout->border[i].metatileId = metatileId; + if (prevMetatileId != metatileId && enableScriptCallback) { + Scripting::cb_BorderMetatileChanged(x, y, prevMetatileId, metatileId); + } + } +} + +void Map::setBorderBlockData(Blockdata blockdata) { + int width = getBorderWidth(); + int size = qMin(blockdata.size(), layout->border.size()); + for (int i = 0; i < size; i++) { + Block prevBlock = layout->border.at(i); + Block newBlock = blockdata.at(i); + if (prevBlock != newBlock) { + layout->border.replace(i, newBlock); + Scripting::cb_BorderMetatileChanged(i % width, i / width, prevBlock.metatileId, newBlock.metatileId); + } + } +} + void Map::_floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation) { QList todo; todo.append(QPoint(x, y)); @@ -474,3 +509,7 @@ bool Map::hasUnsavedChanges() { bool Map::isWithinBounds(int x, int y) { return (x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight()); } + +bool Map::isWithinBorderBounds(int x, int y) { + return (x >= 0 && x < this->getBorderWidth() && y >= 0 && y < this->getBorderHeight()); +} diff --git a/src/editor.cpp b/src/editor.cpp index f4890106..6b2c54cd 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1936,11 +1936,13 @@ void Editor::updateSecondaryTileset(QString tilesetLabel, bool forceLoad) } } -void Editor::toggleBorderVisibility(bool visible) +void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback) { this->setBorderItemsVisible(visible); this->setConnectionsVisibility(visible); porymapConfig.setShowBorder(visible); + if (enableScriptCallback) + Scripting::cb_BorderVisibilityToggled(visible); } void Editor::updateCustomMapHeaderValues(QTableWidget *table) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 79580bfd..ce8e55be 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2913,9 +2913,8 @@ void MainWindow::on_pushButton_ChangeDimensions_clicked() bheightSpinBox->setMinimum(1); widthSpinBox->setMaximum(editor->project->getMaxMapWidth()); heightSpinBox->setMaximum(editor->project->getMaxMapHeight()); - // Maximum based only on data type (u8) of map border width/height - bwidthSpinBox->setMaximum(255); - bheightSpinBox->setMaximum(255); + bwidthSpinBox->setMaximum(MAX_BORDER_WIDTH); + bheightSpinBox->setMaximum(MAX_BORDER_HEIGHT); widthSpinBox->setValue(editor->map->getWidth()); heightSpinBox->setValue(editor->map->getHeight()); bwidthSpinBox->setValue(editor->map->getBorderWidth()); diff --git a/src/mainwindow_scriptapi.cpp b/src/mainwindow_scriptapi.cpp index a2527cdd..c249236b 100644 --- a/src/mainwindow_scriptapi.cpp +++ b/src/mainwindow_scriptapi.cpp @@ -29,12 +29,15 @@ void MainWindow::tryRedrawMapArea(bool forceRedraw) { if (this->needsFullRedraw) { this->editor->map_item->draw(true); this->editor->collision_item->draw(true); + this->editor->selected_border_metatiles_item->draw(); this->editor->updateMapBorder(); this->editor->updateMapConnections(); this->needsFullRedraw = false; } else { this->editor->map_item->draw(); this->editor->collision_item->draw(); + this->editor->selected_border_metatiles_item->draw(); + this->editor->updateMapBorder(); } } @@ -43,8 +46,10 @@ void MainWindow::tryCommitMapChanges(bool commitChanges) { Map *map = this->editor->map; if (map) { map->editHistory.push(new ScriptEditMap(map, - map->layout->lastCommitMapBlocks.dimensions, QSize(map->getWidth(), map->getHeight()), - map->layout->lastCommitMapBlocks.blocks, map->layout->blockdata + map->layout->lastCommitBlocks.mapDimensions, QSize(map->getWidth(), map->getHeight()), + map->layout->lastCommitBlocks.blocks, map->layout->blockdata, + map->layout->lastCommitBlocks.borderDimensions, QSize(map->getBorderWidth(), map->getBorderHeight()), + map->layout->lastCommitBlocks.border, map->layout->border )); } } @@ -88,6 +93,24 @@ void MainWindow::setMetatileId(int x, int y, int metatileId, bool forceRedraw, b this->tryRedrawMapArea(forceRedraw); } +int MainWindow::getBorderMetatileId(int x, int y) { + if (!this->editor || !this->editor->map) + return 0; + if (!this->editor->map->isWithinBorderBounds(x, y)) + return 0; + return this->editor->map->getBorderMetatileId(x, y); +} + +void MainWindow::setBorderMetatileId(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) { + if (!this->editor || !this->editor->map) + return; + if (!this->editor->map->isWithinBorderBounds(x, y)) + return; + this->editor->map->setBorderMetatileId(x, y, metatileId); + this->tryCommitMapChanges(commitChanges); + this->tryRedrawMapArea(forceRedraw); +} + int MainWindow::getCollision(int x, int y) { if (!this->editor || !this->editor->map) return 0; @@ -198,6 +221,24 @@ int MainWindow::getHeight() { return this->editor->map->getHeight(); } +QJSValue MainWindow::getBorderDimensions() { + if (!this->editor || !this->editor->map) + return QJSValue(); + return Scripting::dimensions(this->editor->map->getBorderWidth(), this->editor->map->getBorderHeight()); +} + +int MainWindow::getBorderWidth() { + if (!this->editor || !this->editor->map) + return 0; + return this->editor->map->getBorderWidth(); +} + +int MainWindow::getBorderHeight() { + if (!this->editor || !this->editor->map) + return 0; + return this->editor->map->getBorderHeight(); +} + void MainWindow::setDimensions(int width, int height) { if (!this->editor || !this->editor->map) return; @@ -228,6 +269,36 @@ void MainWindow::setHeight(int height) { this->onMapNeedsRedrawing(); } +void MainWindow::setBorderDimensions(int width, int height) { + if (!this->editor || !this->editor->map || !projectConfig.getUseCustomBorderSize()) + return; + if (width < 1 || height < 1 || width > MAX_BORDER_WIDTH || height > MAX_BORDER_HEIGHT) + return; + this->editor->map->setBorderDimensions(width, height); + this->tryCommitMapChanges(true); + this->onMapNeedsRedrawing(); +} + +void MainWindow::setBorderWidth(int width) { + if (!this->editor || !this->editor->map || !projectConfig.getUseCustomBorderSize()) + return; + if (width < 1 || width > MAX_BORDER_WIDTH) + return; + this->editor->map->setBorderDimensions(width, this->editor->map->getBorderHeight()); + this->tryCommitMapChanges(true); + this->onMapNeedsRedrawing(); +} + +void MainWindow::setBorderHeight(int height) { + if (!this->editor || !this->editor->map || !projectConfig.getUseCustomBorderSize()) + return; + if (height < 1 || height > MAX_BORDER_HEIGHT) + return; + this->editor->map->setBorderDimensions(this->editor->map->getBorderWidth(), height); + this->tryCommitMapChanges(true); + this->onMapNeedsRedrawing(); +} + void MainWindow::clearOverlay(int layer) { if (!this->ui || !this->ui->graphicsView_Map) return; @@ -723,7 +794,7 @@ bool MainWindow::getGridVisibility() { } void MainWindow::setBorderVisibility(bool visible) { - this->editor->toggleBorderVisibility(visible); + this->editor->toggleBorderVisibility(visible, false); } bool MainWindow::getBorderVisibility() { diff --git a/src/project.cpp b/src/project.cpp index 3682d66b..01d32154 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1163,8 +1163,8 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) { bool Project::loadBlockdata(MapLayout *layout) { QString path = QString("%1/%2").arg(root).arg(layout->blockdata_path); layout->blockdata = readBlockdata(path); - layout->lastCommitMapBlocks.blocks = layout->blockdata; - layout->lastCommitMapBlocks.dimensions = QSize(layout->getWidth(), layout->getHeight()); + layout->lastCommitBlocks.blocks = layout->blockdata; + layout->lastCommitBlocks.mapDimensions = QSize(layout->getWidth(), layout->getHeight()); if (layout->blockdata.count() != layout->getWidth() * layout->getHeight()) { logWarn(QString("Layout blockdata length %1 does not match dimensions %2x%3 (should be %4). Resizing blockdata.") @@ -1182,13 +1182,16 @@ void Project::setNewMapBlockdata(Map *map) { for (int i = 0; i < map->getWidth() * map->getHeight(); i++) { map->layout->blockdata.append(qint16(0x3001)); } - map->layout->lastCommitMapBlocks.blocks = map->layout->blockdata; - map->layout->lastCommitMapBlocks.dimensions = QSize(map->getWidth(), map->getHeight()); + map->layout->lastCommitBlocks.blocks = map->layout->blockdata; + map->layout->lastCommitBlocks.mapDimensions = QSize(map->getWidth(), map->getHeight()); } bool Project::loadLayoutBorder(MapLayout *layout) { QString path = QString("%1/%2").arg(root).arg(layout->border_path); layout->border = readBlockdata(path); + layout->lastCommitBlocks.border = layout->border; + layout->lastCommitBlocks.borderDimensions = QSize(layout->getBorderWidth(), layout->getBorderHeight()); + int borderLength = layout->getBorderWidth() * layout->getBorderHeight(); if (layout->border.count() != borderLength) { logWarn(QString("Layout border blockdata length %1 must be %2. Resizing border blockdata.") @@ -1216,6 +1219,8 @@ void Project::setNewMapBorder(Map *map) { map->layout->border.append(qint16(0x01DC)); map->layout->border.append(qint16(0x01DD)); } + map->layout->lastCommitBlocks.border = map->layout->border; + map->layout->lastCommitBlocks.borderDimensions = QSize(map->getBorderWidth(), map->getBorderHeight()); } void Project::saveLayoutBorder(Map *map) { diff --git a/src/scripting.cpp b/src/scripting.cpp index a030ba84..3b16feac 100644 --- a/src/scripting.cpp +++ b/src/scripting.cpp @@ -5,14 +5,17 @@ QMap callbackFunctions = { {OnProjectOpened, "onProjectOpened"}, {OnProjectClosed, "onProjectClosed"}, {OnBlockChanged, "onBlockChanged"}, + {OnBorderMetatileChanged, "onBorderMetatileChanged"}, {OnBlockHoverChanged, "onBlockHoverChanged"}, {OnBlockHoverCleared, "onBlockHoverCleared"}, {OnMapOpened, "onMapOpened"}, {OnMapResized, "onMapResized"}, + {OnBorderResized, "onBorderResized"}, {OnMapShifted, "onMapShifted"}, {OnTilesetUpdated, "onTilesetUpdated"}, {OnMainTabChanged, "onMainTabChanged"}, {OnMapViewTabChanged, "onMapViewTabChanged"}, + {OnBorderVisibilityToggled, "onBorderVisibilityToggled"}, }; Scripting *instance = nullptr; @@ -140,6 +143,18 @@ void Scripting::cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock instance->invokeCallback(OnBlockChanged, args); } +void Scripting::cb_BorderMetatileChanged(int x, int y, uint16_t prevMetatileId, uint16_t newMetatileId) { + if (!instance) return; + + QJSValueList args { + x, + y, + prevMetatileId, + newMetatileId, + }; + instance->invokeCallback(OnBorderMetatileChanged, args); +} + void Scripting::cb_BlockHoverChanged(int x, int y) { if (!instance) return; @@ -176,6 +191,18 @@ void Scripting::cb_MapResized(int oldWidth, int oldHeight, int newWidth, int new instance->invokeCallback(OnMapResized, args); } +void Scripting::cb_BorderResized(int oldWidth, int oldHeight, int newWidth, int newHeight) { + if (!instance) return; + + QJSValueList args { + oldWidth, + oldHeight, + newWidth, + newHeight, + }; + instance->invokeCallback(OnBorderResized, args); +} + void Scripting::cb_MapShifted(int xDelta, int yDelta) { if (!instance) return; @@ -215,6 +242,15 @@ void Scripting::cb_MapViewTabChanged(int oldTab, int newTab) { instance->invokeCallback(OnMapViewTabChanged, args); } +void Scripting::cb_BorderVisibilityToggled(bool visible) { + if (!instance) return; + + QJSValueList args { + visible, + }; + instance->invokeCallback(OnBorderVisibilityToggled, args); +} + QJSValue Scripting::fromBlock(Block block) { QJSValue obj = instance->engine->newObject(); obj.setProperty("metatileId", block.metatileId); diff --git a/src/ui/bordermetatilespixmapitem.cpp b/src/ui/bordermetatilespixmapitem.cpp index 0f03e2aa..8f3bda9b 100644 --- a/src/ui/bordermetatilespixmapitem.cpp +++ b/src/ui/bordermetatilespixmapitem.cpp @@ -15,9 +15,8 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) for (int i = 0; i < selectionDimensions.x() && (i + pos.x()) < width; i++) { for (int j = 0; j < selectionDimensions.y() && (j + pos.y()) < height; j++) { - int blockIndex = (j + pos.y()) * width + (i + pos.x()); uint16_t metatileId = selectedMetatiles->at(j * selectionDimensions.x() + i); - map->layout->border[blockIndex].metatileId = metatileId; + map->setBorderMetatileId(pos.x() + i, pos.y() + j, metatileId, true); } } @@ -40,9 +39,8 @@ void BorderMetatilesPixmapItem::draw() { for (int j = 0; j < height; j++) { int x = i * 16; int y = j * 16; - int index = j * width + i; QImage metatile_image = getMetatileImage( - map->layout->border.value(index).metatileId, + map->getBorderMetatileId(i, j), map->layout->tileset_primary, map->layout->tileset_secondary, map->metatileLayerOrder,