예제 #1
0
def get_model_preview_image(custom_model_name, prefix, selected_colors):
    custom_model_metadata = get_model_metadata(custom_model_name)

    if "preview_hero" not in custom_model_metadata:
        return None

    preview_image_path = custom_model_metadata["preview_%s" % prefix]
    if not os.path.isfile(preview_image_path):
        return None

    preview_image = Image.open(preview_image_path)

    custom_colors = custom_model_metadata.get(prefix + "_custom_colors", {})
    for custom_color_basename, base_color in custom_colors.items():
        custom_color = selected_colors.get(custom_color_basename, None)
        if custom_color is None:
            continue
        custom_color = tuple(custom_color)
        base_color = tuple(base_color)
        if custom_color == base_color:
            continue

        mask_path = custom_model_metadata[
            "preview_" + prefix + "_color_mask_paths"][custom_color_basename]
        check_valid_mask_path(mask_path)

        preview_image = texture_utils.color_exchange(
            preview_image,
            base_color,
            custom_color,
            mask_path=mask_path,
            validate_mask_colors=False)

    return preview_image
예제 #2
0
def change_player_clothes_color(self):
    custom_model_name = self.options.get("custom_player_model", "Link")
    custom_model_metadata = get_model_metadata(custom_model_name)

    link_arc = self.get_arc("files/res/Object/Link.arc")
    link_main_model = link_arc.get_file("cl.bdl")

    if self.options.get("player_in_casual_clothes"):
        is_casual = True
        prefix = "casual"
        link_main_textures = [link_arc.get_file("linktexbci4.bti")]
    else:
        is_casual = False
        prefix = "hero"
        link_main_textures = link_main_model.tex1.textures_by_name[
            "linktexS3TC"]

    first_texture = link_main_textures[0]
    link_main_image = first_texture.render()

    replaced_any = False
    custom_colors = custom_model_metadata.get(prefix + "_custom_colors", {})
    has_colored_eyebrows = custom_model_metadata.get("has_colored_eyebrows",
                                                     False)
    for custom_color_basename, base_color in custom_colors.items():
        custom_color = self.options.get("custom_colors",
                                        {}).get(custom_color_basename, None)
        if custom_color is None:
            continue
        custom_color = tuple(custom_color)
        if custom_color == base_color:
            continue

        mask_path = custom_model_metadata[
            prefix + "_color_mask_paths"][custom_color_basename]

        link_main_image = texture_utils.color_exchange(link_main_image,
                                                       base_color,
                                                       custom_color,
                                                       mask_path=mask_path)
        replaced_any = True

        # Recolor the eyebrows.
        if has_colored_eyebrows and custom_color_basename == "Hair":
            for i in range(1, 6 + 1):
                textures = link_main_model.tex1.textures_by_name["mayuh.%d" %
                                                                 i]
                eyebrow_image = textures[0].render()
                eyebrow_image = texture_utils.color_exchange(
                    eyebrow_image, base_color, custom_color)
                for texture in textures:
                    texture.image_format = 6
                    texture.palette_format = 0
                    texture.replace_image(eyebrow_image)

        # Recolor the back hair for casual Link.
        if is_casual and custom_color_basename == "Hair":
            link_hair_model = link_arc.get_file("katsura.bdl")
            link_hair_textures = link_hair_model.tex1.textures_by_name[
                "katsuraS3TC"]
            first_texture = link_hair_textures[0]
            back_hair_image = first_texture.render()

            back_hair_image.paste(custom_color, [0, 0, 8, 8])

            for texture in link_hair_textures:
                if texture.image_format == 0xE:
                    texture.image_format = 9
                    texture.palette_format = 1
                texture.replace_image(back_hair_image)
            link_hair_model.save_changes()

    if not replaced_any:
        return

    for texture in link_main_textures:
        is_cmpr = (texture.image_format == 0xE)
        try:
            if is_cmpr:
                texture.image_format = 9
                texture.palette_format = 1
            texture.replace_image(link_main_image)
        except texture_utils.TooManyColorsError:
            if is_cmpr:
                texture.image_format = 4
                texture.palette_format = 0
            texture.replace_image(link_main_image)

        if is_casual:
            texture.save_changes()

    link_main_model.save_changes()
