default event_callbacks = [] default _events_completed_any = None default _events_completed_all = None default _events_filtered_completed_all = None default _events_filtered_completed_any = None default _event_completed = None default _event_completed_failed = None init -1 python: class EventQueue(object): def __init__(self, id=None): self.id = id self.queue = [] self.freeze = False self.counter = 0 def freeze(self): self.freeze = True def unfreeze(self): self.freeze = False def delay(self, n): for i in self.queue: i.wait += n def tick(self): """Causes time to pass.""" if self.freeze: return for i in self.queue: i.wait -= 1 def list_applicable(self): queue = [ev for ev in self.queue if (ev.wait <= 0) and ( ev.daytime is None or (ev.daytime == game.daytime) ) and not ev.disabled and ev.requirements_met() ] queue.sort(key=lambda x: x.priority) return queue def start(self, allow_repeat=True): global _events_completed_all, _events_completed_any, _events_filtered_completed_all, _events_filtered_completed_any queue = self.queue _events_completed_all = all(ev.completed for ev in queue) _events_completed_any = any(ev.completed for ev in queue) queue = self.list_applicable() _events_filtered_completed_all = all(ev.completed for ev in queue) _events_filtered_completed_any = any(ev.completed for ev in queue) self.counter += 1 for ev in queue: if not ev.repeat and ev.completed: continue if config.developer: print(f"Starting event id '{ev.id}' ... ") return ev.start() if queue and allow_repeat: return renpy.random.choice(queue).start() def is_in_queue(self, ev): if isinstance(ev, str): return any(i.id == ev for i in self.queue) return ev in self.queue # def menu(self, title, **kwargs): # hints = self.menu_hints() # title += hints # return renpy.display_menu( [ (title, self) ], **kwargs) def menu_hints(self): queue = self.list_applicable() total_applicable = len(queue) total_events = len(self.queue) completed = 0 hints = [] for ev in queue: if ev.completed: hints.append("v") completed += 1 elif ev.completed_failed: hints.append("x") completed += 1 else: hints.append("o") s = "(" + "".join(hints) + f") {completed}/{total_applicable}" if config.developer: s += f"/{total_events}" return s def _debug(self): queue = self.queue queue.sort(key=lambda x: x.priority) for ev in queue: s = f"ID:{ev.id} QUE:{ev.queued} STA:{ev.started} COM:{ev.completed} COMF:{ev.completed_failed} DIS:{ev.disabled}" print(s) def _debug_menu(self): queue = self.queue queue.sort(key=lambda x: x.priority) menu = [] for ev in queue: req = f"{{color=#00ff00}}{ev.req}{{/color}}" if ev.requirements_met() else f"{{color=#ff0000}}{ev.req}{{/color}}" s = f"{{size=12}}id:{ev.id} label:{ev.label}{{/size}}{{size=8}}\npriority:{ev.priority} Daytime:{ev.daytime} Req:{req} AutoENQ:{ev.autoenqueue} AutoDEQ:{ev.autodequeue}{{/size}}" l = ev.label menu.append( (s, l) ) renpy.display_menu(menu) class Event(object): _queue = None def __init__(self, id, wait=0, priority=5, daytime=None, req=None, label=None, func=None, queue="eventqueue", autoenqueue=False, autodequeue=True, repeat=True, fail_suffixes=("_fail", "too_much", "too_much_public"), ignore_labels=[]): self.id = id self.wait = wait self.priority = priority self.daytime = daytime self.req = req self.label = label self.func = func self.queue = queue self.autoenqueue = autoenqueue self.autodequeue = autodequeue self.repeat = repeat self.fail_suffixes = tuple(fail_suffixes) self.ignore_labels = ignore_labels self.queued = False self.started = False self.completed = False self.completed_failed = False self.disabled = False if not renpy.has_label(self.label): raise Exception("Supplied label does not exist.") if autoenqueue: self.enqueue() def disable(self): self.disabled = True def enable(self): self.disabled = False @property def queue(self): return getattr(store, self._queue).queue if self._queue else None @queue.setter def queue(self, name): self._queue = name if name is not None and not hasattr(store, name): if config.developer: print(f"Creating EventQueue object named '{name}' ...") setattr(store, name, EventQueue(name)) def enqueue(self): self.queued = True if not self in self.queue: self.queue.append(self) def requirements_met(self): if self.req: return eval(self.req) return True def start(self): global _event_completed, _event_completed_failed self.started = True _event_completed = self.completed _event_completed_failed = self.completed_failed if self.autodequeue and self in self.queue: self.queue.remove(self) self.queued = False ## additional requirements check if not self._track_completion in event_callbacks: event_callbacks.append(self._track_completion) if self.func: self.func() if self.label: return renpy.jump(self.label) def _track_completion(self, label, abnormal): if renpy.is_init_phase(): return if label == self.label: # Ignore jumps to self. return if label in self.ignore_labels: # Postpone completing the event until end label returns return # if _last_label_call == label: # # Ignore calls. # return # if abnormal: # return if renpy.game.context().return_stack: # If return stack exists, ignore, because we're probably in a call label. return if label.endswith(self.fail_suffixes): self.completed_failed = True else: self.completed = True if self._track_completion in event_callbacks: event_callbacks.remove(self._track_completion) # def catch_label_call(label, args, kwargs): # if config.developer: # print(f"Called '{label}' with ARGS: {args} KWARGS: {kwargs}") # global _last_label_call # _last_label_call = label def execute_event_callbacks(label, abnormal): if renpy.is_init_phase() or not hasattr(store, "event_callbacks"): return for callback in event_callbacks: callback(label, abnormal) def initialize_callbacks(): if renpy.in_rollback(): return # We need to add these after defaults are finished. renpy.config.label_callbacks.append(execute_event_callbacks) # renpy.config.call_callbacks.append(catch_label_call) def show_events_menu(queues, **kwargs): l = [] for queue in queues: if isinstance(queue, str): queue = getattr(store, queue) if not queue.list_applicable(): continue title = f"-{queue.id}- {queue.menu_hints()}" l.append( (title, queue) ) return renpy.display_menu(l, **kwargs) config.after_default_callbacks.append(initialize_callbacks) init offset = -5 default eventqueue = EventQueue() # default _last_label_call = None