def convertV1toV2(self, fileName): reader = MapReader() map = reader.readMap(fileName) if (not map): qWarning("Error at conversion of " + fileName + ":\n" + reader.errorString()) return for layer in map.layers(): if (layer.name().lower().startswith("ruleset")): layer.setName("Input_set") elif (layer.name().lower().startswith("rulenotset")): layer.setName("InputNot_set") elif (layer.name().lower().startswith("ruleregions")): layer.setName("Regions") elif (layer.name().lower().startswith("rule")): newname = layer.name().right(layer.name().length() - 4) layer.setName("Output" + newname) else: qWarning( QString("Warning at conversion of") + fileName + QString("unused layers found")) writer = MapWriter() writer.writeMap(map.data(), fileName) map.tilesets().clear()
def updateActions(self): map = None currentLayerIndex = -1 selection = QRegion() selectedObjectsCount = 0 canMergeDown = False if (self.mMapDocument): map = self.mMapDocument.map() currentLayerIndex = self.mMapDocument.currentLayerIndex() selection = self.mMapDocument.selectedArea() selectedObjectsCount = self.mMapDocument.selectedObjects().count() if (currentLayerIndex > 0): upper = map.layerAt(currentLayerIndex) lower = map.layerAt(currentLayerIndex - 1) canMergeDown = lower.canMergeWith(upper) self.mActionSelectAll.setEnabled(bool(map)) self.mActionSelectNone.setEnabled(not selection.isEmpty()) self.mActionCropToSelection.setEnabled(not selection.isEmpty()) self.mActionAddTileLayer.setEnabled(bool(map)) self.mActionAddObjectGroup.setEnabled(bool(map)) self.mActionAddImageLayer.setEnabled(bool(map)) if map: _x = map.layerCount() else: _x = 0 layerCount = _x hasPreviousLayer = currentLayerIndex >= 0 and currentLayerIndex < layerCount - 1 hasNextLayer = currentLayerIndex > 0 self.mActionDuplicateLayer.setEnabled(currentLayerIndex >= 0) self.mActionMergeLayerDown.setEnabled(canMergeDown) self.mActionSelectPreviousLayer.setEnabled(hasPreviousLayer) self.mActionSelectNextLayer.setEnabled(hasNextLayer) self.mActionMoveLayerUp.setEnabled(hasPreviousLayer) self.mActionMoveLayerDown.setEnabled(hasNextLayer) self.mActionToggleOtherLayers.setEnabled(layerCount > 1) self.mActionRemoveLayer.setEnabled(currentLayerIndex >= 0) self.mActionLayerProperties.setEnabled(currentLayerIndex >= 0) self.mActionDuplicateObjects.setEnabled(selectedObjectsCount > 0) self.mActionRemoveObjects.setEnabled(selectedObjectsCount > 0) duplicateText = QString() removeText = QString() if (selectedObjectsCount > 0): duplicateText = self.tr("Duplicate %n Object(s)", "", selectedObjectsCount) removeText = self.tr("Remove %n Object(s)", "", selectedObjectsCount) else: duplicateText = self.tr("Duplicate Objects") removeText = self.tr("Remove Objects") self.mActionDuplicateObjects.setText(duplicateText) self.mActionRemoveObjects.setText(removeText)
def __writeTileLayer(self, w, tileLayer): w.writeStartElement("layer") self.__writeLayerAttributes(w, tileLayer) self.__writeProperties(w, tileLayer.properties()) encoding = QString() compression = QString() if (self.mLayerDataFormat == Map.LayerDataFormat.Base64 or self.mLayerDataFormat == Map.LayerDataFormat.Base64Gzip or self.mLayerDataFormat == Map.LayerDataFormat.Base64Zlib): encoding = "base64" if (self.mLayerDataFormat == Map.LayerDataFormat.Base64Gzip): compression = "gzip" elif (self.mLayerDataFormat == Map.LayerDataFormat.Base64Zlib): compression = "zlib" elif (self.mLayerDataFormat == Map.LayerDataFormat.CSV): encoding = "csv" w.writeStartElement("data") if encoding != '': w.writeAttribute("encoding", encoding) if compression != '': w.writeAttribute("compression", compression) if (self.mLayerDataFormat == Map.LayerDataFormat.XML): for y in range(tileLayer.height()): for x in range(tileLayer.width()): gid = self.mGidMapper.cellToGid(tileLayer.cellAt(x, y)) w.writeStartElement("tile") w.writeAttribute("gid", str(gid)) w.writeEndElement() elif (self.mLayerDataFormat == Map.LayerDataFormat.CSV): tileData = '' for y in range(tileLayer.height()): for x in range(tileLayer.width()): gid = self.mGidMapper.cellToGid(tileLayer.cellAt(x, y)) tileData += str(gid) if (x != tileLayer.width() - 1 or y != tileLayer.height() - 1): tileData += "," tileData += "\n" w.writeCharacters("\n") w.writeCharacters(tileData) else: tileData = self.mGidMapper.encodeLayerData(tileLayer, self.mLayerDataFormat) w.writeCharacters("\n ") w.writeCharacters(tileData.data().decode()) w.writeCharacters("\n ") w.writeEndElement() # </data> w.writeEndElement() # </layer>
def updateCurrentTiles(self): view = self.currentTilesetView() if (not view): return s = view.selectionModel() if (not s): return indexes = s.selection().indexes() if len(indexes) == 0: return first = indexes[0] minX = first.column() maxX = first.column() minY = first.row() maxY = first.row() for index in indexes: if minX > index.column(): minX = index.column() if maxX < index.column(): maxX = index.column() if minY > index.row(): minY = index.row() if maxY < index.row(): maxY = index.row() # Create a tile layer from the current selection tileLayer = TileLayer(QString(), 0, 0, maxX - minX + 1, maxY - minY + 1) model = view.tilesetModel() for index in indexes: tileLayer.setCell(index.column() - minX, index.row() - minY, Cell(model.tileAt(index))) self.setCurrentTiles(tileLayer)
def readObjectTypes(self, fileName): self.mError = '' objectTypes = QVector() file = QFile(fileName) if (not file.open(QIODevice.ReadOnly | QIODevice.Text)): self.mError = QCoreApplication.translate("ObjectTypes", "Could not open file.") return objectTypes reader = QXmlStreamReader(file) if (not reader.readNextStartElement() or reader.name() != "objecttypes"): self.mError = QCoreApplication.translate( "ObjectTypes", "File doesn't contain object types.") return objectTypes while (reader.readNextStartElement()): if (reader.name() == "objecttype"): atts = reader.attributes() name = QString(atts.value("name")) color = QColor(atts.value("color")) objectTypes.append(ObjectType(name, color)) reader.skipCurrentElement() if (reader.hasError()): self.mError = QCoreApplication.translate( "ObjectTypes", "%s\n\nLine %d, column %d" % (reader.errorString(), reader.lineNumber(), reader.columnNumber())) return objectTypes return objectTypes
def __init__(self, parent=None): super().__init__(parent) ## # The current map document. ## self.mMapDocument = None ## # For each new file of rules a new AutoMapper is setup. In this vector we # can store all of the AutoMappers in order. ## self.mAutoMappers = QVector() ## # This tells you if the rules for the current map document were already # loaded. ## self.mLoaded = False ## # Contains all errors which occurred until canceling. # If mError is not empty, no serious result can be expected. ## self.mError = '' ## # Contains all strings, which try to explain unusual and unexpected # behavior. ## self.mWarning = QString()
def __init__(self, mapReader): self.p = mapReader self.mMap = None self.mError = QString('') self.mReadingExternalTileset = False self.xml = QXmlStreamReader() self.mGidMapper = GidMapper()
def addProperty(self, *args): l = len(args) if l == 0: property, ok = QInputDialog.getText(self.mPropertyBrowser, self.tr("Add Property"), self.tr("Name:"), QLineEdit.Normal, '') if ok: self.addProperty(property) elif l == 1: arg1 = args[0] tp = type(arg1) if tp == bool: self.addProperty() elif tp in [str, QString]: name = arg1 if name == '': return object = self.mMapDocument.currentObject() if (not object): return if (not object.hasProperty(name)): undoStack = self.mMapDocument.undoStack() undoStack.push( SetProperty(self.mMapDocument, self.mMapDocument.currentObjects(), name, QString())) self.mPropertyBrowser.editCustomProperty(name)
def writeMap(self, *args): l = len(args) if l==3: map, device, path = args self.d.writeMap(map, device, path) elif l==2: tp = type(args[1]) if tp==QIODevice: map, device, path = args, QString() self.d.writeMap(map, device, path) elif tp in [QString, str]: ## # Writes a TMX map to the given \a fileName. # # Returns False and sets errorString() when reading failed. # \overload ## map, fileName = args file = QSaveFile(fileName) if (not self.d.openFile(file)): return False self.writeMap(map, file, QFileInfo(fileName).absolutePath()) if (file.error() != QFile.NoError): self.d.mError = file.errorString() return False if (not file.commit()): self.d.mError = file.errorString() return False return True
def __init__(self, parent=None): self.mValues = QMap() self.mSuggestions = QMapList() self.mSuggestionsAttribute = QString() self.Data = VariantPropertyManager.Data() super().__init__(parent) self.mSuggestionsAttribute = "suggestions"
def addTile(self, image, source=QString()): newTile = Tile(image, source, self.tileCount(), self) self.mTiles.append(newTile) if (self.mTileHeight < image.height()): self.mTileHeight = image.height() if (self.mTileWidth < image.width()): self.mTileWidth = image.width() return newTile
def constructArgs(self, props, propOrder): argString = QString() # We work backwards so we don't have to include a bunch of nils for i in range(propOrder.size() - 1, -1, -1): currentValue = props.get(propOrder[i], '') # Special handling of the "additional" property if ((propOrder[i] == "additional") and currentValue.isEmpty()) : currentValue = self.constructAdditionalTable(props, propOrder) if (not argString.isEmpty()) : if (currentValue.isEmpty()) : currentValue = "nil" argString = "%s, %s"%(currentValue, argString) elif currentValue != '': argString = currentValue return argString
def constructArgs(self, props, propOrder): argString = QString() # We work backwards so we don't have to include a bunch of nils for i in range(propOrder.size() - 1, -1, -1): currentValue = props.get(propOrder[i], '') # Special handling of the "additional" property if ((propOrder[i] == "additional") and currentValue.isEmpty()): currentValue = self.constructAdditionalTable(props, propOrder) if (not argString.isEmpty()): if (currentValue.isEmpty()): currentValue = "nil" argString = "%s, %s" % (currentValue, argString) elif currentValue != '': argString = currentValue return argString
def __init__(self, map, fileName=QString()): super().__init__() ## # The filename of a plugin is unique. So it can be used to determine # the right plugin to be used for saving or reloading the map. # The nameFilter of a plugin can not be used, since it's translatable. # The filename of a plugin must not change while maps are open using this # plugin. ## self.mReaderFormat = None self.mWriterFormat = None self.mExportFormat = None self.mSelectedArea = QRegion() self.mSelectedObjects = QList() self.mSelectedTiles = QList() self.mCurrentLayerIndex = 0 self.mLastSaved = QDateTime() self.mLastExportFileName = '' self.mFileName = fileName self.mMap = map self.mLayerModel = LayerModel(self) self.mCurrentObject = map ## Current properties object. ## self.mRenderer = None self.mMapObjectModel = MapObjectModel(self) self.mTerrainModel = TerrainModel(self, self) self.mUndoStack = QUndoStack(self) self.createRenderer() if (map.layerCount() == 0): _x = -1 else: _x = 0 self.mCurrentLayerIndex = _x self.mLayerModel.setMapDocument(self) # Forward signals emitted from the layer model self.mLayerModel.layerAdded.connect(self.onLayerAdded) self.mLayerModel.layerAboutToBeRemoved.connect( self.onLayerAboutToBeRemoved) self.mLayerModel.layerRemoved.connect(self.onLayerRemoved) self.mLayerModel.layerChanged.connect(self.layerChanged) # Forward signals emitted from the map object model self.mMapObjectModel.setMapDocument(self) self.mMapObjectModel.objectsAdded.connect(self.objectsAdded) self.mMapObjectModel.objectsChanged.connect(self.objectsChanged) self.mMapObjectModel.objectsRemoved.connect(self.onObjectsRemoved) self.mMapObjectModel.rowsInserted.connect( self.onMapObjectModelRowsInserted) self.mMapObjectModel.rowsRemoved.connect( self.onMapObjectModelRowsInsertedOrRemoved) self.mMapObjectModel.rowsMoved.connect(self.onObjectsMoved) self.mTerrainModel.terrainRemoved.connect(self.onTerrainRemoved) self.mUndoStack.cleanChanged.connect(self.modifiedChanged) # Register tileset references tilesetManager = TilesetManager.instance() tilesetManager.addReferences(self.mMap.tilesets())
def makeTerrainAttribute(tile): terrain = QString() for i in range(4): if (i > 0): terrain += "," t = tile.cornerTerrainId(i) if (t > -1): terrain += str(t) return terrain
def __init__(self, *args): l = len(args) callback = Callback() shortName = QChar() longName = QString() help = QString() if l == 0: self.callback = 0 self.data = 0 elif l == 5: callback = args[0] data = args[1] shortName = args[2] longName = args[3] help = args[4] self.callback = callback self.data = data self.shortName = shortName self.longName = longName self.help = help
def __init__(self, name, tileWidth, tileHeight, tileSpacing = 0, margin = 0): super().__init__(Object.TilesetType) self.mName = name self.mTileWidth = tileWidth self.mTileHeight = tileHeight self.mTileSpacing = tileSpacing self.mMargin = margin self.mImageWidth = 0 self.mImageHeight = 0 self.mColumnCount = 0 self.mTerrainDistancesDirty = False self.mTileOffset = QPoint() self.mFileName = QString() self.mTiles = QList() self.mTransparentColor = QColor() self.mImageSource = QString() self.mTerrainTypes = QList() self.mWeakPointer = None
def readMap(self, device, path): self.mError = QString('') self.mPath = path map = None self.xml.setDevice(device) if (self.xml.readNextStartElement() and self.xml.name() == "map"): map = self.__readMap() else: self.xml.raiseError(self.tr("Not a map file.")) self.mGidMapper.clear() return map
def addRule(self): filter = self.tr("All Files (*)") filter += ";;" selectedFilter = self.tr("Tiled map files (*.tmx)") filter += selectedFilter fileNames, _ = QFileDialog.getOpenFileNames(self, self.tr("Open Map"), QString(), filter, selectedFilter) if len(fileNames) == 0: return self.mDataModel.insertFileNames(fileNames) self.ui.saveButton.setEnabled(True)
def __init__(self, mode, parent=None): super().__init__(QString(), QIcon(":images/24x24/insert-rectangle.png"), QKeySequence(self.tr("O")), parent) self.mNewMapObjectGroup = ObjectGroup() self.mObjectGroupItem = ObjectGroupItem(self.mNewMapObjectGroup) self.mNewMapObjectItem = None self.mOverlayPolygonItem = None self.mTile = None self.mMode = mode self.mObjectGroupItem.setZValue(10000) # same as the BrushItem
def __init__(self, object, mapDocument, parent=None): super().__init__(parent) self.mObject = object self.mMapDocument = mapDocument ## Bounding rect cached, for adapting to geometry change correctly. ## self.mBoundingRect = QRectF() self.mName = QString() self.mColor = QColor() self.mPolygon = QPolygonF() self.syncWithMapObject()
def toImageFileFilter(formats): filter = QString(QCoreApplication.translate("Utils", "Image files")) filter += " (" first = True for format in formats: format = format.data().decode() if (not first): filter += ' ' first = False filter += "*." filter += format.lower() filter += ')' return filter
def findStampFileName(name, currentFileName=''): invalidChars = QRegularExpression("[^\\w -]+") prefs = preferences.Preferences.instance() stampsDir = QDir(prefs.stampsDirectory()) suggestedFileName = name.toLower().remove(invalidChars) fileName = suggestedFileName + ".stamp" if (fileName == currentFileName or not stampsDir.exists(fileName)): return fileName n = 2 while (fileName != currentFileName and stampsDir.exists(fileName)): fileName = suggestedFileName + QString.number(n) + ".stamp" n += 1 return fileName
def __init__(self, *args): super().__init__(Object.MapObjectType) self.mPolygon = QPolygonF() self.mName = QString() self.mPos = QPointF() self.mCell = Cell() self.mType = QString() self.mId = 0 self.mShape = MapObject.Rectangle self.mObjectGroup = None self.mRotation = 0.0 self.mVisible = True l = len(args) if l == 0: self.mSize = QSizeF(0, 0) elif l == 4: name, _type, pos, size = args self.mName = name self.mType = _type self.mPos = pos self.mSize = QSizeF(size)
def constructAdditionalTable(self, props, propOrder): tableString = QString() unhandledProps = QMap(props) # Remove handled properties for i in range(0, propOrder.size()): unhandledProps.remove(propOrder[i]) # Construct the Lua string if (unhandledProps.size() > 0): tableString = "{" for i in unhandledProps: tableString = "%s%s=%s," % tableString, i[0], i[1] tableString = "%s}" % tableString return tableString
def stampAdded(self, stamp): if (stamp.name().isEmpty() or self.mStampsByName.contains(stamp.name())): # pick the first available stamp name name = QString() index = self.mTileStampModel.stamps().size() while (self.mStampsByName.contains(name)): name = str(index) index += 1 stamp.setName(name) self.mStampsByName.insert(stamp.name(), stamp) if (stamp.fileName().isEmpty()): stamp.setFileName(findStampFileName(stamp.name())) self.saveStamp(stamp)
def __init__(self, *args): self.mObjects = QList() self.mColor = QColor() l = len(args) if l == 0: super().__init__(Layer.ObjectGroupType, QString(), 0, 0, 0, 0) elif l == 5: ## # Constructor with some parameters. ## name, x, y, width, height = args super().__init__(Layer.ObjectGroupType, name, x, y, width, height) else: pass self.mDrawOrder = ObjectGroup.DrawOrder.IndexOrder
def addTerrainType(self, tile=None): if tile: x = tile.id() else: x = -1 terrain = Terrain(self.mTileset.terrainCount(), self.mTileset, QString(), x) terrain.setName(self.tr("New Terrain")) self.mMapDocument.undoStack().push( AddTerrain(self.mMapDocument, terrain)) # Select the newly added terrain and edit its name index = self.mTerrainModel.index(terrain) selectionModel = self.mUi.terrainList.selectionModel() selectionModel.setCurrentIndex( index, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) self.mUi.terrainList.edit(index)
def readMap(self, *args): l = len(args) if l == 2: device, path = args return self.d.readMap(device, path) elif l == 1: tp = type(args[0]) if tp == QIODevice: return self.d.readMap(device, QString()) elif tp in [QString, str]: ## # Reads a TMX map from the given \a fileName. # \overload ## fileName = args[0] file = QFile(fileName) if (not self.d.openFile(file)): return None return self.readMap(file, QFileInfo(fileName).absolutePath())
def __init__(self, *args): super().__init__(Object.TileType) l = len(args) if l==3: image, id, tileset = args self.mImageSource = QString() elif l==4: image, imageSource, id, tileset = args self.mImageSource = imageSource self.mId = id self.mTileset = tileset self.mImage = image self.mTerrain = 0xffffffff self.mProbability = 1.0 self.mObjectGroup = None self.mFrames = QVector() self.mCurrentFrameIndex = 0 self.mUnusedTime = 0
def data(self, index, role=Qt.DisplayRole): isNormalRow = index.row() < self.mCommands.size() command = Command() if (isNormalRow): command = self.mCommands[index.row()] x = role if x == Qt.DisplayRole or x == Qt.EditRole: if (isNormalRow): if (index.column() == CommandDataModel.NameColumn): return command.name if (index.column() == CommandDataModel.CommandColumn): return command.command else: if (index.column() == CommandDataModel.NameColumn): if (role == Qt.EditRole): return QString() else: return self.tr("<new command>") elif x == Qt.ToolTipRole: if (isNormalRow): if (index.column() == CommandDataModel.NameColumn): return self.tr("Set a name for this command") if (index.column() == CommandDataModel.CommandColumn): return self.tr("Set the shell command to execute") if (index.column() == CommandDataModel.EnabledColumn): return self.tr( "Show or hide this command in the command list") else: if (index.column() == CommandDataModel.NameColumn): return self.tr("Add a new command") elif x == Qt.CheckStateRole: if (isNormalRow and index.column() == CommandDataModel.EnabledColumn): if command.isEnabled: _x = 2 else: _x = 0 return _x return QVariant()
def writeTileset(self, writer, tileset, firstGid): writer.writeStartTable() writer.writeKeyAndValue("name", tileset.name()) writer.writeKeyAndValue("firstgid", firstGid) if tileset.fileName() != '': rel = self.mMapDir.relativeFilePath(tileset.fileName()) writer.writeKeyAndValue("filename", rel) ## # Include all tileset information even for external tilesets, since the # external reference is generally a .tsx file (in XML format). ## writer.writeKeyAndValue("tilewidth", tileset.tileWidth()) writer.writeKeyAndValue("tileheight", tileset.tileHeight()) writer.writeKeyAndValue("spacing", tileset.tileSpacing()) writer.writeKeyAndValue("margin", tileset.margin()) if tileset.imageSource() != '': rel = self.mMapDir.relativeFilePath(tileset.imageSource()) writer.writeKeyAndValue("image", rel) writer.writeKeyAndValue("imagewidth", tileset.imageWidth()) writer.writeKeyAndValue("imageheight", tileset.imageHeight()) if (tileset.transparentColor().isValid()): writer.writeKeyAndValue("transparentcolor",tileset.transparentColor().name()) offset = tileset.tileOffset() writer.writeStartTable("tileoffset") writer.writeKeyAndValue("x", offset.x()) writer.writeKeyAndValue("y", offset.y()) writer.writeEndTable() self.writeProperties(writer, tileset.properties()) writer.writeStartTable("terrains") for i in range(tileset.terrainCount()): t = tileset.terrain(i) writer.writeStartTable() writer.writeKeyAndValue("name", t.name()) writer.writeKeyAndValue("tile", t.imageTileId()) self.writeProperties(writer, t.properties()) writer.writeEndTable() writer.writeEndTable() writer.writeKeyAndValue("tilecount", tileset.tileCount()) writer.writeStartTable("tiles") for i in range(0, tileset.tileCount()): tile = tileset.tileAt(i) # For brevity only write tiles with interesting properties if (not includeTile(tile)): continue writer.writeStartTable() writer.writeKeyAndValue("id", i) if (not tile.properties().isEmpty()): self.writeProperties(writer, tile.properties()) if tile.imageSource() != '': src = self.mMapDir.relativeFilePath(tile.imageSource()) tileSize = tile.size() writer.writeKeyAndValue("image", src) if (not tileSize.isNull()) : writer.writeKeyAndValue("width", tileSize.width()) writer.writeKeyAndValue("height", tileSize.height()) terrain = tile.terrain() if (terrain != 0xFFFFFFFF) : writer.writeStartTable("terrain") writer.setSuppressNewlines(True) for i in range(0, 4): writer.writeValue(tile.cornerTerrainId(i)) writer.writeEndTable() writer.setSuppressNewlines(False) if (tile.probability() != 1.0): writer.writeKeyAndValue("probability", tile.probability()) objectGroup = tile.objectGroup() if objectGroup: self.writeObjectGroup(writer, objectGroup, "objectGroup") if (tile.isAnimated()) : frames = tile.frames() writer.writeStartTable("animation") for frame in frames: writer.writeStartTable() writer.writeKeyAndValue("tileid", QString.number(frame.tileId)) writer.writeKeyAndValue("duration", QString.number(frame.duration)) writer.writeEndTable() writer.writeEndTable() # animation writer.writeEndTable() # tile writer.writeEndTable() # tiles writer.writeEndTable() # tileset
def write(self, map, fileName): file = QSaveFile(fileName) if (not file.open(QIODevice.WriteOnly | QIODevice.Text)) : self.mError = self.tr("Could not open file for writing.") return False out = QTextStream(file) # Write the header header = map.property("header") for line in header.split("\\n"): out << line << '\n' width = map.width() height = map.height() asciiMap = QList() cachedTiles = QHash() propertyOrder = QList() propertyOrder.append("terrain") propertyOrder.append("object") propertyOrder.append("actor") propertyOrder.append("trap") propertyOrder.append("status") propertyOrder.append("spot") # Ability to handle overflow and strings for display outputLists = False asciiDisplay = ASCII_MIN overflowDisplay = 1 # Add the empty tile numEmptyTiles = 0 emptyTile = Properties() emptyTile["display"] = "?" cachedTiles["?"] = emptyTile # Process the map, collecting used display strings as we go for y in range(0, height): for x in range(0, width): currentTile = cachedTiles["?"] for layer in map.layers(): # If the layer name does not start with one of the tile properties, skip it layerKey = '' for currentProperty in propertyOrder: if (layer.name().lower().startswith(currentProperty.lower())) : layerKey = currentProperty break if layerKey == '': continue tileLayer = layer.asTileLayer() objectLayer = layer.asObjectGroup() # Process the Tile Layer if (tileLayer) : tile = tileLayer.cellAt(x, y).tile if (tile) : currentTile["display"] = tile.property("display") currentTile[layerKey] = tile.property("value") # Process the Object Layer elif (objectLayer) : for obj in objectLayer.objects(): if (math.floor(obj.y()) <= y and y <= math.floor(obj.y() + obj.height())) : if (math.floor(obj.x()) <= x and x <= math.floor(obj.x() + obj.width())) : # Check the Object Layer properties if either display or value was missing if (not obj.property("display").isEmpty()) : currentTile["display"] = obj.property("display") elif (not objectLayer.property("display").isEmpty()) : currentTile["display"] = objectLayer.property("display") if (not obj.property("value").isEmpty()) : currentTile[layerKey] = obj.property("value") elif (not objectLayer.property("value").isEmpty()) : currentTile[layerKey] = objectLayer.property("value") # If the currentTile does not exist in the cache, add it if (not cachedTiles.contains(currentTile["display"])) : cachedTiles[currentTile["display"]] = currentTile # Otherwise check that it EXACTLY matches the cached one # and if not... elif (currentTile != cachedTiles[currentTile["display"]]) : # Search the cached tiles for a match foundInCache = False displayString = QString() for i in cachedTiles.items(): displayString = i[0] currentTile["display"] = displayString if (currentTile == i[1]) : foundInCache = True break # If we haven't found a match then find a random display string # and cache it if (not foundInCache) : while (True) : # First try to use the ASCII characters if (asciiDisplay < ASCII_MAX) : displayString = asciiDisplay asciiDisplay += 1 # Then fall back onto integers else : displayString = QString.number(overflowDisplay) overflowDisplay += 1 currentTile["display"] = displayString if (not cachedTiles.contains(displayString)) : cachedTiles[displayString] = currentTile break elif (currentTile == cachedTiles[currentTile["display"]]) : break # Check the output type if len(currentTile["display"]) > 1: outputLists = True # Check if we are still the emptyTile if (currentTile == emptyTile) : numEmptyTiles += 1 # Finally add the character to the asciiMap asciiMap.append(currentTile["display"]) # Write the definitions to the file out << "-- defineTile section\n" for i in cachedTiles.items(): displayString = i[0] # Only print the emptyTile definition if there were empty tiles if (displayString == "?" and numEmptyTiles == 0) : continue # Need to escape " and \ characters displayString.replace('\\', "\\\\") displayString.replace('"', "\\\"") args = self.constructArgs(i[1], propertyOrder) if (not args.isEmpty()) : args = QString(", %1").arg(args) out << "defineTile(\"%s\"%s)\n"%(displayString, args) # Check for an ObjectGroup named AddSpot out << "\n-- addSpot section\n" for layer in map.layers(): objectLayer = layer.asObjectGroup() if (objectLayer and objectLayer.name().lower().startsWith("addspot")): for obj in objectLayer.objects(): propertyOrder = QList() propertyOrder.append("type") propertyOrder.append("subtype") propertyOrder.append("additional") args = self.constructArgs(obj.properties(), propertyOrder) if (not args.isEmpty()) : args = QString(", %1").arg(args) for y in range(math.floor(obj.y()), math.floor(obj.y() + obj.height())): for y in range(math.floor(obj.x()), math.floor(obj.x() + obj.width())): out << "addSpot({%s, %s}%s)\n"%(x, y, args) # Check for an ObjectGroup named AddZone out << "\n-- addZone section\n" for layer in map.layers(): objectLayer = layer.asObjectGroup() if (objectLayer and objectLayer.name().lower().startsWith("addzone")): for obj in objectLayer.objects(): propertyOrder = QList() propertyOrder.append("type") propertyOrder.append("subtype") propertyOrder.append("additional") args = self.constructArgs(obj.properties(), propertyOrder) if (not args.isEmpty()) : args = QString(", %1").arg(args) top_left_x = math.floor(obj.x()) top_left_y = math.floor(obj.y()) bottom_right_x = math.floor(obj.x() + obj.width()) bottom_right_y = math.floor(obj.y() + obj.height()) out << "addZone({%s, %s, %s, %s}%s)"%(top_left_x, top_left_y, bottom_right_x, bottom_right_y, args) # Write the map returnStart = QString() returnStop = QString() lineStart = QString() lineStop = QString() itemStart = QString() itemStop = QString() seperator = QString() if (outputLists) : returnStart = "{" returnStop = "}" lineStart = "{" lineStop = "}," itemStart = "[[" itemStop = "]]" seperator = "," else : returnStart = "[[" returnStop = "]]" lineStart = "" lineStop = "" itemStart = "" itemStop = "" seperator = "" out << "\n-- ASCII map section\n" out << "return " << returnStart << '\n' for y in range(0, height): out << lineStart for x in range(0, width): out << itemStart << asciiMap[x + (y * width)] << itemStop << seperator if (y == height - 1): out << lineStop << returnStop else : out << lineStop << '\n' if not file.commit(): self.mError = file.errorString() return False return True
def read(self, fileName): # Read data. file = QFile(fileName) if (not file.open(QIODevice.ReadOnly)): self.mError = self.tr("Cannot open Replica Island map file!") return 0 _in = QDataStream(file) _in.setByteOrder(QDataStream.LittleEndian) _in.setFloatingPointPrecision(QDataStream.SinglePrecision) # Parse file header. mapSignature = _in.readUInt8() layerCount = _in.readUInt8() backgroundIndex = _in.readUInt8() if (_in.status() == QDataStream.ReadPastEnd or mapSignature != 96): self.mError = self.tr("Can't parse file header!") return 0 # Create our map, setting width and height to 0 until we load a layer. map = Map(Map.Orientation.Orthogonal, 0, 0, 32, 32) map.setProperty("background_index", QString.number(backgroundIndex)) # Load our Tilesets. typeTilesets = QVector() tileIndexTilesets = QVector() self.loadTilesetsFromResources(map, typeTilesets, tileIndexTilesets) # Load each of our layers. for i in range(layerCount): # Parse layer header. _type = _in.readUInt8() tileIndex = _in.readUInt8() scrollSpeed = _in.readFloat() levelSignature = _in.readUInt8() width = _in.readUInt32() height = _in.readUInt32() if (_in.status() == QDataStream.ReadPastEnd or levelSignature != 42): self.mError = self.tr("Can't parse layer header!") return 0 # Make sure our width and height are consistent. if (map.width() == 0): map.setWidth(width) if (map.height() == 0): map.setHeight(height) if (map.width() != width or map.height() != height): self.mError = self.tr("Inconsistent layer sizes!") return 0 # Create a layer object. layer = TileLayer(self.layerTypeToName(_type), 0, 0, width, height) layer.setProperty("type", QString.number(_type)) layer.setProperty("tile_index", QString.number(tileIndex)) layer.setProperty("scroll_speed", QString.number(scrollSpeed, 'f')) map.addLayer(layer) # Look up the tileset for this layer. tileset = tilesetForLayer(_type, tileIndex, typeTilesets, tileIndexTilesets) # Read our tile data all at once. #tileData = QByteArray(width*height, b'\x00') bytesNeeded = width*height tileData = _in.readRawData(bytesNeeded) bytesRead = len(tileData) if (bytesRead != bytesNeeded): self.mError = self.tr("File ended in middle of layer!") return 0 i = 0 # Add the tiles to our layer. for y in range(0, height): for x in range(0, width): tile_id = tileData[i]&0xff i += 1 if (tile_id != 255): tile = tileset.tileAt(tile_id) layer.setCell(x, y, Cell(tile)) # Make sure we read the entire *.bin file. if (_in.status() != QDataStream.Ok or not _in.atEnd()): self.mError = self.tr("Unexpected data at end of file!") return 0 return map
def __toVariant(self, *args): l = len(args) if l==1: arg = args[0] tp = type(arg) if tp == Properties: properties = arg variantMap = {} for it in properties: variantMap[it[0]] = it[1] return variantMap elif tp == ObjectGroup: objectGroup = arg objectGroupVariant = {} objectGroupVariant["type"] = "objectgroup" if (objectGroup.color().isValid()): objectGroupVariant["color"] = objectGroup.color().name() objectGroupVariant["draworder"] = drawOrderToString(objectGroup.drawOrder()) self.addLayerAttributes(objectGroupVariant, objectGroup) objectVariants = [] for object in objectGroup.objects(): objectVariant = {} name = object.name() _type = object.type() objectVariant["properties"] = self.__toVariant(object.properties()) objectVariant["id"] = object.id() objectVariant["name"] = name objectVariant["type"] = _type if (not object.cell().isEmpty()): objectVariant["gid"] = self.mGidMapper.cellToGid(object.cell()) objectVariant["x"] = object.x() objectVariant["y"] = object.y() objectVariant["width"] = object.width() objectVariant["height"] = object.height() objectVariant["rotation"] = object.rotation() objectVariant["visible"] = object.isVisible() ## Polygons are stored in this format: # # "polygon/polyline": [ # { "x": 0, "y": 0 }, # { "x": 1, "y": 1 }, # ... # ] ## polygon = object.polygon() if (not polygon.isEmpty()) : pointVariants = [] for point in polygon: pointVariant = {} pointVariant["x"] = point.x() pointVariant["y"] = point.y() pointVariants.append(pointVariant) if (object.shape() == MapObject.Polygon): objectVariant["polygon"] = pointVariants else: objectVariant["polyline"] = pointVariants if (object.shape() == MapObject.Ellipse): objectVariant["ellipse"] = True objectVariants.append(objectVariant) objectGroupVariant["objects"] = objectVariants return objectGroupVariant elif tp == ImageLayer: imageLayer = arg imageLayerVariant = {} imageLayerVariant["type"] = "imagelayer" self.addLayerAttributes(imageLayerVariant, imageLayer) rel = self.mMapDir.relativeFilePath(imageLayer.imageSource()) imageLayerVariant["image"] = rel transColor = imageLayer.transparentColor() if (transColor.isValid()): imageLayerVariant["transparentcolor"] = transColor.name() return imageLayerVariant elif l==2: arg1, arg2 = args tp1 = type(arg1) tp2 = type(arg2) if tp1==Tileset and tp2==int: tileset, firstGid = arg1, arg2 tilesetVariant = {} if firstGid > 0: tilesetVariant["firstgid"] = firstGid fileName = tileset.fileName() if fileName != '': source = self.mMapDir.relativeFilePath(fileName) tilesetVariant["source"] = source # Tileset is external, so no need to write any of the stuff below return tilesetVariant tilesetVariant["firstgid"] = firstGid tilesetVariant["name"] = tileset.name() tilesetVariant["tilewidth"] = tileset.tileWidth() tilesetVariant["tileheight"] = tileset.tileHeight() tilesetVariant["spacing"] = tileset.tileSpacing() tilesetVariant["margin"] = tileset.margin() tilesetVariant["tilecount"] = tileset.tileCount() tilesetVariant["properties"] = self.__toVariant(tileset.properties()) offset = tileset.tileOffset() if (not offset.isNull()) : tileOffset = {} tileOffset["x"] = offset.x() tileOffset["y"] = offset.y() tilesetVariant["tileoffset"] = tileOffset # Write the image element imageSource = tileset.imageSource() if imageSource != '': rel = self.mMapDir.relativeFilePath(tileset.imageSource()) tilesetVariant["image"] = rel transColor = tileset.transparentColor() if (transColor.isValid()): tilesetVariant["transparentcolor"] = transColor.name() tilesetVariant["imagewidth"] = tileset.imageWidth() tilesetVariant["imageheight"] = tileset.imageHeight() ## # Write the properties, terrain, external image, object group and # animation for those tiles that have them. ## tilePropertiesVariant = {} tilesVariant = {} for i in range(0, tileset.tileCount()): tile = tileset.tileAt(i) properties = tile.properties() if (not properties.isEmpty()): tilePropertiesVariant[QString.number(i)] = self.__toVariant(properties) tileVariant = {} if (tile.terrain() != 0xFFFFFFFF) : terrainIds = [] for j in range(0, 4): terrainIds.append(tile.cornerTerrainId(j)) tileVariant["terrain"] = terrainIds if (tile.probability() != 1.0): tileVariant["probability"] = tile.probability() if tile.imageSource() != '': rel = self.mMapDir.relativeFilePath(tile.imageSource()) tileVariant["image"] = rel if (tile.objectGroup()): tileVariant["objectgroup"] = self.__toVariant(tile.objectGroup()) if (tile.isAnimated()) : frameVariants = [] for frame in tile.frames(): frameVariant = {} frameVariant["tileid"] = frame.tileId frameVariant["duration"] = frame.duration frameVariants.append(frameVariant) tileVariant["animation"] = frameVariants if len(tileVariant) > 0: tilesVariant[QString.number(i)] = tileVariant if len(tilePropertiesVariant) > 0: tilesetVariant["tileproperties"] = tilePropertiesVariant if len(tilesVariant) > 0: tilesetVariant["tiles"] = tilesVariant # Write terrains if (tileset.terrainCount() > 0) : terrainsVariant = [] for i in range(0, tileset.terrainCount()): terrain = tileset.terrain(i) properties = terrain.properties() terrainVariant = {} terrainVariant["name"] = terrain.name() if (not properties.isEmpty()): terrainVariant["properties"] = self.__toVariant(properties) terrainVariant["tile"] = terrain.imageTileId() terrainsVariant.append(terrainVariant) tilesetVariant["terrains"] = terrainsVariant return tilesetVariant elif tp1==TileLayer and tp2==Map.LayerDataFormat: tileLayer, format = arg1, arg2 tileLayerVariant = {} tileLayerVariant["type"] = "tilelayer" self.addLayerAttributes(tileLayerVariant, tileLayer) if format == Map.LayerDataFormat.XML or format == Map.LayerDataFormat.CSV: tileVariants = [] for y in range(tileLayer.height()): for x in range(tileLayer.width()): tileVariants.append(self.mGidMapper.cellToGid(tileLayer.cellAt(x, y))) tileLayerVariant["data"] = tileVariants elif format in [Map.LayerDataFormat.Base64, Map.LayerDataFormat.Base64Zlib, Map.LayerDataFormat.Base64Gzip]: tileLayerVariant["encoding"] = "base64" if format == Map.LayerDataFormat.Base64Zlib: tileLayerVariant["compression"] = "zlib" elif format == Map.LayerDataFormat.Base64Gzip: tileLayerVariant["compression"] = "gzip" layerData = self.mGidMapper.encodeLayerData(tileLayer, format) tileLayerVariant["data"] = layerData.data().decode() return tileLayerVariant
def read(self, fileName): file = QFile(fileName) if (not file.open (QIODevice.ReadOnly)): self.mError = self.tr("Could not open file for reading.") return None # default to values of the original flare alpha game. map = Map(Map.Orientation.Isometric, 256, 256, 64, 32) stream = QTextStream(file) line = QString() sectionName = QString() newsection = False path = QFileInfo(file).absolutePath() base = 10 gidMapper = GidMapper() gid = 1 tilelayer = None objectgroup = None mapobject = None tilesetsSectionFound = False headerSectionFound = False tilelayerSectionFound = False # tile layer or objects while (not stream.atEnd()): line = stream.readLine() if line == '': continue startsWith = line[0] if (startsWith == '['): sectionName = line[1:line.index(']')] newsection = True continue if (sectionName == "header"): headerSectionFound = True #get map properties epos = line.index('=') if (epos != -1): key = line[:epos].strip() value = line[epos + 1:].strip() if (key == "width"): map.setWidth(Int(value)) elif (key == "height"): map.setHeight(Int(value)) elif (key == "tilewidth"): map.setTileWidth(Int(value)) elif (key == "tileheight"): map.setTileHeight(Int(value)) elif (key == "orientation"): map.setOrientation(orientationFromString(value)) else: map.setProperty(key, value) elif (sectionName == "tilesets"): tilesetsSectionFound = True epos = line.index('=') key = line[:epos].strip() value = line[epos + 1:].strip() if (key == "tileset"): _list = value.split(',') absoluteSource = _list[0] if (QDir.isRelativePath(absoluteSource)): absoluteSource = path + '/' + absoluteSource tilesetwidth = 0 tilesetheight = 0 if len(_list) > 2: tilesetwidth = Int(_list[1]) tilesetheight = Int(_list[2]) tileset = Tileset.create(QFileInfo(absoluteSource).fileName(), tilesetwidth, tilesetheight) ok = tileset.loadFromImage(absoluteSource) if not ok: self.mError = self.tr("Error loading tileset %s, which expands to %s. Path not found!"%(_list[0], absoluteSource)) return None else : if len(_list) > 4: tileset.setTileOffset(QPoint(Int(_list[3]),Int(_list[4]))) gidMapper.insert(gid, tileset) if len(_list) > 5: gid += Int(_list[5]) else : gid += tileset.tileCount() map.addTileset(tileset) elif (sectionName == "layer"): if (not tilesetsSectionFound): self.mError = self.tr("No tilesets section found before layer section.") return None tilelayerSectionFound = True epos = line.index('=') if (epos != -1): key = line[:epos].strip() value = line[epos + 1:].strip() if (key == "type"): tilelayer = TileLayer(value, 0, 0, map.width(),map.height()) map.addLayer(tilelayer) elif (key == "format"): if (value == "dec"): base = 10 elif (value == "hex"): base = 16 elif (key == "data"): for y in range(map.height()): line = stream.readLine() l = line.split(',') for x in range(min(map.width(), len(l))): ok = False tileid = int(l[x], base) c, ok = gidMapper.gidToCell(tileid) if (not ok): self.mError += self.tr("Error mapping tile id %1.").arg(tileid) return None tilelayer.setCell(x, y, c) else : tilelayer.setProperty(key, value) else : if (newsection): if (map.indexOfLayer(sectionName) == -1): objectgroup = ObjectGroup(sectionName, 0,0,map.width(), map.height()) map.addLayer(objectgroup) else : objectgroup = map.layerAt(map.indexOfLayer(sectionName)) mapobject = MapObject() objectgroup.addObject(mapobject) newsection = False if (not mapobject): continue if (startsWith == '#'): name = line[1].strip() mapobject.setName(name) epos = line.index('=') if (epos != -1): key = line[:epos].strip() value = line[epos + 1:].strip() if (key == "type"): mapobject.setType(value) elif (key == "location"): loc = value.split(',') x,y = 0.0, 0.0 w,h = 0, 0 if (map.orientation() == Map.Orthogonal): x = loc[0].toFloat()*map.tileWidth() y = loc[1].toFloat()*map.tileHeight() if len(loc) > 3: w = Int(loc[2])*map.tileWidth() h = Int(loc[3])*map.tileHeight() else : w = map.tileWidth() h = map.tileHeight() else : x = loc[0].toFloat()*map.tileHeight() y = loc[1].toFloat()*map.tileHeight() if len(loc) > 3: w = Int(loc[2])*map.tileHeight() h = Int(loc[3])*map.tileHeight() else : w = h = map.tileHeight() mapobject.setPosition(QPointF(x, y)) mapobject.setSize(w, h) else : mapobject.setProperty(key, value) if (not headerSectionFound or not tilesetsSectionFound or not tilelayerSectionFound): self.mError = self.tr("This seems to be no valid flare map. " "A Flare map consists of at least a header " "section, a tileset section and one tile layer.") return None return map