예제 #3
0
def change_player_custom_colors(self):
    custom_model_metadata = get_model_metadata(self.custom_model_name)
    disable_casual_clothes = custom_model_metadata.get(
        "disable_casual_clothes", False)

    sword_slash_trail_color = custom_model_metadata.get(
        "sword_slash_trail_color")
    elixir_soup_sword_trail_color = custom_model_metadata.get(
        "elixir_soup_sword_trail_color")
    parrying_sword_trail_color = custom_model_metadata.get(
        "parrying_sword_trail_color")
    boomerang_trail_color = custom_model_metadata.get("boomerang_trail_color")
    arrow_trail_color = custom_model_metadata.get("arrow_trail_color")
    if sword_slash_trail_color:
        self.dol.write_data(write_and_pack_bytes, 0x803F62AC,
                            sword_slash_trail_color, "BBBB")
    if elixir_soup_sword_trail_color:
        self.dol.write_data(write_and_pack_bytes, 0x803F62B0,
                            elixir_soup_sword_trail_color, "BBBB")
    if parrying_sword_trail_color:
        self.dol.write_data(write_and_pack_bytes, 0x803F62B4,
                            parrying_sword_trail_color, "BBBB")
    if boomerang_trail_color:
        self.dol.write_data(write_and_pack_bytes, 0x803F6268,
                            boomerang_trail_color, "BBBB")
    if arrow_trail_color:
        common_jpc = self.get_jpc("files/res/Particle/common.jpc")
        particle = common_jpc.particles_by_id[0x48]
        particle.bsp1.color_prm = tuple(arrow_trail_color)

    link_arc = self.get_arc("files/res/Object/Link.arc")
    link_main_model = link_arc.get_file("cl.bdl")

    if self.options.get(
            "player_in_casual_clothes") and not disable_casual_clothes:
        is_casual = True
        prefix = "casual"
        link_main_textures = [link_arc.get_file("linktexbci4.bti")]
    else:
        is_casual = False
        prefix = "hero"
        link_main_textures = link_main_model.tex1.textures_by_name[
            "linktexS3TC"]

    first_texture = link_main_textures[0]
    link_main_image = first_texture.render()

    hitomi_textures = link_main_model.tex1.textures_by_name["hitomi"]
    hitomi_image = hitomi_textures[0].render()

    hands_model = link_arc.get_file("hands.bdl")
    hands_textures = hands_model.tex1.textures_by_name["handsS3TC"]
    hands_image = hands_textures[0].render()

    all_mouth_textures = OrderedDict()
    all_mouth_images = OrderedDict()

    replaced_any = False
    replaced_any_hands = False
    custom_colors = custom_model_metadata.get(prefix + "_custom_colors", {})
    has_colored_eyebrows = custom_model_metadata.get("has_colored_eyebrows",
                                                     False)
    hands_color_name = custom_model_metadata.get(prefix + "_hands_color_name",
                                                 "Skin")
    mouth_color_name = custom_model_metadata.get(prefix + "_mouth_color_name",
                                                 "Skin")
    hitomi_color_name = custom_model_metadata.get(
        prefix + "_hitomi_color_name", "Eyes")
    eyebrow_color_name = custom_model_metadata.get(
        prefix + "_eyebrow_color_name", "Hair")
    casual_hair_color_name = custom_model_metadata.get(
        "casual_hair_color_name", "Hair")

    # The "_color_name" fields will be completely ignored if that type of texture has even a single mask present.
    for custom_color_basename in custom_colors:
        for i in range(1, 9 + 1):
            mouth_mask_path = custom_model_metadata["mouth_color_mask_paths"][
                i][custom_color_basename]
            if os.path.isfile(mouth_mask_path):
                mouth_color_name = None

        hands_mask_path = custom_model_metadata[
            "hands_" + prefix + "_color_mask_paths"][custom_color_basename]
        if os.path.isfile(hands_mask_path):
            hands_color_name = None

        hitomi_mask_path = custom_model_metadata[
            "hitomi_" + prefix + "_color_mask_paths"][custom_color_basename]
        if os.path.isfile(hitomi_mask_path):
            hitomi_color_name = None

    for custom_color_basename, base_color in custom_colors.items():
        custom_color = self.options.get("custom_colors",
                                        {}).get(custom_color_basename, None)
        if custom_color is None:
            continue
        custom_color = tuple(custom_color)
        base_color = tuple(base_color)
        if custom_color == base_color:
            continue

        # Recolor the pupils.
        replaced_any_pupils_for_this_color = False

        hitomi_mask_path = custom_model_metadata[
            "hitomi_" + prefix + "_color_mask_paths"][custom_color_basename]
        if os.path.isfile(hitomi_mask_path
                          ) or custom_color_basename == hitomi_color_name:
            replaced_any_pupils_for_this_color = True

            if os.path.isfile(hitomi_mask_path):
                check_valid_mask_path(hitomi_mask_path)
                hitomi_image = texture_utils.color_exchange(
                    hitomi_image,
                    base_color,
                    custom_color,
                    mask_path=hitomi_mask_path)
            elif custom_color_basename == hitomi_color_name:
                hitomi_image = texture_utils.color_exchange(hitomi_image,
                                                            base_color,
                                                            custom_color,
                                                            ignore_bright=True)

            for hitomi_texture in hitomi_textures:
                hitomi_texture.replace_image(hitomi_image)

        # Recolor the main player body texture.
        mask_path = custom_model_metadata[
            prefix + "_color_mask_paths"][custom_color_basename]

        if not os.path.isfile(
                mask_path) and replaced_any_pupils_for_this_color:
            # Normally we throw an error for any color that doesn't have a mask for the main body texture, but if it's an eye color, we ignore it.
            pass
        else:
            check_valid_mask_path(mask_path)
            link_main_image = texture_utils.color_exchange(link_main_image,
                                                           base_color,
                                                           custom_color,
                                                           mask_path=mask_path)
        replaced_any = True

        # Recolor the eyebrows.
        if has_colored_eyebrows and custom_color_basename == eyebrow_color_name:
            for i in range(1, 6 + 1):
                eyebrow_textures = link_main_model.tex1.textures_by_name[
                    "mayuh.%d" % i]
                eyebrow_image = eyebrow_textures[0].render()
                eyebrow_image = texture_utils.color_exchange(
                    eyebrow_image, base_color, custom_color)
                for eyebrow_texture in eyebrow_textures:
                    if eyebrow_texture.is_greyscale():
                        raise Exception(
                            "Eyebrows use a greyscale image format, but metadata.txt specified the model should have colored eyebrows."
                        )
                    eyebrow_texture.replace_image(eyebrow_image)

        # Recolor the back hair for casual Link.
        if is_casual and custom_color_basename == casual_hair_color_name:
            link_hair_model = link_arc.get_file("katsura.bdl")
            link_hair_textures = link_hair_model.tex1.textures_by_name[
                "katsuraS3TC"]
            first_texture = link_hair_textures[0]
            back_hair_image = first_texture.render()

            back_hair_image.paste(custom_color, [0, 0, 8, 8])

            for link_hair_texture in link_hair_textures:
                link_hair_texture.replace_image(back_hair_image)
            link_hair_model.save_changes()

        # Recolor the mouth.
        for i in range(1, 9 + 1):
            mouth_mask_path = custom_model_metadata["mouth_color_mask_paths"][
                i][custom_color_basename]
            if os.path.isfile(mouth_mask_path
                              ) or custom_color_basename == mouth_color_name:
                if i not in all_mouth_textures:
                    all_mouth_textures[
                        i] = link_main_model.tex1.textures_by_name[
                            "mouthS3TC.%d" % i]
                    all_mouth_images[i] = all_mouth_textures[i][0].render()

                if os.path.isfile(mouth_mask_path):
                    check_valid_mask_path(mouth_mask_path)
                    all_mouth_images[i] = texture_utils.color_exchange(
                        all_mouth_images[i],
                        base_color,
                        custom_color,
                        mask_path=mouth_mask_path)
                elif custom_color_basename == mouth_color_name:
                    all_mouth_images[i] = texture_utils.color_exchange(
                        all_mouth_images[i], base_color, custom_color)

        # Recolor the hands.
        hands_mask_path = custom_model_metadata[
            "hands_" + prefix + "_color_mask_paths"][custom_color_basename]
        if os.path.isfile(hands_mask_path):
            check_valid_mask_path(hands_mask_path)
            hands_image = texture_utils.color_exchange(
                hands_image,
                base_color,
                custom_color,
                mask_path=hands_mask_path)
            replaced_any_hands = True
        elif custom_color_basename == hands_color_name:
            hands_image = texture_utils.color_exchange(hands_image, base_color,
                                                       custom_color)
            replaced_any_hands = True

    if not replaced_any:
        return

    for texture in link_main_textures:
        if self.custom_model_name == "Link" and is_casual and texture.image_format == ImageFormat.C4:
            # Change the casual clothes texture to use C8 instead of C4 to increase the potential colors from 16 to 256.
            # This is only done for the vanilla Link model that comes with the game, not for custom models, since custom model creators could just change it themselves if they want to.
            texture.image_format = ImageFormat.C8
        elif self.custom_model_name == "Link" and not is_casual and texture.image_format == ImageFormat.CMPR:
            # Change the hero's clothes texture to use C8 instead of CMPR to prevent the lossy compression from creating seams.
            # This is only done for the vanilla Link model that comes with the game, not for custom models, since custom model creators could just change it themselves if they want to.
            texture.image_format = ImageFormat.C8
            texture.palette_format = PaletteFormat.RGB565

        texture.replace_image(link_main_image)

        if is_casual:
            texture.save_changes()

    for i, mouth_textures in all_mouth_textures.items():
        mouth_image = all_mouth_images[i]
        for mouth_texture in mouth_textures:
            mouth_texture.replace_image(mouth_image)

    if replaced_any_hands:
        for hands_texture in hands_textures:
            hands_texture.replace_image(hands_image)
        hands_model.save_changes()

    link_main_model.save_changes()
