LoafyLemon
13a7017773
* Added internal counter for queues * Simplified global vars for event completion checks. * Temporarily disabled Hermione's statistics menu * Replaced counter/points checks with status flags. * Disabled debug profiling for images
290 lines
8.6 KiB
Plaintext
290 lines
8.6 KiB
Plaintext
|
|
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 |