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 inject_into_ROM(self, rom): #should work for the combo rom, VT rando, and the (J) rom. Not sure about the (U) rom...maybe? #the sheet needs to be placed directly into address $108000-$10F000 for i,row in enumerate(itertools.chain(ascii_uppercase, ["AA","AB"])): #over all 28 rows of the sheet for column in range(8): #over all 8 columns image_name = f"{row}{column}" if image_name == "AB7": #AB7 is special, because the palette block sits there in the PNG, so this can't be actually used image_name = "null_block" raw_image_data = common.convert_to_4bpp(self.images[image_name], (0,0), (0,0,16,16), None) rom.bulk_write_to_snes_address(0x108000+0x400*i+0x40*column,raw_image_data[:0x40],0x40) rom.bulk_write_to_snes_address(0x108200+0x400*i+0x40*column,raw_image_data[0x40:],0x40) #the palettes need to be placed directly into address $1BD308-$1BD380, not including the transparency or gloves colors converted_palette = common.convert_to_555(self.master_palette) for i in range(4): rom.write_to_snes_address(0x1BD308+0x1E*i,converted_palette[0x10*i+1:0x10*i+0x10],0x0F*"2") #the glove colors are placed into $1BEDF5-$1BEDF8 for i in range(2): rom.write_to_snes_address(0x1BEDF5+0x02*i,converted_palette[0x10+0x10*i],2) return rom
def inject_into_ROM(self, spiffy_dict, rom): #should work for the combo rom, VT rando #should work for the (J) & (U) ROMs but won't automatically include the extra code needed to manage gloves, etc #this'll check VT rando Tournament Flag tournament_flag = rom.read(0x180213, 2) == 1 #this'll check combo Tournament Flag if rom.type() == "EXHIROM" and not tournament_flag: config = rom.read_from_snes_address(0x80FF52, 2) fieldvals = {} fieldvals["gamemode"] = ["singleworld", "multiworld"] fieldvals["z3logic"] = ["normal", "hard"] fieldvals["m3logic"] = ["normal", "hard"] field = {} field["race"] = ((config & (1 << 15)) >> 15) > 0 # 1 bit field["keysanity"] = ((config & (0b11 << 13)) >> 13) > 0 # 2 bits field["gamemode"] = ((config & (1 << 12)) >> 12) # 1 bit field["z3logic"] = ((config & (0b11 << 10)) >> 10) # 2 bits field["m3logic"] = ((config & (0b11 << 8)) >> 8) # 2 bits field["version"] = {} field["version"]["major"] = ( (config & (0b1111 << 4)) >> 4) # 4 bits field["version"]["minor"] = ( (config & (0b1111 << 0)) >> 0) # 4 bits field["gamemode"] = fieldvals["gamemode"][field["gamemode"]] field["z3logic"] = fieldvals["z3logic"][field["z3logic"]] field["m3logic"] = fieldvals["m3logic"][field["m3logic"]] tournament_flag = field["race"] if not tournament_flag: #the sheet needs to be placed directly into address $108000-$10F000 for i, row in enumerate( itertools.chain( ascii_uppercase, ["AA", "AB"])): #over all 28 rows of the sheet for column in range(8): #over all 8 columns image_name = f"{row}{column}" if image_name == "AB7": #AB7 is special, because the palette block sits there in the PNG, so this can't be actually used image_name = "null_block" raw_image_data = common.convert_to_4bpp( self.images[image_name], (0, 0), (0, 0, 16, 16), None) rom.bulk_write_to_snes_address( 0x108000 + 0x400 * i + 0x40 * column, raw_image_data[:0x40], 0x40) rom.bulk_write_to_snes_address( 0x108200 + 0x400 * i + 0x40 * column, raw_image_data[0x40:], 0x40) #the palettes need to be placed directly into address $1BD308-$1BD380, not including the transparency or gloves colors converted_palette = common.convert_to_555(self.master_palette) for i in range(4): rom.write_to_snes_address( 0x1BD308 + 0x1E * i, converted_palette[0x10 * i + 1:0x10 * i + 0x10], 0x0F * "2") #the glove colors are placed into $1BEDF5-$1BEDF8 for i in range(2): rom.write_to_snes_address(0x1BEDF5 + 0x02 * i, converted_palette[0x10 + 0x10 * i], 2) if (hex(rom.read_from_snes_address(0x238000, 2)) == "0x3702") and (hex( rom.read_from_snes_address(0x23801E, 2)) == "0x3702"): # print("v32-compatible credits") contiguous = digits + ascii_uppercase + "'" letters = { "hi": { " ": "0x9F", '.': "0xA0", '/': "0xA2", ':': "0xA3", '_': "0xA6" }, "lo": { " ": "0x9F", '.': "0xC0", '/': "0xC2", ':': "0xC3", '_': "0xC6" } } for i, ltr in enumerate(itertools.chain(contiguous)): letters["hi"][ltr] = hex(i + 83).upper().replace( "0X", "0x") letters["lo"][ltr] = hex(i + 83 + 38).upper().replace( "0X", "0x") msg = { "hi": { "ascii": "", "rom": { "hex": [], "dec": [] } }, "lo": { "ascii": "", "rom": { "hex": [], "dec": [] } } } author = "" author_short = "" if "author.name" in self.metadata: author = self.metadata["author.name"] if "author.name-short" in self.metadata: author_short = self.metadata["author.name-short"] char_class = "a-zA-Z0-9\'\.\/\:\_ " pattern = r'^([' + char_class + ']+)$' antipattern = r'([^' + char_class + '])' linelen = 32 if len(author) <= linelen: matches = re.match(pattern, author) if matches: author = matches.groups(0)[0] else: author = re.sub(antipattern, "", author) if len(author_short) <= linelen: matches = re.match(pattern, author_short) if matches: author_short = matches.groups(0)[0] else: author_short = re.sub(antipattern, "", author_short) if len(author_short) > len(author): author = author_short author = author.upper() lpad = int((linelen - len(author)) / 2) - 2 author = author.rjust(lpad + len(author)).ljust(linelen) for i, ltr in enumerate(itertools.chain(author)): msg["hi"]["ascii"] += ltr msg["lo"]["ascii"] += ltr msg["hi"]["rom"]["hex"].append(letters["hi"][ltr]) msg["lo"]["rom"]["hex"].append(letters["lo"][ltr]) msg["hi"]["rom"]["dec"].append(int(letters["hi"][ltr], 16)) msg["lo"]["rom"]["dec"].append(int(letters["lo"][ltr], 16)) # print(msg) rom.bulk_write_to_snes_address(0x238002, msg["hi"]["rom"]["dec"], 0x20) rom.bulk_write_to_snes_address(0x238020, msg["lo"]["rom"]["dec"], 0x20) else: # FIXME: English raise AssertionError(f"Cannot inject into a Race/Tournament ROM!") return rom
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