init python:
    class DollOutfit(DollMethods):
        default_schedule = {"day": False, "night": False, "cloudy": False, "rainy": False, "snowy": False}

        def __init__(self, group, unlocked=False, name="", desc="", price=0, temp=False, schedule={}, hidden=False, addons=[]):
            self.group = [x.clone() if not x.parent else x for x in group]
            self.name = name
            self.desc = desc
            self.price = price
            self.char = self.group[0].char
            self.unlocked = unlocked
            self.schedule = dict(self.default_schedule.items() + schedule.items())
            self.hash = self.generate_hash()
            self.temp = temp
            self.hidden = hidden
            self.addons = addons

            if not self.temp:

                if unlocked:
                    self.unlock()

                if not self.hidden and not self in self.char.outfits:
                    self.char.outfits.append(self)

        # if config.developer:
        #     def __del__(self):
        #         print("Outfit with hash: {} has been garbage collected.".format(self.hash))

        def __eq__(self, obj):
            if not isinstance(obj, DollOutfit):
                return NotImplemented
            return self.hash == obj.hash

        def generate_hash(self):
            salt = str( sorted([ sorted([x.name, x.type, x.id, x.color]) for x in self.group ]) )
            return hash(salt)

        def delete(self):
            if self in self.char.outfits:
                self.char.outfits.remove(self)

        def build_image(self):
            masks = []
            sprites = [
                (self.char.body.get_mannequin(self.group), 0)
            ]

            for i in self.group:
                sprites.append([i.get_image(), i.zorder])

                sprites.extend([
                    (i.get_image(), i.zorder),
                    i.get_back(),
                    i.get_front(),
                    i.get_armfix(mannequin=True),
                    ])

                if i.mask:
                    masks.append((i.mask, i.zorder-1))

            sprites.sort(key=itemgetter(1))
            masks.sort(key=itemgetter(1))

            back_sprites = [x for x in sprites if x[1] < 0]
            sprites = [x for x in sprites if x[1] >= 0]

            # Apply alpha mask
            for m in masks:
                mask, mask_zorder = m

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

                    if i < 1 or mask_zorder > sprite_zorder:
                        continue

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

            sprites = back_sprites + sprites
            return tuple(x[0] for x in sprites)

        def exists(self):
            return (self in self.char.outfits)

        def export_data(self, filename, tofile=True):
            """Exports outfit to .png file or clipboard text."""
            exported = [self.group[0].name]
            exported.extend([x.id, x.color] for x in self.group)

            # Encode data
            if tofile:
                path = "{}/game/outfits/".format(config.basedir)
                fn = "{}.png".format(filename)

                if not os.path.exists(path):
                    os.makedirs(path)

                d = Transform(self.get_image(), crop=(210, 200, 700, 1000), anchor=(0.5, 1.0), align=(0.5, 1.0), xsize=310, ysize=470, fit="contain")
                d = Fixed(
                    "interface/wardrobe/export_background.webp",
                    d,
                    "interface/wardrobe/export_frame.webp",
                    Text(active_girl, align=(0.5, 0.995)),
                    Text("Ver. {}".format(config.version), size=10, align=(0.99, 0.99))
                )

                displayable_to_file(d, path+fn, size=(310, 470) )
                image_payload.encode(filename, str(exported))
            else:
                set_clipboard(exported)
            renpy.notify("Export successful!")

        def unlock(self):
            """Unlocks outfit and respective clothing objects from which they were cloned."""
            self.unlocked = True
            for i in self.group:
                i.unlock()

            for i in self.addons:
                i.unlock()

        def save(self):
            """Overwrites this outfit with clothes currently equipped by the character."""
            self.group = []
            for v in self.char.clothes.itervalues():
                if v[0]:
                    self.group.append(v[0].clone())
            self.rebuild_image()
            return

        def is_modded(self):
            """Returns True if one of the group items comes from a mod."""
            for i in self.group:
                if i.is_modded():
                    return True
            return False

        def get_modname(self):
            """Returns a list of mods contained within the outfit group."""
            return list(set([i.get_modname() for i in self.group if i.is_modded()]))

        def get_schedule(self):
            """Returns a dictionary with the current schedule."""
            return self.schedule

        def set_schedule(self, **kwargs):
            for k, v in kwargs.iteritems():
                self.schedule[k] = v

        def has_type(self, *args):
            """Takes argument(s) containing string cloth type(s). Returns True if worn, False otherwise."""
            types = set(x.type for x in self.group)

            for arg in args:
                if arg in self.multislots:
                    if not any(x.startswith(arg) for x in types):
                        return False
                else:
                    if not arg in types:
                        return False
            return True

        def has_any_type(self, *args):
            """Takes arguments containing string cloth types. Returns True if ANY of them is worn, False otherwise."""
            if "clothes" in args:
                for k in self.char.clothes.iterkeys():
                    if not k.startswith(self.blacklist_toggles):
                        if self.has_type(k):
                            return True
            else:
                for arg in args:
                    if self.has_type(arg):
                        return True
            return False
