def save_as_ZSPR(self, filename): # check to see if the functions exist (e.g. crashes hard if used # on Samus) if hasattr(self, "get_binary_sprite_sheet") and \ hasattr(self, "get_binary_palettes"): sprite_sheet = self.get_binary_sprite_sheet() palettes = self.get_binary_palettes() HEADER_STRING = b"ZSPR" VERSION = 0x01 SPRITE_TYPE = 0x01 # this format has "1" for the player sprite RESERVED_BYTES = b'\x00\x00\x00\x00\x00\x00' QUAD_BYTE_NULL_CHAR = b'\x00\x00\x00\x00' DOUBLE_BYTE_NULL_CHAR = b'\x00\x00' SINGLE_BYTE_NULL_CHAR = b'\x00' write_buffer = bytearray() write_buffer.extend(HEADER_STRING) write_buffer.extend(common.as_u8(VERSION)) checksum_start = len(write_buffer) write_buffer.extend(QUAD_BYTE_NULL_CHAR) sprite_sheet_pointer = len(write_buffer) write_buffer.extend(QUAD_BYTE_NULL_CHAR) write_buffer.extend(common.as_u16(len(sprite_sheet))) palettes_pointer = len(write_buffer) write_buffer.extend(QUAD_BYTE_NULL_CHAR) write_buffer.extend(common.as_u16(len(palettes))) write_buffer.extend(common.as_u16(SPRITE_TYPE)) write_buffer.extend(RESERVED_BYTES) write_buffer.extend( self.metadata["sprite.name"].encode('utf-16-le')) write_buffer.extend(DOUBLE_BYTE_NULL_CHAR) write_buffer.extend( self.metadata["author.name"].encode('utf-16-le')) write_buffer.extend(DOUBLE_BYTE_NULL_CHAR) write_buffer.extend( self.metadata["author.name-short"].encode('ascii')) write_buffer.extend(SINGLE_BYTE_NULL_CHAR) write_buffer[sprite_sheet_pointer:sprite_sheet_pointer + 4] = common.as_u32(len(write_buffer)) write_buffer.extend(sprite_sheet) write_buffer[palettes_pointer:palettes_pointer + 4] = common.as_u32(len(write_buffer)) write_buffer.extend(palettes) checksum = (sum(write_buffer) + 0xFF + 0xFF) % 0x10000 checksum_complement = 0xFFFF - checksum write_buffer[checksum_start:checksum_start + 2] = common.as_u16(checksum) write_buffer[checksum_start + 2:checksum_start + 4] = common.as_u16(checksum_complement) with open(filename, "wb") as zspr_file: zspr_file.write(write_buffer) return True # report success to caller else: return False # report failure to caller
def get_binary_palettes(self): raw_palette_data = bytearray() colors_555 = common.convert_to_555(self.master_palette) # Mail and bunny palettes raw_palette_data.extend(itertools.chain.from_iterable([common.as_u16(c) for i in range(4) for c in colors_555[0x10*i+1:0x10*i+0x10]])) # Glove colors raw_palette_data.extend(itertools.chain.from_iterable([common.as_u16(colors_555[0x10*i+0x10]) for i in range(2)])) return raw_palette_data
def palettes(sprite): data = bytearray() all = lambda p: p all_rev = lambda p: p[::-1] first = lambda p: p[:1] index_3 = lambda p: p[3:4] first_14 = lambda p: p[:14] first_15 = lambda p: p[:15] last = lambda p: p[-1:] last_15 = lambda p: p[-15:] palette_manifest = [ ("power", "standard", first, [(first_15, range(1))]), ("varia", "standard", first, [(first_15, range(1))]), ("gravity", "standard", first, [(first_15, range(1))]), ("power", "loader", all, [(first_15, [0x00, 0x01, 0x48, 0x49, 0x4E, 0x4F, 0x54, 0x55, 0x58])]), ("varia", "loader", all, [(first_15, [0x00, 0x01, 0x48, 0x49, 0x4E, 0x4F, 0x54, 0x55, 0x58])]), ("gravity", "loader", all, [(first_15, [0x00, 0x01, 0x48, 0x49, 0x4E, 0x4F, 0x54, 0x55, 0x58])]), ("power", "heat", all, [(last_15, range(16))]), ("varia", "heat", all, [(last_15, range(16))]), ("gravity", "heat", all, [(last_15, range(16))]), ("power", "charge", all, [(first_15, range(8))]), ("varia", "charge", all, [(first_15, range(8))]), ("gravity", "charge", all, [(first_15, range(8))]), ("power", "speed boost", all, [(first_15, range(4))]), ("varia", "speed boost", all, [(first_15, range(4))]), ("gravity", "speed boost", all, [(first_15, range(4))]), ("power", "speed squat", all, [(first_15, range(4))]), ("varia", "speed squat", all, [(first_15, range(4))]), ("gravity", "speed squat", all, [(first_15, range(4))]), ("power", "shinespark", all, [(first_15, range(4))]), ("varia", "shinespark", all, [(first_15, range(4))]), ("gravity", "shinespark", all, [(first_15, range(4))]), ("power", "screw attack", all, [(first_15, range(4))]), ("varia", "screw attack", all, [(first_15, range(4))]), ("gravity", "screw attack", all, [(first_15, range(4))]), ("power", "flash", all, [(first_15, range(6))]), ("power", "death", all, [(first_15, range(9))]), ("power", "hyper", all_rev, [(first_15, range(10))]), ("power", "sepia", first, [(first_15, range(1))]), ("power", "sepia hurt", first, [(first_15, range(1))]), ("power", "xray", all, [(index_3, range(3))]), ("power", "door", first, [(index_3, range(1))]), ("power", "file select", first, [(first_15, range(1))]), ("ship", "intro", first, [(first_15, range(1))]), ("ship", "outro", all, [(first_15, range(16))]), ( "ship", "standard", all, [ (first_14, range(1)), # first 14 colors (last, range(14)) ]), # 15th color is underglow ] for category, pose, palette_set, data_sets in palette_manifest: palettes = [ pal for _, pal in palette_set(sprite.get_timed_palette(category, pose)) ] for color_set, indices in data_sets: colors_555 = [ common.convert_to_555(color_set(pal)) for pal in palettes ] data.extend( itertools.chain.from_iterable([ common.as_u16(c) for i in indices for c in colors_555[i] ])) return data