Implement more map api functions

This commit is contained in:
Marcus Huderle 2020-04-30 18:30:24 -05:00
parent d685718f8d
commit 95012838fd
7 changed files with 295 additions and 66 deletions

View file

@ -41,6 +41,23 @@ public:
Q_INVOKABLE QJSValue getBlock(int x, int y); Q_INVOKABLE QJSValue getBlock(int x, int y);
Q_INVOKABLE void setBlock(int x, int y, int tile, int collision, int elevation); Q_INVOKABLE void setBlock(int x, int y, int tile, int collision, int elevation);
Q_INVOKABLE void setBlocksFromSelection(int x, int y); Q_INVOKABLE void setBlocksFromSelection(int x, int y);
Q_INVOKABLE int getMetatileId(int x, int y);
Q_INVOKABLE void setMetatileId(int x, int y, int metatileId);
Q_INVOKABLE int getCollision(int x, int y);
Q_INVOKABLE void setCollision(int x, int y, int collision);
Q_INVOKABLE int getElevation(int x, int y);
Q_INVOKABLE void setElevation(int x, int y, int elevation);
Q_INVOKABLE void bucketFill(int x, int y, int metatileId);
Q_INVOKABLE void bucketFillFromSelection(int x, int y);
Q_INVOKABLE void magicFill(int x, int y, int metatileId);
Q_INVOKABLE void magicFillFromSelection(int x, int y);
Q_INVOKABLE void shift(int xDelta, int yDelta);
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);
public slots: public slots:
void scaleMapView(int); void scaleMapView(int);
@ -210,6 +227,7 @@ private:
QString getDefaultMap(); QString getDefaultMap();
void setRecentMap(QString map_name); void setRecentMap(QString map_name);
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum); QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
static bool mapDimensionsValid(int width, int height);
void drawMapListIcons(QAbstractItemModel *model); void drawMapListIcons(QAbstractItemModel *model);
void updateMapList(); void updateMapList();

View file

@ -16,6 +16,7 @@ class Scripting
public: public:
Scripting(MainWindow *mainWindow); Scripting(MainWindow *mainWindow);
static QJSValue fromBlock(Block block); static QJSValue fromBlock(Block block);
static QJSValue dimensions(int width, int height);
static void init(MainWindow *mainWindow); static void init(MainWindow *mainWindow);
static void cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock); static void cb_MetatileChanged(int x, int y, Block prevBlock, Block newBlock);

View file

@ -38,14 +38,31 @@ public:
virtual void paint(QGraphicsSceneMouseEvent*); virtual void paint(QGraphicsSceneMouseEvent*);
virtual void floodFill(QGraphicsSceneMouseEvent*); virtual void floodFill(QGraphicsSceneMouseEvent*);
virtual void magicFill(QGraphicsSceneMouseEvent*); virtual void magicFill(QGraphicsSceneMouseEvent*);
void _floodFill(int x, int y); void magicFill(int x, int y, uint16_t metatileId, bool fromScriptCall = false);
void _floodFillSmartPath(int initialX, int initialY); 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);
virtual void pick(QGraphicsSceneMouseEvent*); virtual void pick(QGraphicsSceneMouseEvent*);
virtual void select(QGraphicsSceneMouseEvent*); virtual void select(QGraphicsSceneMouseEvent*);
virtual void shift(QGraphicsSceneMouseEvent*); virtual void shift(QGraphicsSceneMouseEvent*);
void shift(int xDelta, int yDelta);
virtual void draw(bool ignoreCache = false); virtual void draw(bool ignoreCache = false);
void updateMetatileSelection(QGraphicsSceneMouseEvent *event); void updateMetatileSelection(QGraphicsSceneMouseEvent *event);
void paintNormal(int x, int y, bool fromScriptCallback = false); void paintNormal(int x, int y, bool fromScriptCall = false);
private: private:
void paintSmartPath(int x, int y); void paintSmartPath(int x, int y);

