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 sorted([x for x in self.get_instances() if x.type == type], key=lambda y: natsort_key(y.name)) 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 if image == "default": image = f"interface/icons/{self.id}.webp" self.image = 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(f"Item {self.name!r} is not usable as it does not have any function or a label.") if self.owned == 0: raise Exception(f"Item {self.name!r} owned count is equal to zero.") 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(f"Item {self.name!r} is not marked as givable.") if self.owned == 0: raise Exception(f"Item {self.name!r} owned count is equal to zero.") 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, str): 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) if room_image == "default": room_image = f"images/rooms/main_room/decorations/{self.id}.webp" self.room_image = Transform(room_image, zoom=self.room_scale) self.room_image_hover = Transform(room_image_hover or room_image, zoom=self.room_scale) 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(f"Decoration {self.name!r} owned count is equal to zero.") achievements.unlock("decorator") 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(f"{self.label}_use")) if self.recipe is None: raise Exception(f"Potion {self.name!r} recipe is empty!") 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 list(self.in_progress.keys()): raise Exception(f"Potion {self.name!r} is not marked as usable on {who!r}.") 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 = f"{self.label}_make" 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 """ give_label = f"{who[:3]}_{self.label}_give" check_label = f"{who[:3]}_potion_check" if not renpy.has_label(give_label): raise Exception(f"Potion {self.name!r} give label doesn't exist.") if not renpy.has_label(check_label): raise Exception(f"Potion {self.name!r} check label doesn't exist for {who!r}.") if self.owned == 0: raise Exception(f"Potion {self.name!r} owned count is equal to zero.") 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 = f"{self.label}_use" if not renpy.has_label(label): raise Exception(f"Potion {self.name!r} has no use label.") if self.owned == 0: raise Exception(f"Potion {self.name!r} owned count is equal to zero.") self.owned -= 1 self.jump(label) def ret(self, who): """Play the return event for """ if not self.in_progress[who]: raise Exception(f"Potion {self.name!r} is not marked as in progress.") label = f"{who[:3]}_{self.label}_return" if not renpy.has_label(label): raise Exception(f"Potion {self.name!r} has no return label.") 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()