bool CollisionObject::isCollisionWithTileRight() { // iterate through collision layers for (std::vector<TileLayer*>::const_iterator it = m_pCollisionLayers->begin(); it != m_pCollisionLayers->end(); ++it) { TileLayer* pTileLayer = (*it); std::vector<std::vector<int>> tiles = pTileLayer->getTileIDs(); // get this layers position Vector2D layerPos = pTileLayer->getPosition(); int x, y, tileColumn, tileRow, tileid = 0; // calculate position on tile map x = layerPos.getX() / pTileLayer->getTileSize(); y = layerPos.getY() / pTileLayer->getTileSize(); if (getVelocity().getX() > 0) //dreta { tileColumn = ((getPosition().getX() + Camera::Instance()->getPosition().getX() + getWidth()) / pTileLayer->getTileSize()); tileRow = (getPosition().getY() / pTileLayer->getTileSize()); tileid = tiles[tileRow+y][tileColumn + x];//Li restem 1 a la y perque quan estiguem asobre la plataforma no ens doni colisio } if (tileid != 0) // if the tile id not blank then collide { return true; } } return false; }
/** * Returns a new stamp where all variations have been flipped in the given * \a direction. */ TileStamp TileStamp::flipped(FlipDirection direction) const { TileStamp flipped(*this); flipped.d.detach(); for (const TileStampVariation &variation : flipped.variations()) { TileLayer *layer = variation.tileLayer(); if (variation.map->isStaggered()) { Map::StaggerAxis staggerAxis = variation.map->staggerAxis(); if (staggerAxis == Map::StaggerY) { if ((direction == FlipVertically && !(layer->height() & 1)) || direction == FlipHorizontally) variation.map->invertStaggerIndex(); } else { if ((direction == FlipHorizontally && !(layer->width() & 1)) || direction == FlipVertically) variation.map->invertStaggerIndex(); } } if (variation.map->orientation() == Map::Hexagonal) layer->flipHexagonal(direction); else layer->flip(direction); } return flipped; }
/* ------------------------------------------------------------------------------ * startAnimation - Attempts to start the next tile in the chained conveyor * belt animation. Returns true if all tiles have been started. For best * results, call this method each time a new screen frame is blitted. */ bool ConveyorAnimation::startAnimation() { if (this->nextTileToStart >= this->conveyorTiles.size()) { return true; } GridLayer* gl = GridLayer::GetInstance(); TileLayer* currentTile = NULL; if (this->nextTileToStart == 0) { // Always start the first tile in the belt. TileCoord currentTileCoord = this->conveyorTiles[0]; currentTile = gl->getTile(currentTileCoord.first, currentTileCoord.second); currentTile->getAnimation()->play(); gl->pushAnimatedTile(currentTile); this->nextTileToStart++; } else { TileCoord currentTileCoord = this->conveyorTiles[this->nextTileToStart-1]; currentTile = gl->getTile(currentTileCoord.first, currentTileCoord.second); if ((currentTile->getAnimation()->getCurrentStill()+1) % 8 == 0) { TileCoord tileCoord = this->conveyorTiles[this->nextTileToStart]; TileLayer* tile = gl->getTile(tileCoord.first, tileCoord.second); tile->getAnimation()->play(); gl->pushAnimatedTile(tile); this->nextTileToStart++; } } return (this->nextTileToStart >= this->conveyorTiles.size()); }
void StampBrush::configureBrush(const QVector<QPoint> &list) { if (!mStamp) return; QRegion reg; QRegion stampRegion(mStamp->region()); Map *map = mapDocument()->map(); TileLayer *stamp = new TileLayer(QString(), 0, 0, map->width(), map->height()); foreach (QPoint p, list) { const QRegion update = stampRegion.translated(p.x() - mStampX, p.y() - mStampY); if (!reg.intersects(update)) { reg += update; stamp->merge(p, mStamp); } } brushItem()->setTileLayer(stamp); delete stamp; }
void Level::update() { ObjectLayer * pObjects; for (int i = 0; i < m_layers.size(); ++i) { if (m_pPlayer->getPosition()->getX() + m_pPlayer->getWidth() > 635) { TileLayer * pTile = dynamic_cast<TileLayer*>(m_layers[i]); if (pTile && pTile->getNumColumns() + pTile->getColumnIncrement() < pTile->getTileIDs().at(0).size()) { pTile->setColumns(20); m_pPlayer->setPosition(Vector2D(10, 330)); BulletHandler::Instance()->clearAll(); scrollObjects(); } else { m_pPlayer->setVelocity(Vector2D(0.0, 0.0)); } } m_layers[i]->update(); pObjects = dynamic_cast<ObjectLayer*>(m_layers[i]); if (pObjects) { CollisionManager::Instance()->checkEnemyPlayerBulletCollision(BulletHandler::Instance()->getBulletPlayer(), pObjects->getObjects()); } } CollisionManager::Instance()->checkPlayerEnemyBulletCollision(m_pPlayer, BulletHandler::Instance()->getBulletEnemy()); BulletHandler::Instance()->update(); if (m_pPlayer->isDead()) { Game::Instance()->getStateMachine()->changeState(new GameOverState()); } }
void TilesetDock::deleteTilesetView(int index) { TilesetDocument *tilesetDocument = mTilesetDocuments.at(index); tilesetDocument->disconnect(this); Tileset *tileset = tilesetDocument->tileset().data(); TilesetView *view = tilesetViewAt(index); QString path = QLatin1String("TilesetDock/TilesetScale/") + tileset->name(); QSettings *settings = Preferences::instance()->settings(); if (view->scale() != 1.0) settings->setValue(path, view->scale()); else settings->remove(path); mTilesets.remove(index); mTilesetDocuments.removeAt(index); delete view; // view needs to go before the tab mTabBar->removeTab(index); // Make sure we don't reference this tileset anymore if (mCurrentTiles && mCurrentTiles->referencesTileset(tileset)) { TileLayer *cleaned = mCurrentTiles->clone(); cleaned->removeReferencesToTileset(tileset); setCurrentTiles(cleaned); } if (mCurrentTile && mCurrentTile->tileset() == tileset) setCurrentTile(nullptr); }
/*virtual*/ void Bullet::Update(float dt) /*override*/ { SGD::Rectangle rect; rect.top = m_ptPosition.y; rect.left = m_ptPosition.x; rect.Resize(bulletSize*dist); TileLayer *layer0 = World::GetInstance()->GetTileLayers()[0]; if (rect.top < 0.0f || rect.left < 0.0f || rect.bottom >= layer0->layerRows * layer0->GetTileSize().width || rect.right >= layer0->layerColumns * layer0->GetTileSize().height ) { return; } // if this bullet goes outside bullet dropoff range... if (owner->GetOwner() && (m_ptPosition - startPoint).ComputeLength() > bulletDropOff) { // create a message to destroy this bullet DestroyEntityMsg* msg = new DestroyEntityMsg(this); // dispatch the destroy message SGD::MessageManager::GetInstance()->GetInstance()->QueueMessage(msg); } if (gunActive) { dist += 0.075f; if (dist > 1.75f) dist = 1.75f; } // if bullet collides with tile, play collision sound //if (owner->GetGunType() != Weapon::GunType::meleeWeapon) // if not, update bullet Entity::Update(dt); TileLayer* collisionLayer = GameplayState::GetInstance()->GetWorld()->GetTileLayers()[1]; const SGD::Point ref_position = { m_ptPosition.x + m_szSize.width*0.5f, m_ptPosition.y + m_szSize.height*0.5f }; const int tileSize_width = (int)collisionLayer->GetTileSize().width; const int tileSize_height = (int)collisionLayer->GetTileSize().height; const int tilesWide = collisionLayer->layerColumns - 1; const int tilesHigh = collisionLayer->layerRows - 1; SGD::Point index = { Math::Clamp((ref_position.x / (float)tileSize_width), 0.f, (float)tilesWide), Math::Clamp(ref_position.y / (float)tileSize_height, 0.f, (float)tilesHigh) }; Tile* tile_at = collisionLayer->GetTileAt(int(index.x), int(index.y)); if (tile_at && !tile_at->isPassable) { if (tile_at->event != "bp" && owner->GetGunType() != Weapon::GunType::meleeWeapon && owner->GetGunType() != Weapon::GunType::MutantAtk) { SGD::AudioManager::GetInstance()->PlayAudio(GameplayState::GetInstance()->bulletImpact); DestroyEntityMsg* msg = new DestroyEntityMsg(this); msg->QueueMessage(); } } }
void LevelParser::parseTileLayer(TiXmlElement* pTileElement, std::vector<Layer*> *pLayers, const std::vector<Tileset>* pTilesets, std::vector<TileLayer*> *m_CollisionsLayer) { TileLayer* pTileLayer = new TileLayer(m_tileSizew, m_tileSizeh, *pTilesets); bool collidable = false; std::vector<std::vector<int>> data; std::string decodedIDs; TiXmlElement* pDataNode; for (TiXmlElement* e = pTileElement->FirstChildElement(); e != NULL; e = e->NextSiblingElement()) { if (e->Value() == std::string("properties")) { for (TiXmlElement* property = e->FirstChildElement(); property != NULL; property = property->NextSiblingElement()) { if (property->Value() == std::string("property")) { if (property->Attribute("name") == std::string("collidable")) { collidable = true; } } } } if (e->Value() == std::string("data")) { pDataNode = e; } } for (TiXmlNode* e = pDataNode->FirstChild(); e != NULL; e = e->NextSibling()) { TiXmlText* text = e->ToText(); std::string t = text->Value(); decodedIDs = base64_decode(t); } uLongf numGids = m_width * m_height * sizeof(int); std::vector<unsigned> gids(numGids); uncompress((Bytef*)&gids[0], &numGids, (const Bytef*)decodedIDs.c_str(), decodedIDs.size()); std::vector<int> layerRow(m_width); for (int j = 0; j < m_height; j++) { data.push_back(layerRow); } for (int rows = 0; rows < m_height; rows++) { for (int cols = 0; cols < m_width; cols++) { data[rows][cols] = gids[rows * m_width + cols]; } } if (collidable) { m_CollisionsLayer->push_back(pTileLayer); } pTileLayer->setTileIDs(data); pLayers->push_back(pTileLayer); }
TileLayer *StampBrush::getRandomTileLayer() const { if (mRandomList.empty()) return 0; TileLayer *ret = new TileLayer(QString(), 0, 0, 1, 1); ret->setCell(0, 0, mRandomList.at(rand() % mRandomList.size())); return ret; }
void TerrainBrush::capture() { TileLayer *tileLayer = currentTileLayer(); Q_ASSERT(tileLayer); // TODO: we need to know which corner the mouse is closest to... const Cell &cell = tileLayer->cellAt(tilePosition()); Terrain *t = cell.tile->terrainAtCorner(0); setTerrain(t); }
/** * Returns a new stamp where all variations have been flipped in the given * \a direction. */ TileStamp TileStamp::flipped(FlipDirection direction) const { TileStamp flipped(*this); flipped.d.detach(); foreach (const TileStampVariation &variation, flipped.variations()) { TileLayer *layer = static_cast<TileLayer*>(variation.map->layerAt(0)); layer->flip(direction); } return flipped; }
void LevelParser::parseTileLayer(TiXmlElement* pTileElement, std::vector<Layer*> *pLayers, const std::vector<Tileset>* pTilesets) { TileLayer* pTileLayer = new TileLayer(m_tileSize, *pTilesets); // tile data std::vector<std::vector<int>> data; std::string decodedIDs; TiXmlElement* pDataNode = NULL; for (TiXmlElement* e = pTileElement->FirstChildElement(); e != NULL; e = e->NextSiblingElement()) { if (e->Value() == std::string("data")) { pDataNode = e; } } for (TiXmlNode* e = pDataNode->FirstChild(); e != NULL; e = e->NextSibling()) { TiXmlText* text = e->ToText(); std::string t = text->Value(); decodedIDs = base64_decode(t); } // uncompress zlib compression uLongf numGids = m_width * m_height * sizeof(int); std::vector<unsigned> gids(numGids); uncompress((Bytef*)&gids[0], &numGids, (const Bytef*)decodedIDs.c_str(), decodedIDs.size()); std::vector<int> layerRow(m_width); for (int j = 0; j < m_height; j++) { data.push_back(layerRow); } for (int rows = 0; rows < m_height; rows++) { for (int cols = 0; cols < m_width; cols++) { data[rows][cols] = gids[rows * m_width + cols]; } } pTileLayer->setTileIDs(data); pLayers->push_back(pTileLayer); }
void MapDocument::autocropMap() { if (!mCurrentLayer || !mCurrentLayer->isTileLayer()) return; TileLayer *tileLayer = static_cast<TileLayer*>(mCurrentLayer); const QRect bounds = tileLayer->region().boundingRect(); if (bounds.isNull()) return; resizeMap(bounds.size(), -bounds.topLeft(), true); }
Layer *TileLayer::mergedWith(Layer *other) const { Q_ASSERT(canMergeWith(other)); const TileLayer *o = static_cast<TileLayer*>(other); const QRect unitedBounds = bounds().united(o->bounds()); const QPoint offset = position() - unitedBounds.topLeft(); TileLayer *merged = static_cast<TileLayer*>(clone()); merged->resize(unitedBounds.size(), offset); merged->merge(o->position() - unitedBounds.topLeft(), o); return merged; }
void Tile::Render() { // For efficiency, we only render from lowest to highest // layer index for (size_t i=m_iLowLayerIdx; i<=m_iHighLayerIdx; ++i) { // Some layers may not have been set in between TileLayer* pTileLayer = m_tileLayerPtrs[i].get(); if ( pTileLayer != NULL ) pTileLayer->Render(m_pos.x, m_pos.y, m_size.w, m_size.h); } }
/** * Returns a new stamp where all variations have been rotated in the given * \a direction. */ TileStamp TileStamp::rotated(RotateDirection direction) const { TileStamp rotated(*this); rotated.d.detach(); for (const TileStampVariation &variation : rotated.variations()) { const QRect mapRect(QPoint(), variation.map->size()); QSize rotatedSize; for (auto layer : variation.map->tileLayers()) { TileLayer *tileLayer = static_cast<TileLayer*>(layer); // Synchronize tile layer size to map size (assumes map contains all layers) if (tileLayer->rect() != mapRect) { tileLayer->resize(mapRect.size(), tileLayer->position()); tileLayer->setPosition(0, 0); } if (variation.map->orientation() == Map::Hexagonal) tileLayer->rotateHexagonal(direction, variation.map); else tileLayer->rotate(direction); rotatedSize = tileLayer->size(); } variation.map->setWidth(rotatedSize.width()); variation.map->setHeight(rotatedSize.height()); } return rotated; }
void BucketFillTool::randomFill(TileLayer &tileLayer, const QRegion ®ion) const { if (region.isEmpty() || mRandomCellPicker.isEmpty()) return; for (const QRect &rect : region.translated(-tileLayer.position()).rects()) { for (int _x = rect.left(); _x <= rect.right(); ++_x) { for (int _y = rect.top(); _y <= rect.bottom(); ++_y) { tileLayer.setCell(_x, _y, mRandomCellPicker.pick()); } } } }
void StampBrush::endCapture() { if (mBrushBehavior != Capture) return; mBrushBehavior = Free; TileLayer *tileLayer = currentTileLayer(); Q_ASSERT(tileLayer); // Intersect with the layer and translate to layer coordinates QRect captured = capturedArea(); captured.intersect(QRect(tileLayer->x(), tileLayer->y(), tileLayer->width(), tileLayer->height())); if (captured.isValid()) { captured.translate(-tileLayer->x(), -tileLayer->y()); TileLayer *capture = tileLayer->copy(captured); emit currentTilesChanged(capture); // A copy will have been created, so delete this version delete capture; } else { updatePosition(); } }
void BucketFillTool::updateRandomList() { mRandomList.clear(); mMissingTilesets.clear(); foreach (const TileStampVariation &variation, mStamp.variations()) { TileLayer *tileLayer = static_cast<TileLayer*>(variation.map->layerAt(0)); mapDocument()->unifyTilesets(variation.map, mMissingTilesets); for (int x = 0; x < tileLayer->width(); x++) for (int y = 0; y < tileLayer->height(); y++) if (!tileLayer->cellAt(x, y).isEmpty()) mRandomList.append(tileLayer->cellAt(x, y)); } }
void CollisionManager::checkPlayerTileCollision(Player* pPlayer, const std::vector<TileLayer*>& collisionLayers) { for(auto it = collisionLayers.begin(); it != collisionLayers.end(); ++it) { TileLayer* pTileLayer = (*it); std::vector<std::vector<int>> tiles = pTileLayer->getTileIDs(); Vector2D layerPos = pTileLayer->getPosition(); int x, y, tileColumn, tileRow, tileid = 0; x = layerPos.getX() / pTileLayer->getTileSize(); y = layerPos.getY() / pTileLayer->getTileSize(); if(pPlayer->getVelocity().getX() >= 0 || pPlayer->getVelocity().getY() >= 0) { tileColumn = ((pPlayer->getPosition().getX() + pPlayer->getWidth()) / pTileLayer->getTileSize()); tileRow = ((pPlayer->getPosition().getY() + pPlayer->getHeight()) / pTileLayer->getTileSize()); tileid = tiles[tileRow + y][tileColumn + x]; } else if(pPlayer->getVelocity().getX() < 0 || pPlayer->getVelocity().getY() < 0) { tileColumn = pPlayer->getPosition().getX() / pTileLayer->getTileSize(); tileRow = pPlayer->getPosition().getY() / pTileLayer->getTileSize(); tileid = tiles[tileRow + y][tileColumn + x]; } if(tileid != 0) { pPlayer->collision(); } } }
void SelectSameTileTool::tilePositionChanged(const QPoint &tilePos) { // Make sure that a tile layer is selected and contains current tile pos. TileLayer *tileLayer = currentTileLayer(); if (!tileLayer) return; QRegion resultRegion; if (tileLayer->contains(tilePos)) { const Cell &matchCell = tileLayer->cellAt(tilePos); resultRegion = tileLayer->region([&] (const Cell &cell) { return cell == matchCell; }); } mSelectedRegion = resultRegion; brushItem()->setTileRegion(mSelectedRegion); }
/** * Returns a new stamp where all variations have been rotated in the given * \a direction. */ TileStamp TileStamp::rotated(RotateDirection direction) const { TileStamp rotated(*this); rotated.d.detach(); foreach (const TileStampVariation &variation, rotated.variations()) { TileLayer *layer = static_cast<TileLayer*>(variation.map->layerAt(0)); layer->rotate(direction); variation.map->setWidth(layer->width()); variation.map->setHeight(layer->height()); } return rotated; }
void Eraser::doErase(bool mergeable) { TileLayer *tileLayer = currentTileLayer(); const QPoint tilePos = tilePosition(); if (!tileLayer->bounds().contains(tilePos)) return; QRegion eraseRegion(tilePos.x(), tilePos.y(), 1, 1); EraseTiles *erase = new EraseTiles(mapDocument(), tileLayer, eraseRegion); erase->setMergeable(mergeable); mapDocument()->undoStack()->push(erase); mapDocument()->emitRegionEdited(eraseRegion, tileLayer); }
void TerrainBrush::updateBrush(QPoint cursorPos, const QVector<QPoint> *list) { // get the current tile layer TileLayer *currentLayer = currentTileLayer(); Q_ASSERT(currentLayer); int layerWidth = currentLayer->width(); int layerHeight = currentLayer->height(); int numTiles = layerWidth * layerHeight; int paintCorner = 0; // if we are in vertex paint mode, the bottom right corner on the map will appear as an invalid tile offset... if (mBrushMode == PaintVertex) { if (cursorPos.x() == layerWidth) { cursorPos.setX(cursorPos.x() - 1); paintCorner |= 1; } if (cursorPos.y() == layerHeight) { cursorPos.setY(cursorPos.y() - 1); paintCorner |= 2; } } // if the cursor is outside of the map, bail out if (!currentLayer->bounds().contains(cursorPos)) return; // TODO: this seems like a problem... there's nothing to say that 2 adjacent tiles are from the same tileset, or have any relation to eachother... Tileset *terrainTileset = mTerrain ? mTerrain->tileset() : NULL; // allocate a buffer to build the terrain tilemap (TODO: this could be retained per layer to save regular allocation) Tile **newTerrain = new Tile*[numTiles]; // allocate a buffer of flags for each tile that may be considered (TODO: this could be retained per layer to save regular allocation) char *checked = new char[numTiles]; memset(checked, 0, numTiles); // create a consideration list, and push the start points QList<QPoint> transitionList; int initialTiles = 0; if (list) { // if we were supplied a list of start points foreach (const QPoint &p, *list) { transitionList.push_back(p); ++initialTiles; } } else {
// Reader Tiled::Map *DroidcraftPlugin::read(const QString &fileName) { using namespace Tiled; QByteArray uncompressed; // Read data QFile f(fileName); if (f.open(QIODevice::ReadOnly)) { QByteArray compressed = f.readAll(); f.close(); uncompressed = decompress(compressed, 48 * 48); } // Check the data if (uncompressed.count() != 48 * 48) { mError = tr("This is not a valid Droidcraft map file!"); return 0; } // Build 48 x 48 map // Create a Map -> Create a Tileset -> Add Tileset to map // -> Create a TileLayer -> Fill layer -> Add TileLayer to Map Map *map = new Map(Map::Orthogonal, 48, 48, 32, 32); Tileset *mapTileset = new Tileset("tileset", 32, 32); mapTileset->loadFromImage(QImage(":/tileset.png"), "tileset.png"); map->addTileset(mapTileset); // Fill layer TileLayer *mapLayer = new TileLayer("map", 0, 0, 48, 48); // Load for (int i = 0; i < 48 * 48; i++) { unsigned char tileFile = uncompressed.at(i); int y = i / 48; int x = i - (48 * y); Tile *tile = mapTileset->tileAt(tileFile); mapLayer->setCell(x, y, Cell(tile)); } map->addLayer(mapLayer); return map; }
void MapToVariantConverter::addTileLayerData(QVariantMap &variant, const TileLayer &tileLayer, Map::LayerDataFormat format, const QRect &bounds) const { switch (format) { case Map::XML: case Map::CSV: { QVariantList tileVariants; for (int y = bounds.top(); y <= bounds.bottom(); ++y) for (int x = bounds.left(); x <= bounds.right(); ++x) tileVariants << mGidMapper.cellToGid(tileLayer.cellAt(x, y)); variant[QLatin1String("data")] = tileVariants; break; } case Map::Base64: case Map::Base64Zlib: case Map::Base64Gzip: { QByteArray layerData = mGidMapper.encodeLayerData(tileLayer, format, bounds); variant[QLatin1String("data")] = layerData; break; } } }
void ShapeFillTool::mouseReleased(QGraphicsSceneMouseEvent *event) { AbstractTileFillTool::mouseReleased(event); if (mToolBehavior != MakingShape) return; if (event->button() == Qt::LeftButton) { mToolBehavior = Free; TileLayer *tileLayer = currentTileLayer(); if (!tileLayer) return; if (!brushItem()->isVisible() || !tileLayer->isUnlocked()) return; const TileLayer *preview = mFillOverlay.data(); if (!preview) return; PaintTileLayer *paint = new PaintTileLayer(mapDocument(), tileLayer, preview->x(), preview->y(), preview); paint->setText(QCoreApplication::translate("Undo Commands", "Shape Fill")); if (!mMissingTilesets.isEmpty()) { for (const SharedTileset &tileset : mMissingTilesets) { if (!mapDocument()->map()->tilesets().contains(tileset)) new AddTileset(mapDocument(), tileset, paint); } mMissingTilesets.clear(); } QRegion fillRegion(mFillRegion); mapDocument()->undoStack()->push(paint); emit mapDocument()->regionEdited(fillRegion, currentTileLayer()); mFillRegion = QRegion(); mFillOverlay.clear(); brushItem()->clear(); } }
TileLayer *TileLayer::copy(const QRegion ®ion) const { const QRect areaBounds = region.boundingRect(); TileLayer *copied = new TileLayer(QString(), 0, 0, areaBounds.width(), areaBounds.height()); for (const QRect &rect : region.rects()) for (int x = rect.left(); x <= rect.right(); ++x) for (int y = rect.top(); y <= rect.bottom(); ++y) copied->setCell(x - areaBounds.x(), y - areaBounds.y(), cellAt(x, y)); return copied; }
/** * Returns a new stamp where all variations have been rotated in the given * \a direction. */ TileStamp TileStamp::rotated(RotateDirection direction) const { TileStamp rotated(*this); rotated.d.detach(); for (const TileStampVariation &variation : rotated.variations()) { TileLayer *layer = variation.tileLayer(); if (variation.map->orientation() == Map::Hexagonal) layer->rotateHexagonal(direction, variation.map); else layer->rotate(direction); variation.map->setWidth(layer->width()); variation.map->setHeight(layer->height()); } return rotated; }
/** * Updates the list used random stamps. * This is done by taking all non-null tiles from the original stamp mStamp. */ void StampBrush::updateRandomList() { mRandomCellPicker.clear(); mMissingTilesets.clear(); if (mStamp.isEmpty()) return; foreach (const TileStampVariation &variation, mStamp.variations()) { TileLayer *tileLayer = static_cast<TileLayer*>(variation.map->layerAt(0)); mapDocument()->unifyTilesets(variation.map, mMissingTilesets); for (int x = 0; x < tileLayer->width(); x++) { for (int y = 0; y < tileLayer->height(); y++) { const Cell &cell = tileLayer->cellAt(x, y); if (!cell.isEmpty()) mRandomCellPicker.add(cell, cell.tile->probability()); } } } }