View file

@ -2305,7 +2305,7 @@ void MainWindow::on_pushButton_ChangeDimensions_clicked()
int realWidth = widthSpinBox->value() + 15; int realWidth = widthSpinBox->value() + 15;
int realHeight = heightSpinBox->value() + 14; int realHeight = heightSpinBox->value() + 14;
int numMetatiles = realWidth * realHeight; int numMetatiles = realWidth * realHeight;
if (numMetatiles <= 0x2800) { if (MainWindow::mapDimensionsValid(widthSpinBox->value(), heightSpinBox->value())) {
dialog.accept(); dialog.accept();
} else { } else {
QString errorText = QString("Error: The specified width and height are too large.\n" QString errorText = QString("Error: The specified width and height are too large.\n"
@ -2330,6 +2330,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) void MainWindow::on_checkBox_smartPaths_stateChanged(int selected)
{ {
bool enabled = selected == Qt::Checked; bool enabled = selected == Qt::Checked;
@ -2566,3 +2577,140 @@ void MainWindow::setBlocksFromSelection(int x, int y) {
} }
} }
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) {
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));
}
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) {
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));
}
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) {
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));
}
void MainWindow::bucketFill(int x, int y, int metatileId) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->floodFill(x, y, metatileId, true);
}
void MainWindow::bucketFillFromSelection(int x, int y) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->floodFill(x, y, true);
}
void MainWindow::magicFill(int x, int y, int metatileId) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->magicFill(x, y, metatileId, true);
}
void MainWindow::magicFillFromSelection(int x, int y) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->magicFill(x, y, true);
}
void MainWindow::shift(int xDelta, int yDelta) {
if (!this->editor || !this->editor->map)
return;
this->editor->map_item->shift(xDelta, yDelta);
}
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();
}

View file

@ -73,3 +73,10 @@ QJSValue Scripting::fromBlock(Block block) {
obj.setProperty("rawValue", block.rawValue()); obj.setProperty("rawValue", block.rawValue());
return obj; return obj;
} }
QJSValue Scripting::dimensions(int width, int height) {
QJSValue obj = instance->engine->newObject();
obj.setProperty("width", width);
obj.setProperty("height", height);
return obj;
}

View file

