diff options
Diffstat (limited to 'src/mapdata.py')
-rw-r--r-- | src/mapdata.py | 255 |
1 files changed, 247 insertions, 8 deletions
diff --git a/src/mapdata.py b/src/mapdata.py index de00b10..1eb35c8 100644 --- a/src/mapdata.py +++ b/src/mapdata.py @@ -1,11 +1,31 @@ from common import * import weakref +import mapfile +import base64 TILE_SIZE = (24,24) MAP_SIZE_IN_TILES = (512,512) MAP_SIZE = (MAP_SIZE_IN_TILES[0] * TILE_SIZE[0], MAP_SIZE_IN_TILES[1] * TILE_SIZE[1]) +@mapfile.dumpClassAs(QtGui.QPixmap, 'pixmap') +def dumpPixmap(pm): + buf = QtCore.QBuffer() + buf.open(buf.WriteOnly) + pm.save(buf, 'PNG') + data = str(buf.data()) + buf.close() + return {'png': base64.b64encode(data)} + +@mapfile.loadClassFrom('pixmap') +def loadPixmap(source): + pm = QtGui.QPixmap() + pm.loadFromData(base64.b64decode(source['png']), 'PNG') + return pm + +@mapfile.dumpable('layer') class KPLayer(object): + __dump_attribs__ = ('name', '_visible') + def __repr__(self): return "<KPLayer %r>" % self.name @@ -42,7 +62,17 @@ class KPLayer(object): item.setFlag(flag2, value) +@mapfile.dumpable('object') class KPObject(object): + __dump_attribs__ = ('position', 'size', 'tileset') + + def _load(self, mapObj, src): + self.kind = mapObj.loadedTilesets[self.tileset].objects[src['kind']] + self.updateCache() + + def _dump(self, mapObj, dest): + dest['kind'] = mapObj.loadedTilesets[self.tileset].objects.index(self.kind) + def __init__(self): self.position = (0,0) self.size = (1,1) @@ -55,7 +85,13 @@ class KPObject(object): self.cache = self.kind.render(self.size) +@mapfile.dumpable('tile_layer') class KPTileLayer(KPLayer): + __dump_attribs__ = KPLayer.__dump_attribs__ + ('tileset', 'objects') + + def _load(self, mapObj, src): + self.updateCache() + def __repr__(self): return "<KPTileLayer %r with %r>" % (self.name, self.tileset) @@ -127,21 +163,84 @@ class KPTileLayer(KPLayer): y += 1 +@mapfile.dumpable('doodad') class KPDoodad(object): + __dump_attribs__ = ('position', 'size', 'angle', 'animations') + + def _dump(self, mapObj, dest): + dest['sourceRef'] = mapObj.refDoodad(self.source) + + def _load(self, mapObj, src): + self.source = mapObj.derefDoodad(src['sourceRef']) + def __init__(self): self.position = [0,0] self.size = [0,0] self.angle = 0 - self.index = 0 + self.source = None self.animations = [] - + self.timelines = None + def setDefaultSize(self): - source = KP.mainWindow.doodadSelector.getDoodad(self.index) - pixmap = source.icon().pixmap(source.icon().availableSizes()[0]) + pixmap = self.source[1] self.size = [pixmap.width(), pixmap.height()] + def cleanUpAnimations(self): + myTimelines = self.timelines + if myTimelines is None: return + + timelineList = KP.mapScene.timeLines + + for timeline in myTimelines: + try: + timelineList.remove(timeline) + except ValueError: + pass + + self.timelines = None + + def setupAnimations(self): + self.cleanUpAnimations() + timelineList = KP.mapScene.timeLines + myTimelines = [] + + for anim in self.animations: + Loop, Curve, Frames, Type, StartVal, EndVal = anim + + Timeline = QtCore.QTimeLine() + + # Interpolate the correct modifier + if Curve == "Linear": + Timeline.setCurveShape(3) + elif Curve == "Sinusoidial": + Timeline.setCurveShape(4) + elif Curve == "Cosinoidial": + Timeline.setCurveShape(5) + + Timeline.setFrameRange(StartVal, EndVal) + + if Loop == "Contiguous": + Timeline.setLoopCount(1) + elif Loop == "Loop": + Timeline.setLoopCount(0) # Dollars *holds pinky to corner of mouth* + elif Loop == "Reversible Loop": + Timeline.setLoopCount(1) + Timeline.finished.connect(Timeline.toggleDirection) + Timeline.finished.connect(Timeline.start) + + Timeline.setDuration(Frames/60.0*1000) # Wii goes at 60 frames per second + + timelineList.append(Timeline) + myTimelines.append(Timeline) + + self.timelines = myTimelines + + +@mapfile.dumpable('doodad_layer') class KPDoodadLayer(KPLayer): + __dump_attribs__ = KPLayer.__dump_attribs__ + ('objects',) + def __repr__(self): return "<KPDoodadLayer %r>" % self.name @@ -163,7 +262,20 @@ class KPNodeAction(object): pass +@mapfile.dumpable('node') class KPNode(object): + __dump_attribs__ = ( + 'position', 'actions', 'level', 'isStop', 'mapChange', + 'transition', 'mapID', 'foreignID') + + def _dump(self, mapObj, dest): + dest['exitIDs'] = map(mapObj.refPath, self.exits) + + def _load(self, mapObj, src): + self.exitIDs = src['exitIDs'] + # The exits array will be created by KPPathLayer._load after the + # paths have all been created. + def __init__(self): self.position = (0,0) self.actions = [] @@ -176,8 +288,27 @@ class KPNode(object): self.foreignID = None +@mapfile.dumpable('path') class KPPath(object): - def __init__(self, startNode, endNode, cloneFrom=None): + __dump_attribs__ = ('unlocks', 'secret', 'animation', 'movementSpeed') + + def _dump(self, mapObj, dest): + dest['startNodeLink'] = mapObj.refNode(self._startNodeRef()) + dest['endNodeLink'] = mapObj.refNode(self._endNodeRef()) + dest['linkedLayer'] = mapObj.refLayer(self.linkedLayer) + + def _load(self, mapObj, src): + self._startNodeRef = weakref.ref(mapObj.derefNode(src['startNodeLink'])) + self._endNodeRef = weakref.ref(mapObj.derefNode(src['endNodeLink'])) + self.linkedLayer = mapObj.derefLayer(src['linkedLayer']) + + def __init__(self, startNode=None, endNode=None, cloneFrom=None): + if startNode is None and endNode is None: + # null ctor, ignore this + # we're probably loaded from a file, so trust + # that everything is correct ... _load will set it all up + return + self._startNodeRef = weakref.ref(startNode) self._endNodeRef = weakref.ref(endNode) @@ -213,7 +344,15 @@ class KPPath(object): self._endNodeRef = weakref.ref(newEnd) +@mapfile.dumpable('path_layer') class KPPathLayer(KPLayer): + __dump_attribs__ = KPLayer.__dump_attribs__ + ('nodes', 'paths') + + def _load(self, mapObj, src): + for node in self.nodes: + node.exits = map(mapObj.derefPath, node.exitIDs) + del node.exitIDs + def __repr__(self): return "<KPPathLayer %r>" % self.name @@ -241,15 +380,41 @@ class KPPathLayer(KPLayer): item.setFlag(flag, value) +@mapfile.dumpable('map_root') class KPMap(object): + __dump_attribs__ = ('layers', 'nextLayerNumber', 'doodadDefinitions') + + def _preload(self, src): + # we need this early so we can use the deref methods! + for layer in self.layers: + if isinstance(layer, KPPathLayer): + self.pathLayer = layer + + def _load(self, mapObj, source): + self.layerModel.list = self.layers + self.doodadModel.list = self.doodadDefinitions + + def save(self): + path = self.filePath + if path is None: + raise "no path specified for this map" + + import mapfile + dumped = mapfile.dump(self) + open(path, 'wb').write(dumped) + def __init__(self): + self.filePath = None + self.nextLayerNumber = 1 self.pathLayer = self._createPathLayer() self.layers = [self.pathLayer] self.layerModel = KPMap.LayerModel(self.layers) - self.nodes = [] - self.paths = [] + + self.doodadDefinitions = [] + self.doodadModel = KPMap.DoodadModel(self.doodadDefinitions) + self.tilesets = {} self.loadedTilesets = {} @@ -311,7 +476,6 @@ class KPMap(object): return False - def _createPathLayer(self): layer = KPPathLayer() layer.name = 'Paths' @@ -373,6 +537,81 @@ class KPMap(object): self.layerModel.endRemoveRows() + # DOODADS + class DoodadModel(QtCore.QAbstractListModel): + def __init__(self, doodadList): + QtCore.QAbstractListModel.__init__(self) + self.list = doodadList + + + def headerData(self, section, orientation, role = Qt.DisplayRole): + return 'Doodad' + + def rowCount(self, parent): + return len(self.list) + + def data(self, index, role = Qt.DisplayRole): + try: + if index.isValid(): + doodad = self.list[index.row()] + + if role == Qt.DecorationRole: + return doodad[1] + elif role == Qt.ToolTipRole: + return doodad[0] + + except IndexError: + pass + + return QtCore.QVariant() + + def flags(self, index): + if not index.isValid(): + return Qt.ItemIsEnabled + return QtCore.QAbstractListModel.flags(self, index) + + def addDoodad(self, title, image): + doodad = (title, image) + + index = len(self.doodadDefinitions) + self.doodadModel.beginInsertRows(QtCore.QModelIndex(), index, index) + self.doodadDefinitions.append(doodad) + self.doodadModel.endInsertRows() + + return doodad + + def removeDoodad(self, doodad): + if doodad not in self.doodadDefinitions: + raise ValueError + + index = self.doodadDefinitions.index(doodad) + self.doodadModel.beginRemoveRows(QtCore.QModelIndex(), index, index) + del self.doodadDefinitions[index] + self.doodadModel.endRemoveRows() + + + # REFERENCES + def refDoodad(self, doodad): + return -1 if (doodad is None) else self.doodadDefinitions.index(doodad) + def derefDoodad(self, ref): + return self.doodadDefinitions[ref] if (ref >= 0) else None + + def refLayer(self, layer): + return -1 if (layer is None) else self.layers.index(layer) + def derefLayer(self, ref): + return self.layers[ref] if (ref >= 0) else None + + def refPath(self, path): + return -1 if (path is None) else self.pathLayer.paths.index(path) + def derefPath(self, ref): + return self.pathLayer.paths[ref] if (ref >= 0) else None + + def refNode(self, node): + return -1 if (node is None) else self.pathLayer.nodes.index(node) + def derefNode(self, ref): + return self.pathLayer.nodes[ref] if (ref >= 0) else None + + # TILESETS def loadTilesets(self): import os from hashlib import sha256 as sha |