diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/exporter.py | 192 | ||||
-rw-r--r-- | src/ui.py | 4 |
2 files changed, 145 insertions, 51 deletions
diff --git a/src/exporter.py b/src/exporter.py index 4026929..0c24d50 100644 --- a/src/exporter.py +++ b/src/exporter.py @@ -1,8 +1,15 @@ from common import * import array import sys +import math from ctypes import create_string_buffer +# Useful Stuff +u32 = struct.Struct('>I') +u16 = struct.Struct('>H') +zero32 = u32.pack(0) + + def RGB5A3Encode(tex): tex = tex.toImage() w, h = tex.width(), tex.height() @@ -54,7 +61,8 @@ class KPMapExporter: class LayerExporter: def __init__(self, layer): self.layer = layer - + + class TileLayerExporter(LayerExporter): def buildSectors(self, sectors, indices): # we'll use the cache held by the layer: why reinvent the wheel? layer = self.layer @@ -67,8 +75,8 @@ class KPMapExporter: sectorLeft = layerX / 16 sectorTop = layerY / 16 - sectorRight = (layerX + layerWidth) / 16 - sectorBottom = (layerY + layerHeight) / 16 + sectorRight = (layerX + layerWidth - 1) / 16 + sectorBottom = (layerY + layerHeight - 1) / 16 rawSectors = [] for i in xrange(sectorBottom - sectorTop + 1): @@ -100,7 +108,7 @@ class KPMapExporter: # now add the created sectors to the data count = reduce(lambda x,y: x+len(y), rawSectors, 0) - sectorMap = [-1 for i in xrange(count)] + sectorMap = [0xFFFF for i in xrange(count)] destIdx = 0 for srcRow in rawSectors: @@ -119,23 +127,52 @@ class KPMapExporter: destIdx += 1 self.sectorBounds = (sectorLeft, sectorTop, sectorRight, sectorBottom) + self.realBounds = (layerX, layerY, layerX+layerWidth-1, layerY+layerHeight-1) self.sectorMap = sectorMap + class DoodadLayerExporter(LayerExporter): + pass + + class PathLayerExporter(LayerExporter): + pass + def __init__(self, mapObj): self.map = mapObj - self.layers = map(KPMapExporter.LayerExporter, self.map.layers) + self.tileAssociates = {} + self.doodadAssociates = {} - def build(self): - u32 = struct.Struct('>I') - u16 = struct.Struct('>H') - zero32 = u32.pack(0) + output = [] + for layer in self.map.layers: + if isinstance(layer, KPTileLayer) and len(layer.objects) > 0: + output.append(KPMapExporter.TileLayerExporter(layer)) + + elif isinstance(layer, KPDoodadLayer) and len(layer.objects) > 0: + output.append(KPMapExporter.DoodadLayerExporter(layer)) + + elif isinstance(layer, KPPathLayer): + for iLayer in self.map.associateLayers: + if len(iLayer.objects) > 0: + tl = KPMapExporter.TileLayerExporter(iLayer) + self.tileAssociates[iLayer.associate] = tl + output.append(tl) + + if len(iLayer.doodads) > 0: + dl = KPMapExporter.DoodadLayerExporter(iLayer) + self.doodadAssociates[iLayer.associate] = dl + output.append(dl) + + output.append(KPMapExporter.PathLayerExporter(layer)) + self.layers = output + + def build(self): requiredFixUps = [] stringsToAdd = set() textures = set() + tilesets = set() offsets = {None: 0xFFFFFFFF} # first off, build the sectors @@ -143,7 +180,7 @@ class KPMapExporter: sectorIndices = {} for layer in self.layers: - if isinstance(layer.layer, KPTileLayer): + if isinstance(layer, self.TileLayerExporter): layer.buildSectors(sectors, sectorIndices) sectorData = self._packSectorData(sectors) @@ -158,6 +195,22 @@ class KPMapExporter: requiredFixUps.append((len(data), layer)) data += zero32 + # map all paths to unlock info + unlockInfo = {} + + for node in self.map.pathLayer.nodes: + if not node.level: continue + + checked = set() + affected = [] + self._findUnlocksForNode(node, checked, affected) + + level1, level2 = node.level + + for item, secret in affected: + unlockInfo[item] = (level1, level2, secret) + + # now build the layers for eLayer in self.layers: layer = eLayer.layer @@ -165,32 +218,40 @@ class KPMapExporter: offsets[eLayer] = len(data) offsets[layer] = len(data) - if isinstance(layer, KPTileLayer): + if isinstance(eLayer, self.TileLayerExporter): data += u32.pack(0) # tileset name - stringsToAdd.add(layer.tileset) - requiredFixUps.append((len(data), layer.tileset)) + tileset = '/Maps/%s.bin' % layer.tileset + tilesets.add(tileset) + stringsToAdd.add(tileset) + requiredFixUps.append((len(data), ('tileset', tileset))) data += zero32 # sector info data += struct.pack('>IIII', *eLayer.sectorBounds) + data += struct.pack('>IIII', *eLayer.realBounds) data += ''.join(map(u16.pack, eLayer.sectorMap)) pad = (4 - (len(data) & 3)) % 4 data += ('\0' * pad) - elif isinstance(layer, KPDoodadLayer): + elif isinstance(eLayer, self.DoodadLayerExporter): data += u32.pack(1) # doodad list - data += u32.pack(len(layer.objects)) - for doodad in layer.objects: + try: + doodadList = layer.doodads + except AttributeError: + doodadList = layer.objects + + data += u32.pack(len(doodadList)) + for doodad in doodadList: requiredFixUps.append((len(data), doodad)) data += zero32 # now pack them ... - for doodad in layer.objects: + for doodad in doodadList: offsets[doodad] = len(data) x, y = doodad.position @@ -207,9 +268,9 @@ class KPMapExporter: loopid = self.ANIM_LOOPS.index(rLoop) curveid = self.ANIM_CURVES.index(rCurve) typeid = self.ANIM_TYPES.index(rType) - data += struct.pack('>iififf', loopid, curveid, rFrames, typeid, rStart, rEnd) + data += struct.pack('>iiiiiiii', loopid, curveid, rFrames, typeid, rStart, rEnd, 0, 0) - elif isinstance(layer, KPPathLayer): + elif isinstance(eLayer, self.PathLayerExporter): data += u32.pack(2) # lists @@ -232,14 +293,48 @@ class KPMapExporter: x, y = node.position current = len(data) - data += struct.pack('>hhiiii', x, y, 0, 0, 0, 0) + data += struct.pack('>hhiiiiii', x+12, y+12, 0, 0, 0, 0, 0, 0) + + # this varies + if node.isStop(): + # figure out the exits by direction + leftExit, rightExit, upExit, downExit = None, None, None, None + + for exit in node.exits: + start, end = exit._startNodeRef(), exit._endNodeRef() + opposite = end if (start == node) else start + + oX, oY = opposite.position + deltaX, deltaY = oX-x, oY-y + angle = math.degrees(math.atan2(deltaX, deltaY)) % 360 + print "Here: %d,%d Opposite %d,%d Delta: %d,%d Angle: %d" % (x,y,oX,oY,deltaX,deltaY,angle) + + # Left = 270, Right = 90, Up = 180, Down = 0 + if angle >= 225 and angle <= 315: + leftExit = exit + elif angle >= 45 and angle <= 135: + rightExit = exit + elif angle > 135 and angle < 225: + upExit = exit + elif angle > 315 or angle < 45: + downExit = exit + + exits = [leftExit, rightExit, upExit, downExit] + + else: + # not a stop, so just dump them in + exits = node.exits + [None,None,None,None] - exits = node.exits + [None,None,None,None] # TODO requiredFixUps.append((current+4, exits[0])) requiredFixUps.append((current+8, exits[1])) requiredFixUps.append((current+12, exits[2])) requiredFixUps.append((current+16, exits[3])) + if node in self.tileAssociates: + requiredFixUps.append((current+20, self.tileAssociates[node])) + if node in self.doodadAssociates: + requiredFixUps.append((current+24, self.doodadAssociates[node])) + if node.isStop(): if node.level: level1, level2 = node.level @@ -269,29 +364,20 @@ class KPMapExporter: requiredFixUps.append((current, start)) requiredFixUps.append((current+4, end)) - requiredFixUps.append((current+8, path.linkedLayer)) - data += (zero32 * 3) - - data += struct.pack('>fi', path.movementSpeed, path.animation) - - # unlocking paths/nodes! - unlocks = [] - us = struct.Struct('>bbbbi') - - for node in self.map.pathLayer.nodes: - if not node.level: continue - - checked = set() - affected = [] - self._findUnlocksForNode(node, checked, affected, True) + if path in self.tileAssociates: + requiredFixUps.append((current+8, self.tileAssociates[path])) + if path in self.doodadAssociates: + requiredFixUps.append((current+12, self.doodadAssociates[path])) - level1, level2 = node.level + data += (zero32 * 4) - for item, secret in affected: - unlocks.append(us.pack(secret, level1, level2, 0, offsets[item])) + try: + unlockL1, unlockL2, isSecret = unlockInfo[path] + unlockType = (2 if isSecret else 1) + except KeyError: + unlockL1, unlockL2, unlockType = 0, 0, 0 - struct.pack_into('>ii', data, 8, len(unlocks), len(data)) - data += ''.join(unlocks) + data += struct.pack('>bbbbfi', unlockType, unlockL1, unlockL2, 1, path.movementSpeed, path.animation) # now that we're almost done... pack the strings for string in stringsToAdd: @@ -300,16 +386,21 @@ class KPMapExporter: data += '\0' # textures - texHeaderStartOffset = len(data) - texHeaderEndOffset = texHeaderStartOffset + (len(textures) * 0x20) + texPadding = ((len(data) + 0x1F) & ~0x1F) - len(data) + data += ('\0' * texPadding) - texDataStartOffset = (texHeaderEndOffset + 0x1F) & ~0x1F - texPadding = texDataStartOffset - texHeaderEndOffset + texHeaderStartOffset = len(data) + texDataStartOffset = texHeaderStartOffset + ((len(textures) + len(tilesets)) * 0x20) currentTexOffset = texDataStartOffset imageData = [] + struct.pack_into('>ii', data, 8, len(textures), len(data)) + for setname in tilesets: + offsets[('tileset', setname)] = len(data) + data += self._buildGXTexObjRGB5A3(1024, 512, offsets[setname]) + for tex in textures: offsets[tex] = len(data) data += self._buildGXTexObjRGB5A3(tex.width(), tex.height(), currentTexOffset) @@ -318,7 +409,6 @@ class KPMapExporter: imageData.append(converted) currentTexOffset += len(converted) - data += ('\0' * texPadding) for piece in imageData: data += piece @@ -333,7 +423,7 @@ class KPMapExporter: ANIM_TYPES = ['X Position', 'Y Position', 'Angle', 'X Scale', 'Y Scale', 'Opacity'] - def _findUnlocksForNode(self, node, checked, affected, isFirstBranch=False, secret=None): + def _findUnlocksForNode(self, node, checked, affected, isFirstBranch=True, secret=None): if node in checked: return checked.add(node) @@ -367,11 +457,11 @@ class KPMapExporter: # Format: RGB5A3 (5) # Wrap: CLAMP (0) return struct.pack('>IIIIIIIHH', - 0x10, 0, - (0x20000 | ((height - 1) << 10) | (width - 1)), - imgOffset, # (imgptr >> 5) + 0x90, 0, + (0x500000 | ((height - 1) << 10) | (width - 1)), + 0x10000000 + imgOffset, # (imgptr >> 5) 0, 0, 0, - (((width + 3) / 4) * ((height + 3) / 4)) & 0x1FFFF, + (((width + 3) / 4) * ((height + 3) / 4)) & 0x7FFF, 0x0202 ) @@ -328,21 +328,25 @@ class KPLayerList(QtGui.QWidget): def moveUp(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, index - 1) + self.setButtonStates() KP.mainWindow.editor.viewport().update() def moveDown(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, index + 2) + self.setButtonStates() KP.mainWindow.editor.viewport().update() def moveTop(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, 0) + self.setButtonStates() KP.mainWindow.editor.viewport().update() def moveBottom(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, len(KP.map.layers)) + self.setButtonStates() KP.mainWindow.editor.viewport().update() |