init -1 python: class Room(object): def __init__(self, id, menu=None): self.id = id self.menu = menu self.objects = set() def add(self, obj): self.objects.add(obj) def remove(self, obj): self.objects.remove(obj) class RoomObject(object): def __init__(self, room, id, pos, idle, hover=None, foreground=None, background=None, anchor=(0.5, 0.5), focus_mask=True, action=NullAction(), hovered=None, unhovered=None, tooltip=None, decoration=None, zorder=0, hidden=False, overlay=None): self.room = room self.id = id self.pos = pos self.idle = idle self.hover = hover or self.idle self.foreground = foreground self.background = background self.anchor = anchor self.focus_mask = focus_mask self.action = action self.hovered = hovered self.unhovered = unhovered self.tooltip = tooltip self.decoration = decoration self.zorder = zorder self.hidden = hidden self.overlay = overlay # Add to the main room if room was specified if self.room: self.room.add(self) # Backwards compatibility, to be resolved if possible. self.xpos, self.ypos = self.pos if isinstance(self.action, dict): self._default_action = self.action.copy() else: self._default_action = self.action def generate_hash(self): salt = str( [self.id, self.pos, self.idle, self.hover, self.foreground, self.background, self.anchor, self.focus_mask, self.action, self.hovered, self.unhovered, self.tooltip, self.decoration, self.zorder, self.hidden, self.overlay] ) return hashstring(salt) def set_image(self, idle, hover=None): self.idle = idle self.hover = hover or idle def get_idle(self): return self._get_idle(self.generate_hash()) @functools.cache def _get_idle(self, hash): if self.hidden: return Null() if self.decoration: if self.decoration.replaces: return Fixed(self.decoration.room_image, fit_first=True) else: return Fixed(self.idle, self.decoration.room_image, fit_first=True) return Fixed(self.idle, fit_first=True) def get_hover(self): return self._get_hover(self.generate_hash()) @functools.cache def _get_hover(self, hash): if self.hidden: return Null() if self.decoration: if self.decoration.replaces: return At(Fixed(self.decoration.room_image_hover, fit_first=True), pulse_hover) else: return At(Fixed(self.hover, self.decoration.room_image_hover, fit_first=True), pulse_hover) return At(Fixed(self.hover, fit_first=True), pulse_hover) ### Shader needs more work. # if self.decoration: # return Transform(Fixed(self.hover, self.decoration.room_image, fit_first=True), shader="outline_shader") # return Transform(self.hover, shader="outline_shader") def get_foreground(self): return self._get_foreground(self.generate_hash()) @functools.cache def _get_foreground(self, hash): if self.hidden: return Null() if self.overlay: if self.foreground: return Fixed(self.foreground, self.overlay) return self.overlay elif self.foreground: return self.foreground def set_decoration(self, decoration): if not isinstance(decoration, (Decoration, NoneType)): raise TypeError("Decoration must be a Decoration instance reference or a NoneType") self.decoration = decoration def get_action(self): deco = self.decoration if deco and deco.replace_action: action = deco.replace_action else: action = self.action if isinstance(action, dict): if not action: raise IndexError(f"Action dict was provided for '{self.id}' but it is empty.") btns = create_wheelmenu(action) if not btns: return None return Call("wheelmenu", btns=btns, ret=self.room.menu) return action def reset_action(self): if isinstance(self._default_action, dict): self.action = self._default_action.copy() elif isinstance(self._default_action, set): self.action = set(self._default_action) elif isinstance(self._default_action, list): self.action = self._default_action[:] else: self.action = self._default_action def get_anchor(self): deco = self.decoration if deco and deco.replace_anchor: return deco.replace_anchor return self.anchor def get_pos(self): deco = self.decoration if deco and deco.replace_pos: return deco.replace_pos return self.pos def RoomHighlightToggle(state=None): if not room_menu_active or renpy.in_rollback(): return room = getattr(store, states.room, None) if not room: return for i in room.objects: if i.hidden or not i.action: continue if i.overlay: i.overlay = None else: i.overlay = At(Text("🔎", align=(0.5, 0.5), size=24), room_highlight_anim) renpy.restart_interaction() transform room_highlight_anim: subpixel True easein 0.5 zoom 1.2 easeout 0.5 zoom 1.0 repeat default room_menu_active = False screen room_menu(): tag room_menu on "show" action SetVariable("room_menu_active", True) on "hide" action SetVariable("room_menu_active", False)