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 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
Exemple #3
0
    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
Exemple #5
0
    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
Exemple #6
0
    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
Exemple #7
0
    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 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