summaryrefslogtreecommitdiff
path: root/src/exporter.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/exporter.py')
-rw-r--r--src/exporter.py135
1 files changed, 75 insertions, 60 deletions
diff --git a/src/exporter.py b/src/exporter.py
index 2396633..2f99a56 100644
--- a/src/exporter.py
+++ b/src/exporter.py
@@ -191,7 +191,8 @@ class KPMapExporter:
sectorData = self._packSectorData(sectors)
# now that we've got that, we can pack the first part of the file
- data = bytearray(struct.pack('>IIII', len(self.layers), 16 + len(sectorData), 0, 0))
+ data = bytearray(struct.pack('>IIIII', len(self.layers), 20 + len(sectorData), 0, 0, 0))
+ requiredFixUps.append((16, 'UnlockBytecode'))
# list of layer pointers goes here.. or will, later
data += sectorData
@@ -200,22 +201,6 @@ 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
@@ -225,6 +210,7 @@ class KPMapExporter:
if isinstance(eLayer, self.TileLayerExporter):
data += u32.pack(0)
+ data += u32.pack(0xFF000000)
# tileset name
tileset = '/Maps/Texture/%s.bin' % layer.tileset
@@ -243,6 +229,7 @@ class KPMapExporter:
elif isinstance(eLayer, self.DoodadLayerExporter):
data += u32.pack(1)
+ data += u32.pack(0xFF000000)
# doodad list
try:
@@ -277,6 +264,15 @@ class KPMapExporter:
elif isinstance(eLayer, self.PathLayerExporter):
data += u32.pack(2)
+ data += zero32
+
+ # before we do anything, build the list of secret levels
+ # we'll need that
+ levelsWithSecrets = set()
+
+ for path in layer.paths:
+ if hasattr(path, 'unlockSpec') and path.unlockSpec is not None:
+ self._checkSpecForSecrets(path.unlockSpec, levelsWithSecrets)
# lists
current = len(data)
@@ -343,8 +339,9 @@ class KPMapExporter:
if node.isStop():
if node.level:
level1, level2 = node.level
- # i i b b b b: node type, Extra pointer, world, level, padding (hasSecret?), padding
- data += struct.pack('>iibbbb', 2, 0, level1, level2, 0, 0)
+ hasSecret = (1 if ((level1,level2) in levelsWithSecrets) else 0)
+ # i i i b b b b: node type, isNew, Extra pointer, world, level, hasSecret, padding
+ data += struct.pack('>iiibbbb', 2, 0, 0, level1, level2, hasSecret, 0)
elif node.mapChange:
data += u32.pack(3) # node type
@@ -353,17 +350,22 @@ class KPMapExporter:
requiredFixUps.append((len(data)+4, destMap))
stringsToAdd.add(destMap)
- # i i b b b b: Extra pointer, dest map, map ID, foreign ID, transition, padding
- data += struct.pack('>iibbbb', 0, 0, node.mapID, node.foreignID, node.transition, 0)
+ # i i i b b b b: isNew, Extra pointer, dest map, map ID, foreign ID, transition, padding
+ data += struct.pack('>iiibbbb', 0, 0, 0, node.mapID, node.foreignID, node.transition, 0)
else:
data += u32.pack(1) # node type
- data += u32.pack(0) # Extra pointer
+ data += zero32 # isNew
+ data += zero32 # Extra pointer
else:
- data += u32.pack(0) # node type
- data += u32.pack(0) # Extra pointer
+ data += zero32 # node type
+ data += zero32 # isNew
+ data += zero32 # Extra pointer
- for path in layer.paths:
+ pathIndices = {}
+
+ for i, path in enumerate(layer.paths):
+ pathIndices[path] = i
offsets[path] = len(data)
start = path._startNodeRef()
@@ -379,13 +381,11 @@ class KPMapExporter:
data += (zero32 * 4)
- try:
- unlockL1, unlockL2, isSecret = unlockInfo[path]
- unlockType = (2 if isSecret else 1)
- except KeyError:
- unlockL1, unlockL2, unlockType = 0, 0, 0
+ available = 0
+ if (not hasattr(path, 'unlockSpec')) or path.unlockSpec is None:
+ available = 3
- data += struct.pack('>bbbbfi', unlockType, unlockL1, unlockL2, 1, path.movementSpeed, path.animation)
+ data += struct.pack('>bbbbfi', available, 0, 0, 0, path.movementSpeed, path.animation)
# now that we're almost done... pack the strings
for string in stringsToAdd:
@@ -420,6 +420,41 @@ class KPMapExporter:
for piece in imageData:
data += piece
+ # at the end comes the unlock bytecode
+ offsets['UnlockBytecode'] = len(data)
+
+ # first off, build a map of unlocks
+ unlockLists = {}
+
+ from unlock import stringifyUnlockData
+
+ for path in self.map.pathLayer.paths:
+ if not hasattr(path, 'unlockSpec'):
+ continue
+ spec = path.unlockSpec
+ if spec is None:
+ continue
+
+ # we stringify it first because the specs become lists when
+ # imported from the kpmap (not tuples) and those can't be
+ # used as dict keys
+ spec = stringifyUnlockData(spec)
+ try:
+ lst = unlockLists[spec]
+ except KeyError:
+ lst = []
+ unlockLists[spec] = lst
+ lst.append(path)
+
+ # now produce the thing
+ from unlock import parseUnlockText, packUnlockSpec
+
+ for spec, lst in unlockLists.iteritems():
+ data += packUnlockSpec(parseUnlockText(spec))
+ data += chr(len(lst))
+ for p in lst:
+ data += u16.pack(pathIndices[p])
+
# to finish up, correct every offset
for offset, target in requiredFixUps:
u32.pack_into(data, offset, offsets[target])
@@ -430,36 +465,16 @@ class KPMapExporter:
ANIM_CURVES = ['Linear', 'Sinusoidial', 'Cosinoidial']
ANIM_TYPES = ['X Position', 'Y Position', 'Angle', 'X Scale', 'Y Scale', 'Opacity']
+ def _checkSpecForSecrets(self, spec, levelSet):
+ kind = spec[0]
- def _findUnlocksForNode(self, node, checked, affected, isFirstBranch=True, secret=None):
- if node in checked: return
-
- checked.add(node)
-
- for path in node.exits:
- if path not in checked:
- checked.add(path)
- self._findUnlocksForPath(path, node, checked, affected, isFirstBranch, secret)
-
-
- def _findUnlocksForPath(self, path, sourceNode, checked, affected, isFirstBranch, secret=None):
- start, end = path._startNodeRef(), path._endNodeRef()
- if start == sourceNode:
- destNode = end
- if isFirstBranch and path.unlocks != 1:
- return
- else:
- destNode = start
- if isFirstBranch and path.unlocks != 2:
- return
-
- if secret is None:
- secret = path.secret
- affected.append((path, secret))
-
- if not destNode.isStop():
- self._findUnlocksForNode(destNode, checked, affected, False, secret)
-
+ if kind == 'level':
+ k, one, two, secret = spec
+ if secret:
+ levelSet.add((one, two))
+ elif kind == 'and' or kind == 'or':
+ for term in spec[1]:
+ self._checkSpecForSecrets(term, levelSet)
def _buildGXTexObjRGB5A3(self, width, height, imgOffset):
# Format: RGB5A3 (5)