예제 #4
0
def change_player_clothes_color(self):
    custom_model_metadata = get_model_metadata(self.custom_model_name)
    disable_casual_clothes = custom_model_metadata.get(
        "disable_casual_clothes", False)

    link_arc = self.get_arc("files/res/Object/Link.arc")
    link_main_model = link_arc.get_file("cl.bdl")

    if self.options.get(
            "player_in_casual_clothes") and not disable_casual_clothes:
        is_casual = True
        prefix = "casual"
        link_main_textures = [link_arc.get_file("linktexbci4.bti")]
    else:
        is_casual = False
        prefix = "hero"
        link_main_textures = link_main_model.tex1.textures_by_name[
            "linktexS3TC"]

    first_texture = link_main_textures[0]
    link_main_image = first_texture.render()

    replaced_any = False
    custom_colors = custom_model_metadata.get(prefix + "_custom_colors", {})
    has_colored_eyebrows = custom_model_metadata.get("has_colored_eyebrows",
                                                     False)
    hands_color_name = custom_model_metadata.get(prefix + "_hands_color_name",
                                                 "Skin")
    mouth_color_name = custom_model_metadata.get(prefix + "_mouth_color_name",
                                                 "Skin")
    eyebrow_color_name = custom_model_metadata.get(
        prefix + "_eyebrow_color_name", "Hair")
    casual_hair_color_name = custom_model_metadata.get(
        "casual_hair_color_name", "Hair")
    for custom_color_basename, base_color in custom_colors.items():
        custom_color = self.options.get("custom_colors",
                                        {}).get(custom_color_basename, None)
        if custom_color is None:
            continue
        custom_color = tuple(custom_color)
        base_color = tuple(base_color)
        if custom_color == base_color:
            continue

        mask_path = custom_model_metadata[
            prefix + "_color_mask_paths"][custom_color_basename]

        check_valid_mask_path(mask_path)

        link_main_image = texture_utils.color_exchange(link_main_image,
                                                       base_color,
                                                       custom_color,
                                                       mask_path=mask_path)
        replaced_any = True

        # Recolor the eyebrows.
        if has_colored_eyebrows and custom_color_basename == eyebrow_color_name:
            for i in range(1, 6 + 1):
                eyebrow_textures = link_main_model.tex1.textures_by_name[
                    "mayuh.%d" % i]
                eyebrow_image = eyebrow_textures[0].render()
                eyebrow_image = texture_utils.color_exchange(
                    eyebrow_image, base_color, custom_color)
                for eyebrow_texture in eyebrow_textures:
                    eyebrow_texture.replace_image(eyebrow_image)

        # Recolor the back hair for casual Link.
        if is_casual and custom_color_basename == casual_hair_color_name:
            link_hair_model = link_arc.get_file("katsura.bdl")
            link_hair_textures = link_hair_model.tex1.textures_by_name[
                "katsuraS3TC"]
            first_texture = link_hair_textures[0]
            back_hair_image = first_texture.render()

            back_hair_image.paste(custom_color, [0, 0, 8, 8])

            for link_hair_texture in link_hair_textures:
                link_hair_texture.replace_image(back_hair_image)
            link_hair_model.save_changes()

        # Recolor the mouth.
        if custom_color_basename == mouth_color_name:
            for i in range(1, 9 + 1):
                mouth_textures = link_main_model.tex1.textures_by_name[
                    "mouthS3TC.%d" % i]
                mouth_image = mouth_textures[0].render()
                mouth_image = texture_utils.color_exchange(
                    mouth_image, base_color, custom_color)
                for mouth_texture in mouth_textures:
                    mouth_texture.replace_image(mouth_image)

        # Recolor the hands.
        if custom_color_basename == hands_color_name:
            hands_model = link_arc.get_file("hands.bdl")
            hands_textures = hands_model.tex1.textures_by_name["handsS3TC"]
            hands_image = hands_textures[0].render()

            hands_mask_path = custom_model_metadata["hands_" + prefix +
                                                    "_color_mask_path"]
            if os.path.isfile(hands_mask_path):
                hands_image = texture_utils.color_exchange(
                    hands_image,
                    base_color,
                    custom_color,
                    mask_path=hands_mask_path)
            else:
                hands_image = texture_utils.color_exchange(
                    hands_image, base_color, custom_color)

            for hands_texture in hands_textures:
                hands_texture.replace_image(hands_image)
            hands_model.save_changes()

    if not replaced_any:
        return

    for texture in link_main_textures:
        texture.replace_image(link_main_image)

        if is_casual:
            texture.save_changes()

    link_main_model.save_changes()