@ -42,6 +42,17 @@ void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) {
if (x != selection_origin.x() || y != selection_origin.y()) { if (x != selection_origin.x() || y != selection_origin.y()) {
int xDelta = x - selection_origin.x(); int xDelta = x - selection_origin.x();
int yDelta = y - selection_origin.y(); int yDelta = y - selection_origin.y();
this->shift(xDelta, yDelta);
selection_origin = QPoint(x, y);
selection.clear();
draw();
}
}
}
}
}
void MapPixmapItem::shift(int xDelta, int yDelta) {
Blockdata *backupBlockdata = map->layout->blockdata->copy(); Blockdata *backupBlockdata = map->layout->blockdata->copy();
for (int i = 0; i < map->getWidth(); i++) for (int i = 0; i < map->getWidth(); i++)
for (int j = 0; j < map->getHeight(); j++) { for (int j = 0; j < map->getHeight(); j++) {
@ -60,21 +71,14 @@ void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) {
} }
delete backupBlockdata; delete backupBlockdata;
selection_origin = QPoint(x, y);
selection.clear();
draw();
}
}
}
}
} }
void MapPixmapItem::paintNormal(int x, int y, bool fromScriptCallback) { void MapPixmapItem::paintNormal(int x, int y, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions(); QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
int initialX = fromScriptCallback ? x : this->paint_tile_initial_x; int initialX = fromScriptCall ? x : this->paint_tile_initial_x;
int initialY = fromScriptCallback ? y : this->paint_tile_initial_y; int initialY = fromScriptCall ? y : this->paint_tile_initial_y;
// Snap the selected position to the top-left of the block boundary. // Snap the selected position to the top-left of the block boundary.
// This allows painting via dragging the mouse to tile the painted region. // This allows painting via dragging the mouse to tile the painted region.
@ -98,7 +102,7 @@ void MapPixmapItem::paintNormal(int x, int y, bool fromScriptCallback) {
block->collision = selectedCollisions->at(index).first; block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second; block->elevation = selectedCollisions->at(index).second;
} }
map->setBlock(actualX, actualY, *block, !fromScriptCallback); map->setBlock(actualX, actualY, *block, !fromScriptCall);
} }
} }
} }
@ -271,9 +275,9 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
if (selectedMetatiles->count() > 1 || (block && block->tile != tile)) { if (selectedMetatiles->count() > 1 || (block && block->tile != tile)) {
bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier; bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier;
if ((this->settings->smartPathsEnabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3) if ((this->settings->smartPathsEnabled || smartPathsEnabled) && selectionDimensions.x() == 3 && selectionDimensions.y() == 3)
this->_floodFillSmartPath(x, y); this->floodFillSmartPath(x, y);
else else
this->_floodFill(x, y); this->floodFill(x, y);
} }
} }
@ -289,15 +293,37 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
QPointF pos = event->pos(); QPointF pos = event->pos();
int initialX = static_cast<int>(pos.x()) / 16; int initialX = static_cast<int>(pos.x()) / 16;
int initialY = static_cast<int>(pos.y()) / 16; int initialY = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(initialX, initialY); this->magicFill(initialX, initialY);
}
if (block) { draw();
}
}
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<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions(); QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length(); this->magicFill(x, y, selectionDimensions, selectedMetatiles, selectedCollisions, fromScriptCall);
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); }
uint16_t tile = block->tile;
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 y = 0; y < map->getHeight(); y++) {
for (int x = 0; x < map->getWidth(); x++) { for (int x = 0; x < map->getWidth(); x++) {
block = map->getBlock(x, y); block = map->getBlock(x, y);
@ -314,21 +340,33 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
block->collision = selectedCollisions->at(index).first; block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second; block->elevation = selectedCollisions->at(index).second;
} }
map->setBlock(x, y, *block); map->setBlock(x, y, *block, !fromScriptCall);
} }
} }
} }
} }
}
draw();
}
} }
void MapPixmapItem::_floodFill(int initialX, int initialY) { void MapPixmapItem::floodFill(int initialX, int initialY, bool fromScriptCall) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions(); 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(); bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length();
int numMetatiles = map->getWidth() * map->getHeight(); int numMetatiles = map->getWidth() * map->getHeight();
@ -364,7 +402,7 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
block->collision = selectedCollisions->at(index).first; block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second; 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) { if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x + 1, y)); todo.append(QPoint(x + 1, y));
@ -387,7 +425,7 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
delete[] visited; delete[] visited;
} }
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) { void MapPixmapItem::floodFillSmartPath(int initialX, int initialY) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions(); QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();

View file

@ -9,11 +9,11 @@ const grassTiles = [0x8, 0x9, 0x10, 0x11];
// Porymap callback when a block is painted. // Porymap callback when a block is painted.
export function on_block_changed(x, y, prevBlock, newBlock) { export function on_block_changed(x, y, prevBlock, newBlock) {
try { try {
if (grassTiles.indexOf(newBlock.tile) != -1) { // if (grassTiles.indexOf(newBlock.tile) != -1) {
const i = randInt(0, grassTiles.length); // const i = randInt(0, grassTiles.length);
map.setBlock(x, y, grassTiles[i], newBlock.collision, newBlock.elevation); // map.setBlock(x, y, grassTiles[i], newBlock.collision, newBlock.elevation);
} // }
map.setBlocksFromSelection(1, 1) console.log("ran", map.getWidth(), map.getHeight());
} catch(err) { } catch(err) {
console.log(err); console.log(err);
} }