rendered paste bodyimport structimport StringIOimport sysimport getoptimport os.path as pathimport globBLOCK_MAP_END_OF_BLOCK = 0x00BLOCK_MAP_CHIPSET = 0x01BLOCK_MAP_WIDTH = 0x02BLOCK_MAP_HEIGHT = 0x03BLOCK_MAP_TYPE_OF_LOOP = 0x0BBLOCK_MAP_PARALLAX_BACK = 0x1FBLOCK_MAP_BACKGROUND = 0x20BLOCK_MAP_HORIZONTAL_PAN = 0x21BLOCK_MAP_VERTICAL_PAN = 0x22BLOCK_MAP_HORIZONTAL_PAN_A = 0x23BLOCK_MAP_HORIZONTAL_PAN_SP = 0x24BLOCK_MAP_VERTICAL_PAN_A = 0x25BLOCK_MAP_VERTICAL_PAN_SP = 0x26BLOCK_MAP_LOWER_LAYER = 0x47BLOCK_MAP_UPPER_LAYER = 0x48BLOCK_MAP_EVENTS_LAYER = 0x51BLOCK_MAP_TIMES_SAVED = 0x5Bclass DataBlock: def __init__(self, type, data, length): self.type = type self.data = StringIO.StringIO(data) self.length = length def read_byte(stream): return struct.unpack("B", stream.read(1))[0] def read_integer(stream): value = 0 temp = 0x80 while temp & 0x80: value <<= 7 temp = read_byte(stream) value |= temp & 0x7F return value def read_string(stream, length): return stream.read(length) def read_array2(stream, length): max = read_integer(stream) array = {} while stream.tell() < length: row = read_integer(stream) while True: col = read_integer(stream) if col == 0: break datalen = read_integer(stream) if not array.has_key(row): array[row] = {} array[row][col] = DataBlock(col, stream.read(datalen), datalen) return array def loop_type_string(type): if type == 0x00: return "None" elif type == 0x01: return "Horizontal" elif type == 0x02: return "Vertical" elif type == 0x03: return "Both" else: return "Unknown" class LcfDataBase: def __init__(self, path): self.path = path self.file = open(path, "rb") self.chipsets = {} self.check_header() for block in self.read_blocks(): if block.type == 0x14: array = read_array2(block.data, block.length) for row in array: chip_name = read_string(array[row][0x01].data, array[row][0x01].length) chip_filename = read_string(array[row][0x02].data, array[row][0x02].length) self.chipsets[row] = { 'name': chip_name, 'filename': chip_filename } def check_header(self): header = self.file.read(12) if header != "\x0bLcfDataBase": raise "Invalid header. Doesn't appear to be an RM2K database file." def read_blocks(self): try: while True: type = read_integer(self.file) length = read_integer(self.file) data = self.file.read(length) yield DataBlock(type, data, length) except Exception, e: returnclass LcfMapUnit: def __init__(self, path): self.path = path self.file = open(path, "rb") self.check_header() # set up default map data self.chipset_id = 1 self.width = 20 self.height = 15 self.loop_type = 0 self.parallax = False self.background = None self.pan_horizontal = False self.pan_horizontal_auto = False self.pan_horizontal_speed = 0 self.pan_vertical = False self.pan_vertical_auto = False self.pan_vertical_speed = 0 self.layers = {} self.event_count = 0 self.save_count = 0 for block in self.read_blocks(): if block.type == BLOCK_MAP_CHIPSET: self.chipset_id = read_integer(block.data) elif block.type == BLOCK_MAP_WIDTH: self.width = read_integer(block.data) elif block.type == BLOCK_MAP_HEIGHT: self.height = read_integer(block.data) elif block.type == BLOCK_MAP_TYPE_OF_LOOP: self.loop_type = read_integer(block.data) elif block.type == BLOCK_MAP_PARALLAX_BACK: self.parallax = read_integer(block.data) == 1 elif block.type == BLOCK_MAP_BACKGROUND: self.background = read_string(block.data, block.length) elif block.type == BLOCK_MAP_HORIZONTAL_PAN: self.pan_horizontal = read_integer(block.data) == 1 elif block.type == BLOCK_MAP_VERTICAL_PAN: self.pan_vertical = read_integer(block.data) == 1 elif block.type == BLOCK_MAP_HORIZONTAL_PAN_A: self.pan_horizontal_auto = read_integer(block.data) == 1 elif block.type == BLOCK_MAP_VERTICAL_PAN_A: self.pan_vertical_auto = read_integer(block.data) == 1 elif block.type == BLOCK_MAP_HORIZONTAL_PAN_SP: self.pan_horizontal_speed = read_integer(block.data) elif block.type == BLOCK_MAP_VERTICAL_PAN_SP: self.pan_vertical_speed = read_integer(block.data) elif block.type == BLOCK_MAP_LOWER_LAYER: self.layers['lower'] = block.data.read() elif block.type == BLOCK_MAP_UPPER_LAYER: self.layers['upper'] = block.data.read() elif block.type == BLOCK_MAP_TIMES_SAVED: self.save_count = read_integer(block.data) elif block.type == BLOCK_MAP_END_OF_BLOCK: break def check_header(self): header = self.file.read(11) if header != "\nLcfMapUnit": raise "Invalid header. Doesn't appear to be an RM2K map file." def read_blocks(self): try: while True: type = read_integer(self.file) length = read_integer(self.file) data = self.file.read(length) yield DataBlock(type, data, length) except Exception, e: return def print_help(): print "usage: convert.py [action] [args]" print "Actions:" print " info [map] Shows information on an RM2k map." print " convert [map] [output_map] Converts an RM2k map to a Sphere map." print print "Switches:" print " -c [file], --chipset=[file] Override the map's chipset." print " -h, --help Prints this help." print print "map-converter v0.1 by engine #100. Licensed under the GPL." print "http://projects.casiotone.org/map-converter/"def run_convert(): opts, leftover = getopt.gnu_getopt(sys.argv[1:], 'hc:', ['help', 'chipset=']) use_chipset = None rtp_path = None for opt, arg in opts: if opt == '-h' or opt == '--help': print_help() return if opt == '-c' or opt == '--chipset': use_chipset = arg if len(leftover) == 0: raise Exception("No action specified.") return if len(leftover) >= 1: action = leftover[0] if action == "convert": if len(leftover) == 1: raise Exception("An rm2k map file must be specified to convert a map.") sys.exit(1) if len(leftover) == 2: raise Exception("An output map file must be specified to convert a map.") sys.exit(1) map = LcfMapUnit(leftover[1]) out = leftover[2] chipset_path = "" if use_chipset is None: # attempt to get the chipset from RPG_RT.ldb db = LcfDataBase(path.join(path.dirname(leftover[1]), "RPG_RT.ldb")) print "Searching for database chipset #%d: %s (%s)" % (map.chipset_id, db.chipsets[map.chipset_id]['name'], db.chipsets[map.chipset_id]['filename']) filename = db.chipsets[map.chipset_id]['filename'] chip_path = path.join(path.dirname(leftover[1]), "ChipSet", filename) chip_files = glob.glob(chip_path + ".*") if len(chip_files): chipset_path = chip_files[0] print "Found at %s" % chipset_path else: raise Exception("Chipset could not be found in the project. It may be part of the RTP.") sys.exit(1) else: print "Using specified chipset: %s" % (use_chipset) # convert here print "Conversion..." elif action == "info": if len(leftover) == 1: raise Exception("An rm2k map file must be specified to view information on.") sys.exit(1) map = LcfMapUnit(leftover[1]) print "Map size: %dx%d" % (map.width, map.height) print "Loop type: %d (%s)" % (map.loop_type, loop_type_string(map.loop_type)) print "Chipset ID: %d" % (map.chipset_id) print "Parallax: %s" % (map.parallax) print "Background: %s" % (map.background) print "Panning:" if map.pan_horizontal: print " |- Horizontal: %d %s" % (map.pan_horizontal_speed, ["(Auto)", ""][int(map.pan_horizontal_auto)]) else: print " |- Horizontal: None" if map.pan_vertical: print " |- Vertical: %d %s" % (map.pan_vertical_speed, ["(Auto)", ""][int(map.pan_vertical_auto)]) else: print " |- Vertical: None" print "Layer data lengths: %d, %d" % (len(map.layers['lower']), len(map.layers['upper'])) print "Save count: %d" % (map.save_count) if __name__ == "__main__": try: run_convert() except Exception, e: print e sys.exit(1)