예제 #5
0
def change_player_clothes_color(self):
    custom_model_metadata = get_model_metadata(self.custom_model_name)
    disable_casual_clothes = custom_model_metadata.get(
        "disable_casual_clothes", False)

    link_arc = self.get_arc("files/res/Object/Link.arc")
    link_main_model = link_arc.get_file("cl.bdl")

    if self.options.get(
            "player_in_casual_clothes") and not disable_casual_clothes:
        is_casual = True
        prefix = "casual"
        link_main_textures = [link_arc.get_file("linktexbci4.bti")]
    else:
        is_casual = False
        prefix = "hero"
        link_main_textures = link_main_model.tex1.textures_by_name[
            "linktexS3TC"]

    first_texture = link_main_textures[0]
    link_main_image = first_texture.render()

    hands_model = link_arc.get_file("hands.bdl")
    hands_textures = hands_model.tex1.textures_by_name["handsS3TC"]
    hands_image = hands_textures[0].render()

    replaced_any = False
    replaced_any_hands = False
    custom_colors = custom_model_metadata.get(prefix + "_custom_colors", {})
    has_colored_eyebrows = custom_model_metadata.get("has_colored_eyebrows",
                                                     False)
    hands_color_name = custom_model_metadata.get(prefix + "_hands_color_name",
                                                 "Skin")
    mouth_color_name = custom_model_metadata.get(prefix + "_mouth_color_name",
                                                 "Skin")
    eyebrow_color_name = custom_model_metadata.get(
        prefix + "_eyebrow_color_name", "Hair")
    casual_hair_color_name = custom_model_metadata.get(
        "casual_hair_color_name", "Hair")
    for custom_color_basename, base_color in custom_colors.items():
        custom_color = self.options.get("custom_colors",
                                        {}).get(custom_color_basename, None)
        if custom_color is None:
            continue
        custom_color = tuple(custom_color)
        base_color = tuple(base_color)
        if custom_color == base_color:
            continue

        mask_path = custom_model_metadata[
            prefix + "_color_mask_paths"][custom_color_basename]

        check_valid_mask_path(mask_path)

        link_main_image = texture_utils.color_exchange(link_main_image,
                                                       base_color,
                                                       custom_color,
                                                       mask_path=mask_path)
        replaced_any = True

        # Recolor the eyebrows.
        if has_colored_eyebrows and custom_color_basename == eyebrow_color_name:
            for i in range(1, 6 + 1):
                eyebrow_textures = link_main_model.tex1.textures_by_name[
                    "mayuh.%d" % i]
                eyebrow_image = eyebrow_textures[0].render()
                eyebrow_image = texture_utils.color_exchange(
                    eyebrow_image, base_color, custom_color)
                for eyebrow_texture in eyebrow_textures:
                    if eyebrow_texture.is_greyscale():
                        raise Exception(
                            "Eyebrows use a greyscale image format, but metadata.txt specified the model should have colored eyebrows."
                        )
                    eyebrow_texture.replace_image(eyebrow_image)

        # Recolor the back hair for casual Link.
        if is_casual and custom_color_basename == casual_hair_color_name:
            link_hair_model = link_arc.get_file("katsura.bdl")
            link_hair_textures = link_hair_model.tex1.textures_by_name[
                "katsuraS3TC"]
            first_texture = link_hair_textures[0]
            back_hair_image = first_texture.render()

            back_hair_image.paste(custom_color, [0, 0, 8, 8])

            for link_hair_texture in link_hair_textures:
                link_hair_texture.replace_image(back_hair_image)
            link_hair_model.save_changes()

        # Recolor the mouth.
        if custom_color_basename == mouth_color_name:
            for i in range(1, 9 + 1):
                mouth_textures = link_main_model.tex1.textures_by_name[
                    "mouthS3TC.%d" % i]
                mouth_image = mouth_textures[0].render()
                mouth_image = texture_utils.color_exchange(
                    mouth_image, base_color, custom_color)
                for mouth_texture in mouth_textures:
                    mouth_texture.replace_image(mouth_image)

        # Recolor the hands.
        hands_mask_path = custom_model_metadata[
            "hands_" + prefix + "_color_mask_paths"][custom_color_basename]
        if os.path.isfile(hands_mask_path):
            hands_image = texture_utils.color_exchange(
                hands_image,
                base_color,
                custom_color,
                mask_path=hands_mask_path)
            replaced_any_hands = True
        elif custom_color_basename == hands_color_name:
            hands_image = texture_utils.color_exchange(hands_image, base_color,
                                                       custom_color)
            replaced_any_hands = True

    if not replaced_any:
        return

    for texture in link_main_textures:
        if self.custom_model_name == "Link" and is_casual and texture.image_format == ImageFormat.C4:
            # Change the casual clothes texture to use C8 instead of C4 to increase the potential colors from 16 to 256.
            # This is only done for the vanilla Link model that comes with the game, not for custom models, since custom model creators could just change it themselves if they want to.
            texture.image_format = ImageFormat.C8

        texture.replace_image(link_main_image)

        if is_casual:
            texture.save_changes()

    if replaced_any_hands:
        for hands_texture in hands_textures:
            hands_texture.replace_image(hands_image)
        hands_model.save_changes()

    link_main_model.save_changes()