init python: class Inventory(object): def __init__(self): self.items = set() def add(self, item): self.items.add(item) def remove(self, item): self.items.remove(item) def get_instances(self): return self.items def get_instances_of_type(self, type): return filter(lambda x: x.type == type, self.get_instances()) class Item(object): def __init__(self, id, type, name, price=0, desc="", unlocked=True, func=None, label=None, limit=100, image="default", givable=False, currency="gold", caption="use", owned=0, infinite=False, give_label=None, usable_on=[]): self.id = id self.type = type self.name = name self.price = price self.desc = desc self.unlocked = unlocked self.func = func self.label = label self.limit = limit self.image = "interface/icons/{}.webp".format(self.id) if image == "default" else image self.currency = currency self.caption = caption self.givable = givable self.usable = bool(self.func or self.label) self.used = False self._owned = owned self.infinite = infinite self.give_label = give_label self.usable_on = usable_on inventory.add(self) def use(self): if not self.usable: raise Exception("Item '{}' is not usable as it does not have any function or a label.".format(self.name)) if self.owned == 0: raise Exception("Item '{}' owned count is equal to zero.".format(self.name)) if not self.type == "quest": # Quest items require manual triggers, it's more convenient. self.used = True if self.func: self.func() if self.label: if renpy.context_nesting_level() > 0: renpy.jump_out_of_context(self.label) else: renpy.jump(self.label) def give(self, who): if not self.givable: raise Exception("Item '{}' is not marked as givable.".format(self.name)) if self.owned == 0: raise Exception("Item '{}' owned count is equal to zero.".format(self.name)) if not self.type == "quest": # Quest items require manual triggers, it's more convenient. self.used = True if self.func: self.func() if self.give_label: if renpy.context_nesting_level() > 0: renpy.jump_out_of_context(self.give_label) else: renpy.jump(self.give_label) def get_image(self): if isinstance(self.image, basestring): return self.image else: return self.image() @property def owned(self): return self._owned @owned.setter def owned(self, value): if not self.unlocked: self.unlocked = True self._owned = max(min(value, self.limit), 0) class Decoration(Item): room_scale = 0.5 def __init__(self, id, type, name, placement, price=0, desc="", unlocked=True, image="default", room_image="default", room_image_hover=None, owned=0, replaces=False, use_action=None, replace_action=None, replace_anchor=None, replace_pos=None): super(Decoration, self).__init__(id, type, name, price, desc, unlocked, None, None, 1, image, False, "tokens", "Apply", owned) self.room_image = Transform("images/rooms/objects/decorations/{}.webp".format(self.id), zoom=self.room_scale) if room_image == "default" else Transform(room_image, zoom=self.room_scale) self.room_image_hover = Transform(room_image_hover, zoom=self.room_scale) if room_image_hover else self.room_image self.usable = True self.placement = placement self.in_use = False self.replaces = replaces self.use_action = use_action self.replace_action = replace_action self.replace_anchor = replace_anchor self.replace_pos = replace_pos if not isinstance(self.placement, RoomObject): raise TypeError("Placement must be a RoomObject instance reference.") def use(self): if self.owned == 0: raise Exception("Decoration '{}' owned count is equal to zero.".format(self.name)) target = self.placement if not target.decoration is None: target.decoration.in_use = False if self.use_action: self.use_action() # Toggle if not target.decoration == self: target.set_decoration(self) self.in_use = True else: target.set_decoration(None) self.in_use = False class Potion(Item): def __init__(self, id, type, name, price=0, desc="", unlocked=True, label=None, limit=100, image="default", currency="gold", caption="give", owned=0, recipe=None, usable_on=[], levels={}): super(Potion, self).__init__(id, type, name, price, desc, unlocked, None, label, limit, image, True, currency, caption, owned) # self.givable = bool(self.give_label) self.label = label self.recipe = recipe self.usable_on = usable_on self.levels = levels self.make_intro = False self.in_progress = {i: False for i in usable_on} self.usable = bool( renpy.has_label("{}_use".format(self.label)) ) if self.recipe is None: raise Exception("Potion '{}' recipe is empty!".format(self.name)) def has_ingredients(self): return all(x.owned > 0 for x in self.recipe) def set_active(self, who): """Marks the event as 'in progress' and will trigger a return event in the morning/evening.""" if not who in self.in_progress.keys(): raise Exception("Potion '{}' is not marked as usable on '{}'.".format(self.name, who)) self.in_progress[who] = True def make(self): if not self.has_ingredients(): return for i in self.recipe: if not i.infinite: i.owned -= 1 self.owned += 1 label = "{}_make".format(self.label) if renpy.has_label(label) and not self.make_intro: self.make_intro = True self.jump(label) def check_progression(self, who): """Check if progression is eligible to play this event""" progression = get_character_progression(who) return (progression >= self.levels.get(who)) def give(self, who): """Use potion on <active_girl>""" give_label = "{}_{}_give".format(who[:3], self.label) check_label = "{}_potion_check".format(who[:3]) if not renpy.has_label(give_label): raise Exception("Potion '{}' give label doesn't exist.".format(self.name)) if not renpy.has_label(check_label): raise Exception("Potion '{}' check label doesn't exist for '{}'.".format(self.name, who)) if self.owned == 0: raise Exception("Potion '{}' owned count is equal to zero.".format(self.name)) if not self.check_progression(who): self.jump(check_label) self.owned -= 1 self.jump(give_label) def use(self): """Use potion on Genie""" label = "{}_use".format(self.label) if not renpy.has_label(label): raise Exception("Potion '{}' has no use label.".format(self.name)) if self.owned == 0: raise Exception("Potion '{}' owned count is equal to zero.".format(self.name)) self.owned -= 1 self.jump(label) def ret(self, who): """Play the return event for <girl>""" if not self.in_progress[who]: raise Exception("Potion '{}' is not marked as in progress.".format(self.name)) label = "{}_{}_return".format(who[:3], self.label) if not renpy.has_label(label): raise Exception("Potion '{}' has no return label.".format(self.name)) self.in_progress[who] = False self.jump(label) def jump(self, label): if renpy.context_nesting_level() > 0: renpy.jump_out_of_context(label) else: renpy.jump(label) init offset = -5 default inventory = Inventory()