init python:
    class DollCloth(DollMethods):
        def __init__(self, name, categories, type, id, color, zorder=None, unlocked=False, level=0, blacklist=[], parent=None, armfix=False, modpath=None):
            self.name = name
            self.char = eval(name)
            self.categories = categories
            self.type = type
            self.id = id
            self.color = color
            self.color_default = [x[:] for x in color]
            self.unlocked = unlocked
            self.layers = len(color)
            self.parent = parent
            self.ico = Null()
            self.blacklist = blacklist
            self.level = level
            self.modpath = posixpath.normpath(modpath) if modpath else ""
            self.armfix = armfix
            self.back_outline = None
            self.front_outline = None

            # Inherit zorder from character if needed
            self.zorder = zorder or self.char.clothes[type][1]

            self.seen = self.unlocked
            self.cached_icon = False

            self.set_imagepath()
            self.set_layers()

            # Add to character wardrobe and unordered list
            if not parent:
                self.char.wardrobe.setdefault(self.categories[0], {}).setdefault(self.categories[1], []).append(self)
                self.char.wardrobe_list.append(self)

        def set_imagepath(self):
            if any(x in self.type for x in self.multislots):
                subpath = self.type[:-1]
            else:
                subpath = self.type

            path = "{}/characters/{}/clothes/{}/{}/".format(self.modpath, self.name, subpath, self.id)

            if renpy.loadable(path + "0.webp"):
                self.imagepath = path
                return
            raise IOError("Couldn't find file \"{}/characters/{}/clothes/{}/{}/0.webp\"".format(self.modpath, self.name, subpath, self.id))

        def set_layers(self):
            for x in self.layers_special:
                path = "{}{}.webp".format(self.imagepath, x)
                self.__dict__[x] = path if renpy.loadable(path) else None

            for x in self.layers_additional:
                self.__dict__[x] = []

                for i in xrange(self.layers):
                    path = "{}{}_{}.webp".format(self.imagepath, i, x)
                    if renpy.loadable(path):
                        self.__dict__[x].append(path)
                    else:
                        self.__dict__[x].append(None)

                path = "{}outline_{}.webp".format(self.imagepath, x)
                self.__dict__[x+"_outline"] = path if renpy.loadable(path) else None

        def build_image(self):
            sprites = [(self.apply_color("{}{}.webp".format(self.imagepath, x), x), x) for x in xrange(self.layers)]

            # Add extra layers if exist
            for n, x in enumerate(self.layers_extra):
                path = "{}{}.webp".format(self.imagepath, x)
                if renpy.loadable(path):
                    sprites.append((path, self.layers+n))

            sprites.sort(key=itemgetter(1))
            sprites = tuple(x[0] for x in sprites)
            return sprites

        def build_mannequin(self):
            sprites = [
                self.get_back(),
                self.get_mannequin(),
                self.get_front(),
                (self.get_image(), self.zorder),
                self.get_armfix(mannequin=True)
            ]

            sprites.sort(key=itemgetter(1))

            # Apply Alpha mask
            if self.mask:
                mask_zorder = self.zorder-1

                for i, s in enumerate(sprites):
                    sprite, sprite_zorder = s

                    if mask_zorder > sprite_zorder >= 0:
                        continue

                    c = tuple(x[0] for x in sprites[:i] if not isinstance(x[0], Null))
                    masked = AlphaMask(Fixed(*c, fit_first=True), self.mask)
                    sprites = sprites[i:]
                    sprites.insert(0, (masked, mask_zorder))
                    break


            bounds = "{}outline.webp".format(self.imagepath) if renpy.loadable("{}outline.webp".format(self.imagepath)) else "{}0.webp".format(self.imagepath)

            sprites = tuple(x[0] for x in sprites)
            return (sprites, bounds)

        def make_icon(self):
            thread = DollThread(target=self.build_icon)
            thread.daemon = True
            thread.start()

            sprite = thread.join()

            self.ico = DollDisplayable(sprite)

        def build_icon(self):
            sprites, bounds = self.build_mannequin()

            wmax, hmax = self.sizes
            wmin = hmin = 96

            x, y, w, h = crop_whitespace(bounds)
            xoffset, yoffset = w/2, h/2

            w = h = max(w, h, wmin, hmin)

            w = max(wmin, w + w/2)
            h = max(hmin, h + h/2)

            x = clamp( (x - w/2) + xoffset, 0, wmax)
            y = clamp( (y - h/2) + yoffset, 0, hmax)

            # Forbid exceeding the image height.
            if y+h > hmax:
                y = hmax-h

            return Transform(Fixed(*sprites, fit_first=True), crop=(x, y, w, h))

        def rebuild_icon(self):
            # Defers rebuild until next time get_image is called
            self.cached_icon = False

        def get_back(self):
            """Returns a list of layers displayed in the back of object/character"""
            back_outline = [self.back_outline] if self.back_outline else []
            sprites = [self.apply_color(x, n) for n, x in enumerate(self.back) if x] + back_outline
            if sprites:
                return (Fixed(*sprites, fit_first=True), -100+self.zorder)

            w, h = self.sizes
            return (Null(width=w, height=h), -100+self.zorder)

        def get_front(self):
            """Returns a list of layers displayed in the front of object/character"""
            front_outline = [self.front_outline] if self.front_outline else []
            sprites = [self.apply_color(x, n) for n, x in enumerate(self.front) if x] + front_outline
            if sprites:
                return (Fixed(*sprites, fit_first=True), 100+self.zorder)

            w, h = self.sizes
            return (Null(width=w, height=h), 100+self.zorder)

        def get_armfix(self, mannequin=False):
            if self.armfix:
                if mannequin:
                    armleft = gray_tint("{}armleft/{}_fix.webp".format(self.char.body.imagepath, self.char.body.get_part("armleft")))
                    armright = gray_tint("{}armright/{}_fix.webp".format(self.char.body.imagepath, self.char.body.get_part("armright")))
                else:
                    armleft = Transform("{}armleft/{}_fix.webp".format(self.char.body.imagepath, self.char.body.get_part("armleft")), matrixcolor=HueMatrix(self.char.body.hue))
                    armright = Transform("{}armright/{}_fix.webp".format(self.char.body.imagepath, self.char.body.get_part("armright")), matrixcolor=HueMatrix(self.char.body.hue))
                return (Fixed(armleft, armright, fit_first=True), 0.5+self.zorder)

            w, h = self.sizes
            return (Null(width=w, height=h), 0.5+self.zorder)

        def get_mannequin(self):
            return (self.char.body.get_mannequin(group=[self]), 0)

        def get_icon(self):
            """Returns cropped Fixed displayable"""
            if not renpy.is_skipping():
                if not self.cached_icon:
                    self.cached_icon = True
                    self.make_icon()
            return self.ico

        def apply_color(self, img, n):
            """Takes image and int layer number. Used internally."""
            c = TintMatrix(tuple(self.color[n]))
            return Transform(img, matrixcolor=c)

        def set_color(self, n):
            """Takes int layer number for manual color picking or a list to replace the cloth color in its entirety."""
            if isinstance(n, int):
                col = Color(tuple(self.color[n]))
                dcol = Color(tuple(self.color_default[n]))

                cp.live_replace(col)
                cp.start_replace(col)
                cp.default_replace(dcol)

                renpy.show_screen("colorpickerscreen", self)

                while True:
                    action, value = ui.interact()

                    if action == "layer":
                        n = value
                        col = Color(tuple(self.color[value]))
                        dcol = Color(tuple(self.color_default[n]))

                        cp.live_replace(col)
                        cp.start_replace(col)
                        cp.default_replace(dcol)
                    elif action == "released":
                        self.color[n] = [int(255*x) for x in value.rgba]
                        self.rebuild_image()
                        self.char.rebuild_image()
                    elif action == "replace":
                        self.color[n] = [int(255*x) for x in value.rgba]
                        cp.live_replace(value)
                        self.rebuild_image()
                        self.char.rebuild_image()
                    elif action == "finish":
                        break

                renpy.hide_screen("colorpickerscreen")
            elif isinstance(n, list):
                self.color = [x[:] for x in n]
                self.rebuild_image()
                self.char.rebuild_image()
            self.rebuild_icon()

        def reset_color(self, n=None):
            """Reset cloth color. Takes optional int layer number to reset only specific layer color."""
            if n:
                self.color[n] = [x for x in self.color_default]
            else:
                self.color = [x[:] for x in self.color_default]
            self.rebuild_image()
            self.char.rebuild_image()
            self.rebuild_icon()

        def clone(self):
            """Creates a clone of this cloth object. Since it requires a parent object it should be used internally only to avoid object depth issue."""
            return DollCloth(self.name, self.categories, self.type, self.id, [x[:] for x in self.color], self.zorder, self.unlocked, self.level, self.blacklist, self, self.armfix, self.modpath)

        def set_pose(self, pose):
            compatible = False

            for x in (self.categories[0], self.categories[1], self.type):
                if pose is None:
                    path = "{}/characters/{}/clothes/{}/{}/".format(self.modpath, self.name, x, self.id)
                    if renpy.loadable(path + "0.webp"):
                        self.imagepath = path
                        self.char.wear(self.type)
                        compatible = True
                        break
                else:
                    path = "{}/characters/{}/poses/{}/clothes/{}/{}/".format(self.modpath, self.name, pose, x, self.id)
                    if renpy.loadable(path + "0.webp"):
                        self.imagepath = path
                        self.char.wear(self.type)
                        compatible = True
                        break

            if not compatible:
                self.char.strip(self.type)
                return

            self.set_layers()
            self.rebuild_image()
            return

        def is_compatible(self):
            return

        def is_modded(self):
            """Returns True if item comes from a mod."""
            if self.modpath:
                return True
            return False

        def get_modname(self):
            """Return the name of the mod directory if exists."""
            return self.modpath.split("/")[1] if self.is_modded() else None

        def mark_as_seen(self):
            self.seen = True

        def is_multislot(self):
            return any(x in self.type for x in self.multislots)

        def unlock(self):
            self.unlocked = True

            if self.parent:
                self.parent.unlock()
