示例#1
0
def death_bank(direction, sprite):
    len = 0x3F60
    image = rom_inject.compile_death_image(direction, sprite)
    return bytes(
        itertools.chain.from_iterable(
            common.convert_to_4bpp(image, (0, 0), (0, 16 * i, 128, 16 *
                                                   (i + 1)), None)
            for i in range(16)))[:len]
示例#2
0
def file_select(sprite):
    file_select_sprites = Image.new("P", (128, 24), 0)

    for image_name, src, dest in [
        ("file_select_head", None, (0, 0)),
        ("file_select_head1", None, (24, 0)),
        ("file_select_head2", None, (48, 0)),
        ("file_select_visor", None, (72, 0)),
        ("file_select_visor1", None, (88, 0)),
        ("file_select_visor2", None, (104, 0)),
        ("file_select_visor3", None, (72, 8)),
        ("file_select_visor4", None, (88, 8)),
        ("file_select_cursor_array", (0, 24, 8, 32), (112, 16)),
        ("file_select_cursor_array", (0, 16, 8, 24), (112, 8)),
        ("file_select_cursor_array", (0, 8, 8, 16), (120, 0)),
        ("file_select_cursor_array", (8, 8, 16, 16), (120, 8)),
        ("file_select_cursor_array", (8, 16, 16, 24), (120, 16)),
        ("file_select_piping", (0, 0, 24, 8), (72, 16)),  # Top
        ("file_select_piping", (16, 8, 24, 24), (104, 8)),  # Side
        ("file_select_piping", (0, 16, 8, 24), (96, 16)),  # Corner
    ]:
        source_image = sprite.images[image_name]
        source_image = source_image.crop(src) if src else source_image
        file_select_sprites.paste(source_image, dest)

    cursor_array = sprite.images["file_select_cursor_array"]
    file_select_missile = cursor_array.crop((0, 0, 8, 8))
    file_select_missile_head = cursor_array.crop((8, 24, 16, 32))

    data = bytearray()
    # Due to how convert_to_4bpp package the data we must first get a whole sheet row, then extract the third row (first 0x200 bytes)
    data.extend(
        common.convert_to_4bpp(file_select_sprites, (0, 0), (0, 0, 128, 16),
                               None))
    data.extend(
        common.convert_to_4bpp(file_select_sprites, (0, 0), (0, 16, 128, 32),
                               None)[:0x200])
    data.extend(
        common.convert_to_4bpp(file_select_missile, (0, 0), (0, 0, 8, 8),
                               None))
    data.extend(
        common.convert_to_4bpp(file_select_missile_head, (0, 0), (0, 0, 8, 8),
                               None))
    return data
示例#3
0
	def get_binary_sprite_sheet(self):
		top_half_of_rows = bytearray()
		bottom_half_of_rows = bytearray()

		# 28 rows, 8 columns
		for image_name in [f"{row}{column}" for row in itertools.chain(ascii_uppercase, ["AA","AB"]) for column in range(8)]:
			# AB7 holds the palette block so use null_block instead
			image_name = image_name if image_name != "AB7" else "null_block"
			raw_image = common.convert_to_4bpp(self.images[image_name],(0,0),(0,0,16,16),None)
			top_half_of_rows += bytes(raw_image[:0x40])
			bottom_half_of_rows += bytes(raw_image[0x40:])

		return bytes(b for row_offset in range(0,len(top_half_of_rows),0x200) \
						 for b in top_half_of_rows[row_offset:row_offset+0x200]+bottom_half_of_rows[row_offset:row_offset+0x200])
示例#4
0
	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
示例#5
0
    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