#include "mainwindow.h" #include "ui_mainwindow.h" #include "scripting.h" #include "editcommands.h" #include "config.h" #include "imageproviders.h" // TODO: "tilesetNeedsRedraw" is used when redrawing the map after // changing a metatile's tiles via script. It is unnecessarily // resource intensive. The map metatiles that need to be updated are // not marked as changed, so they will not be redrawn if the cache // isn't ignored. Ideally the setMetatileTiles functions would properly // set each of the map spaces that use the modified metatile so that // the cache could be used, though this would lkely still require a // full read of the map. void MainWindow::tryRedrawMapArea(bool forceRedraw) { if (!forceRedraw) return; if (this->tilesetNeedsRedraw) { // Refresh anything that can display metatiles 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(); if (this->tilesetEditor) this->tilesetEditor->updateTilesets(this->editor->map->layout->tileset_primary_label, this->editor->map->layout->tileset_secondary_label); if (this->editor->metatile_selector_item) this->editor->metatile_selector_item->draw(); if (this->editor->selected_border_metatiles_item) this->editor->selected_border_metatiles_item->draw(); if (this->editor->current_metatile_selection_item) this->editor->current_metatile_selection_item->draw(); this->tilesetNeedsRedraw = false; } else { this->editor->map_item->draw(); this->editor->collision_item->draw(); this->editor->selected_border_metatiles_item->draw(); this->editor->updateMapBorder(); } } void MainWindow::tryCommitMapChanges(bool commitChanges) { if (commitChanges) { Map *map = this->editor->map; if (map) { map->editHistory.push(new ScriptEditMap(map, 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 )); } } } //===================== // Editing map blocks //===================== QJSValue MainWindow::getBlock(int x, int y) { if (!this->editor || !this->editor->map) return QJSValue(); Block block; if (!this->editor->map->getBlock(x, y, &block)) { return Scripting::fromBlock(Block()); } return Scripting::fromBlock(block); } void MainWindow::setBlock(int x, int y, int metatileId, int collision, int elevation, bool forceRedraw, bool commitChanges) { if (!this->editor || !this->editor->map) return; this->editor->map->setBlock(x, y, Block(metatileId, collision, elevation)); this->tryCommitMapChanges(commitChanges); this->tryRedrawMapArea(forceRedraw); } void MainWindow::setBlock(int x, int y, int rawValue, bool forceRedraw, bool commitChanges) { if (!this->editor || !this->editor->map) return; this->editor->map->setBlock(x, y, Block(static_cast<uint16_t>(rawValue))); 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; if (!this->editor->map->getBlock(x, y, &block)) { return 0; } return block.metatileId(); } void MainWindow::setMetatileId(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) { if (!this->editor || !this->editor->map) return; Block block; if (!this->editor->map->getBlock(x, y, &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; if (!this->editor->map->getBlock(x, y, &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; if (!this->editor->map->getBlock(x, y, &block)) { return; } this->editor->map->setBlock(x, y, Block(block.metatileId(), 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; if (!this->editor->map->getBlock(x, y, &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; if (!this->editor->map->getBlock(x, y, &block)) { return; } this->editor->map->setBlock(x, y, Block(block.metatileId(), 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, true); 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 (!Project::mapDimensionsValid(width, height)) return; this->editor->map->setDimensions(width, height); this->tryCommitMapChanges(true); this->onMapNeedsRedrawing(); } void MainWindow::setWidth(int width) { if (!this->editor || !this->editor->map) return; if (!Project::mapDimensionsValid(width, this->editor->map->getHeight())) return; this->editor->map->setDimensions(width, this->editor->map->getHeight()); this->tryCommitMapChanges(true); this->onMapNeedsRedrawing(); } void MainWindow::setHeight(int height) { if (!this->editor || !this->editor->map) return; if (!Project::mapDimensionsValid(this->editor->map->getWidth(), height)) return; this->editor->map->setDimensions(this->editor->map->getWidth(), height); this->tryCommitMapChanges(true); this->onMapNeedsRedrawing(); } //===================== // Editing map border //===================== 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); } 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::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(); } //====================== // Editing map tilesets //====================== void MainWindow::refreshAfterPaletteChange(Tileset *tileset) { if (this->tilesetEditor) { this->tilesetEditor->updateTilesets(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, bool forceRedraw) { 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); if (forceRedraw) { this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary); } } void MainWindow::setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes, bool forceRedraw) { 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]); } if (forceRedraw) { this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary); } } void MainWindow::setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) { 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); if (forceRedraw) { this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary); } } void MainWindow::setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes, bool forceRedraw) { 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]); } if (forceRedraw) { this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary); } } QJSValue MainWindow::getTilesetPalette(const 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(const 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; tileset->palettePreviews[paletteIndex][i] = qRgb(colors[i][0], colors[i][1], colors[i][2]); } } void MainWindow::setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) { 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); if (forceRedraw) { this->refreshAfterPalettePreviewChange(); } } void MainWindow::setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes, bool forceRedraw) { 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]); } if (forceRedraw) { this->refreshAfterPalettePreviewChange(); } } void MainWindow::setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) { 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); if (forceRedraw) { this->refreshAfterPalettePreviewChange(); } } void MainWindow::setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes, bool forceRedraw) { 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]); } if (forceRedraw) { 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); } int MainWindow::getNumPrimaryTilesetMetatiles() { if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary) return 0; return this->editor->map->layout->tileset_primary->metatiles.length(); } int MainWindow::getNumSecondaryTilesetMetatiles() { if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary) return 0; return this->editor->map->layout->tileset_secondary->metatiles.length(); } int MainWindow::getNumPrimaryTilesetTiles() { if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary) return 0; return this->editor->map->layout->tileset_primary->tiles.length(); } int MainWindow::getNumSecondaryTilesetTiles() { if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary) return 0; return this->editor->map->layout->tileset_secondary->tiles.length(); } 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::saveMetatilesByMetatileId(int metatileId) { Tileset * tileset = Tileset::getMetatileTileset(metatileId, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); if (this->editor->project && tileset) this->editor->project->saveTilesetMetatiles(tileset); } void MainWindow::saveMetatileAttributesByMetatileId(int metatileId) { Tileset * tileset = Tileset::getMetatileTileset(metatileId, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); if (this->editor->project && tileset) this->editor->project->saveTilesetMetatileAttributes(tileset); // If the Tileset Editor is currently displaying the updated metatile, refresh it if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId) this->tilesetEditor->onSelectedMetatileChanged(metatileId); } Metatile * MainWindow::getMetatile(int metatileId) { if (!this->editor || !this->editor->map || !this->editor->map->layout) return nullptr; return Tileset::getMetatile(metatileId, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); } QString MainWindow::getMetatileLabel(int metatileId) { if (!this->editor || !this->editor->map || !this->editor->map->layout) return QString(); return Tileset::getMetatileLabel(metatileId, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); } void MainWindow::setMetatileLabel(int metatileId, QString label) { if (!this->editor || !this->editor->map || !this->editor->map->layout) return; // If the Tileset Editor is opened on this metatile we need to update the text box if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId){ this->tilesetEditor->setMetatileLabel(label); return; } if (!Tileset::setMetatileLabel(metatileId, label, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary)) { logError("Failed to set metatile label. Must be a valid metatile id and a label containing only letters, numbers, and underscores."); return; } if (this->editor->project) this->editor->project->saveTilesetMetatileLabels(this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); } int MainWindow::getMetatileLayerType(int metatileId) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return -1; return metatile->layerType; } void MainWindow::setMetatileLayerType(int metatileId, int layerType) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return; metatile->setLayerType(layerType); this->saveMetatileAttributesByMetatileId(metatileId); } int MainWindow::getMetatileEncounterType(int metatileId) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return -1; return metatile->encounterType; } void MainWindow::setMetatileEncounterType(int metatileId, int encounterType) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return; metatile->setEncounterType(encounterType); this->saveMetatileAttributesByMetatileId(metatileId); } int MainWindow::getMetatileTerrainType(int metatileId) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return -1; return metatile->terrainType; } void MainWindow::setMetatileTerrainType(int metatileId, int terrainType) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return; metatile->setTerrainType(terrainType); this->saveMetatileAttributesByMetatileId(metatileId); } int MainWindow::getMetatileBehavior(int metatileId) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return -1; return metatile->behavior; } void MainWindow::setMetatileBehavior(int metatileId, int behavior) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return; metatile->setBehavior(behavior); this->saveMetatileAttributesByMetatileId(metatileId); } int MainWindow::getMetatileAttributes(int metatileId) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return -1; return metatile->getAttributes(); } void MainWindow::setMetatileAttributes(int metatileId, int attributes) { Metatile * metatile = this->getMetatile(metatileId); if (!metatile) return; metatile->setAttributes(attributes); this->saveMetatileAttributesByMetatileId(metatileId); } int MainWindow::calculateTileBounds(int * tileStart, int * tileEnd) { int maxNumTiles = projectConfig.getNumTilesInMetatile(); if (*tileEnd >= maxNumTiles || *tileEnd < 0) *tileEnd = maxNumTiles - 1; if (*tileStart >= maxNumTiles || *tileStart < 0) *tileStart = 0; return 1 + (*tileEnd - *tileStart); } QJSValue MainWindow::getMetatileTiles(int metatileId, int tileStart, int tileEnd) { Metatile * metatile = this->getMetatile(metatileId); int numTiles = calculateTileBounds(&tileStart, &tileEnd); if (!metatile || numTiles <= 0) return QJSValue(); QJSValue tiles = Scripting::getEngine()->newArray(numTiles); for (int i = 0; i < numTiles; i++, tileStart++) tiles.setProperty(i, Scripting::fromTile(metatile->tiles[tileStart])); return tiles; } void MainWindow::setMetatileTiles(int metatileId, QJSValue tilesObj, int tileStart, int tileEnd, bool forceRedraw) { Metatile * metatile = this->getMetatile(metatileId); int numTiles = calculateTileBounds(&tileStart, &tileEnd); if (!metatile || numTiles <= 0) return; // Write to metatile using as many of the given Tiles as possible int numTileObjs = qMin(tilesObj.property("length").toInt(), numTiles); int i = 0; for (; i < numTileObjs; i++, tileStart++) metatile->tiles[tileStart] = Scripting::toTile(tilesObj.property(i)); // Fill remainder of specified length with empty Tiles for (; i < numTiles; i++, tileStart++) metatile->tiles[tileStart] = Tile(); this->saveMetatilesByMetatileId(metatileId); this->tilesetNeedsRedraw = true; this->tryRedrawMapArea(forceRedraw); } void MainWindow::setMetatileTiles(int metatileId, int tileId, bool xflip, bool yflip, int palette, int tileStart, int tileEnd, bool forceRedraw) { Metatile * metatile = this->getMetatile(metatileId); int numTiles = calculateTileBounds(&tileStart, &tileEnd); if (!metatile || numTiles <= 0) return; // Write to metatile using Tiles of the specified value Tile tile = Tile(tileId, xflip, yflip, palette); for (int i = tileStart; i <= tileEnd; i++) metatile->tiles[i] = tile; this->saveMetatilesByMetatileId(metatileId); this->tilesetNeedsRedraw = true; this->tryRedrawMapArea(forceRedraw); } QJSValue MainWindow::getMetatileTile(int metatileId, int tileIndex) { QJSValue tilesObj = this->getMetatileTiles(metatileId, tileIndex, tileIndex); return tilesObj.property(0); } void MainWindow::setMetatileTile(int metatileId, int tileIndex, int tileId, bool xflip, bool yflip, int palette, bool forceRedraw) { this->setMetatileTiles(metatileId, tileId, xflip, yflip, palette, tileIndex, tileIndex, forceRedraw); } void MainWindow::setMetatileTile(int metatileId, int tileIndex, QJSValue tileObj, bool forceRedraw) { Tile tile = Scripting::toTile(tileObj); this->setMetatileTiles(metatileId, tile.tileId, tile.xflip, tile.yflip, tile.palette, tileIndex, tileIndex, forceRedraw); } QJSValue MainWindow::getTilePixels(int tileId) { if (tileId < 0 || !this->editor || !this->editor->project || !this->editor->map || !this->editor->map->layout) return QJSValue(); QImage tileImage = getTileImage(tileId, this->editor->map->layout->tileset_primary, this->editor->map->layout->tileset_secondary); if (tileImage.isNull() || tileImage.sizeInBytes() < 64) return QJSValue(); const uchar * pixels = tileImage.constBits(); QJSValue pixelArray = Scripting::getEngine()->newArray(64); for (int i = 0; i < 64; i++) { pixelArray.setProperty(i, pixels[i]); } return pixelArray; } //===================== // Editing map header //===================== QString MainWindow::getSong() { if (!this->editor || !this->editor->map) return QString(); return this->editor->map->song; } void MainWindow::setSong(QString song) { if (!this->ui || !this->editor || !this->editor->project) return; if (!this->editor->project->songNames.contains(song)) { logError(QString("Unknown song '%1'").arg(song)); return; } this->ui->comboBox_Song->setCurrentText(song); } QString MainWindow::getLocation() { if (!this->editor || !this->editor->map) return QString(); return this->editor->map->location; } void MainWindow::setLocation(QString location) { if (!this->ui || !this->editor || !this->editor->project) return; if (!this->editor->project->mapSectionNameToValue.contains(location)) { logError(QString("Unknown location '%1'").arg(location)); return; } this->ui->comboBox_Location->setCurrentText(location); } bool MainWindow::getRequiresFlash() { if (!this->editor || !this->editor->map) return false; return this->editor->map->requiresFlash; } void MainWindow::setRequiresFlash(bool require) { if (!this->ui) return; this->ui->checkBox_Visibility->setChecked(require); } QString MainWindow::getWeather() { if (!this->editor || !this->editor->map) return QString(); return this->editor->map->weather; } void MainWindow::setWeather(QString weather) { if (!this->ui || !this->editor || !this->editor->project) return; if (!this->editor->project->weatherNames.contains(weather)) { logError(QString("Unknown weather '%1'").arg(weather)); return; } this->ui->comboBox_Weather->setCurrentText(weather); } QString MainWindow::getType() { if (!this->editor || !this->editor->map) return QString(); return this->editor->map->type; } void MainWindow::setType(QString type) { if (!this->ui || !this->editor || !this->editor->project) return; if (!this->editor->project->mapTypes.contains(type)) { logError(QString("Unknown map type '%1'").arg(type)); return; } this->ui->comboBox_Type->setCurrentText(type); } QString MainWindow::getBattleScene() { if (!this->editor || !this->editor->map) return QString(); return this->editor->map->battle_scene; } void MainWindow::setBattleScene(QString battleScene) { if (!this->ui || !this->editor || !this->editor->project) return; if (!this->editor->project->mapBattleScenes.contains(battleScene)) { logError(QString("Unknown battle scene '%1'").arg(battleScene)); return; } this->ui->comboBox_BattleScene->setCurrentText(battleScene); } bool MainWindow::getShowLocationName() { if (!this->editor || !this->editor->map) return false; return this->editor->map->show_location; } void MainWindow::setShowLocationName(bool show) { if (!this->ui) return; this->ui->checkBox_ShowLocation->setChecked(show); } bool MainWindow::getAllowRunning() { if (!this->editor || !this->editor->map) return false; return this->editor->map->allowRunning; } void MainWindow::setAllowRunning(bool allow) { if (!this->ui) return; this->ui->checkBox_AllowRunning->setChecked(allow); } bool MainWindow::getAllowBiking() { if (!this->editor || !this->editor->map) return false; return this->editor->map->allowBiking; } void MainWindow::setAllowBiking(bool allow) { if (!this->ui) return; this->ui->checkBox_AllowBiking->setChecked(allow); } bool MainWindow::getAllowEscaping() { if (!this->editor || !this->editor->map) return false; return this->editor->map->allowEscaping; } void MainWindow::setAllowEscaping(bool allow) { if (!this->ui) return; this->ui->checkBox_AllowEscaping->setChecked(allow); } int MainWindow::getFloorNumber() { if (!this->editor || !this->editor->map) return 0; return this->editor->map->floorNumber; } void MainWindow::setFloorNumber(int floorNumber) { if (!this->ui) return; if (floorNumber < -128 || floorNumber > 127) { logError(QString("Invalid floor number '%1'").arg(floorNumber)); return; } this->ui->spinBox_FloorNumber->setValue(floorNumber); }