2023-03-20 21:44:55 +00:00
|
|
|
init python early:
|
2022-05-16 23:48:22 +00:00
|
|
|
# Import commonly used python modules
|
|
|
|
import time
|
|
|
|
import datetime
|
|
|
|
import math
|
|
|
|
import random
|
|
|
|
import pygame
|
|
|
|
import fnmatch
|
|
|
|
import posixpath
|
|
|
|
import re
|
2022-05-26 20:50:54 +00:00
|
|
|
import string
|
2023-03-16 22:55:14 +00:00
|
|
|
import functools
|
2023-11-11 20:02:36 +00:00
|
|
|
import timeit as timeit_module
|
2022-05-16 23:48:22 +00:00
|
|
|
from bisect import bisect
|
|
|
|
from operator import itemgetter
|
|
|
|
from operator import add as _add
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
get_volume_preference = renpy.game.preferences.get_volume
|
|
|
|
|
|
|
|
def num_to_word(n, readable=True):
|
|
|
|
"""Transcript numbers (integers) into readable words."""
|
|
|
|
n = int(n)
|
|
|
|
units = ("","one","two","three","four","five","six","seven","eight","nine")
|
|
|
|
teens = ("","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen")
|
|
|
|
tens = ("","ten","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety")
|
|
|
|
thousands = ("","thousand","million","billion","trillion","quadrillion","quintillion","sextillion","septillion","octillion","nonillion","decillion","undecillion","duodecillion","tredecillion","quattuordecillion","sexdecillion","septendecillion","octodecillion","novemdecillion","vigintillion")
|
|
|
|
|
|
|
|
output = []
|
|
|
|
if n == 0:
|
|
|
|
output.append("zero")
|
|
|
|
else:
|
|
|
|
s = str(n)
|
2022-09-21 20:57:04 +00:00
|
|
|
groups = (len(s)+2)//3
|
2022-05-16 23:48:22 +00:00
|
|
|
s = s.zfill(groups*3)
|
|
|
|
|
2022-09-21 20:57:04 +00:00
|
|
|
for i in range(0, groups*3, 3):
|
2022-05-16 23:48:22 +00:00
|
|
|
h,t,u = int(s[i]), int(s[i+1]), int(s[i+2])
|
2022-09-21 20:57:04 +00:00
|
|
|
g = groups-(i//3+1)
|
2022-05-16 23:48:22 +00:00
|
|
|
|
|
|
|
if h > 0:
|
|
|
|
output.append(units[h]+" hundred")
|
|
|
|
if t > 1:
|
|
|
|
if u > 0:
|
|
|
|
output.append(tens[t]+"-"+units[u])
|
|
|
|
else:
|
|
|
|
output.append(tens[t])
|
|
|
|
elif t == 1:
|
|
|
|
if u > 0:
|
|
|
|
output.append(teens[u])
|
|
|
|
else:
|
|
|
|
output.append(tens[t])
|
|
|
|
else:
|
|
|
|
if u > 0:
|
|
|
|
output.append(units[u])
|
|
|
|
|
|
|
|
if g > 0 and (h+t+u) > 0:
|
|
|
|
if i == (groups*3)-6:
|
|
|
|
output.append(thousands[g]+" and")
|
|
|
|
else:
|
|
|
|
output.append(thousands[g]+",")
|
|
|
|
|
|
|
|
if readable:
|
|
|
|
output = " ".join(output)
|
|
|
|
return output
|
|
|
|
|
|
|
|
def clamp(n, smallest, largest):
|
|
|
|
return max(smallest, min(n, largest))
|
|
|
|
|
|
|
|
def white_tint(image):
|
|
|
|
return Transform( image, matrixcolor=TintMatrix((1.1, 1.1, 1.1)) )
|
|
|
|
|
|
|
|
def gray_tint(image):
|
|
|
|
return Transform( image, matrixcolor=SaturationMatrix(0.0) )
|
|
|
|
|
|
|
|
def yellow_tint(image):
|
|
|
|
return Transform( image, matrixcolor=TintMatrix((1.2, 1.1, 0.7)) )
|
|
|
|
|
|
|
|
def image_hover(image, brightness=0.12):
|
|
|
|
"""Returns slightly brighter image used during hover events"""
|
|
|
|
return Transform( image, matrixcolor=BrightnessMatrix(brightness) )
|
|
|
|
|
|
|
|
def image_alpha(image, alpha=0.5):
|
|
|
|
"""Returns an image with changed alpha 0 - fully transparent 1 - fully visible"""
|
|
|
|
return Transform( image, matrixcolor=OpacityMatrix(alpha) )
|
|
|
|
|
|
|
|
def set_clipboard(txt):
|
|
|
|
txt = str(txt)
|
2023-04-22 15:39:15 +00:00
|
|
|
pygame.scrap.put(pygame.scrap.SCRAP_TEXT, txt.encode())
|
2022-05-16 23:48:22 +00:00
|
|
|
|
|
|
|
def get_clipboard():
|
|
|
|
clipboard = pygame.scrap.get(pygame.scrap.SCRAP_TEXT)
|
|
|
|
if clipboard:
|
2023-04-22 15:39:15 +00:00
|
|
|
return clipboard.decode()
|
2022-05-16 23:48:22 +00:00
|
|
|
return None
|
|
|
|
|
|
|
|
def evaluate(txt):
|
2023-02-09 19:35:52 +00:00
|
|
|
try:
|
|
|
|
return __import__('ast').literal_eval(txt)
|
|
|
|
except Exception as e:
|
2023-02-10 23:12:16 +00:00
|
|
|
print("Error evaluating data:")
|
2023-02-09 19:35:52 +00:00
|
|
|
print(e)
|
2022-05-16 23:48:22 +00:00
|
|
|
|
|
|
|
def disable_game_menu():
|
|
|
|
setattr(renpy.store, "_game_menu_screen", None)
|
|
|
|
|
|
|
|
def enable_game_menu():
|
|
|
|
setattr(renpy.store, "_game_menu_screen", "save_screen")
|
|
|
|
|
|
|
|
def make_revertable(obj):
|
|
|
|
if isinstance(obj, _list):
|
|
|
|
return [make_revertable(x) for x in obj]
|
|
|
|
elif isinstance(obj, _dict):
|
2023-11-11 19:54:41 +00:00
|
|
|
return dict((make_revertable(k), make_revertable(v)) for (k,v) in obj.items())
|
2022-05-16 23:48:22 +00:00
|
|
|
else:
|
|
|
|
return obj
|
|
|
|
|
|
|
|
def is_integer(s):
|
|
|
|
s = str(s)
|
2023-11-11 19:58:07 +00:00
|
|
|
if not s:
|
|
|
|
return False
|
|
|
|
if s[0] in ("-", "+"):
|
|
|
|
# calling lstrip("0+-") would be faster but not exactly identical
|
|
|
|
s = s[1:]
|
|
|
|
if s.lstrip("0").isdigit():
|
|
|
|
return True
|
|
|
|
return False
|
2022-05-16 23:48:22 +00:00
|
|
|
|
|
|
|
def timeit(func, loops=10000, args=(), kwargs={}):
|
2023-11-11 20:02:36 +00:00
|
|
|
rv = timeit_module.timeit("func(*args, **kwargs)", number=loops, globals=dict(func=func, args=args, kwargs=kwargs))
|
|
|
|
print(f"The task has taken {rv} seconds to finish")
|
|
|
|
|
|
|
|
def autorange(func, args=(), kwargs={}):
|
|
|
|
loops, time = timeit_module.Timer("func(*args, **kwargs)", globals=dict(func=func, args=args, kwargs=kwargs)).autorange()
|
|
|
|
print(f"The task has taken {time/loops} seconds to finish ({loops} iterations in {time} seconds)")
|
2022-05-16 23:48:22 +00:00
|
|
|
|
|
|
|
def list_swap_values(l, val1, val2):
|
|
|
|
"""Mutates the original list."""
|
|
|
|
l[val1], l[val2] = l[val2], l[val1]
|
|
|
|
|
|
|
|
def natsort_key(s, pattern=re.compile("([0-9]+)")):
|
|
|
|
return [int(t) if t.isdigit() else t.lower() for t in pattern.split(str(s))]
|
|
|
|
|
|
|
|
def tts(s):
|
|
|
|
renpy.display.tts.tts(str(s))
|
|
|
|
|
|
|
|
def is_in_lead(house):
|
2022-09-21 20:57:04 +00:00
|
|
|
if isinstance(house, str):
|
2022-05-16 23:48:22 +00:00
|
|
|
house = getattr(renpy.store, house)
|
|
|
|
|
|
|
|
return (house == max(gryffindor, slytherin, ravenclaw, hufflepuff))
|
|
|
|
|
|
|
|
def play_potion_return(who):
|
|
|
|
if game.daytime:
|
|
|
|
return
|
|
|
|
|
|
|
|
for i in inventory.get_instances_of_type("potion"):
|
|
|
|
if not who in i.usable_on:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if not i.in_progress[who]:
|
|
|
|
continue
|
|
|
|
|
|
|
|
i.ret(who)
|
2022-05-26 20:50:54 +00:00
|
|
|
|
|
|
|
def strip(s):
|
|
|
|
# We need a custom strip implementation because we cannot tell
|
|
|
|
# if the raw argument isn't encapsulated in double, or triple quotes
|
|
|
|
if s.startswith(('"', "'")) and s.endswith(('"', "'")):
|
|
|
|
return s[1:-1]
|
|
|
|
return s
|
|
|
|
|
|
|
|
def matches(s1, s2, filter=" "):
|
|
|
|
return s1.replace(filter, "") == s2.replace(filter, "")
|
2022-07-23 20:57:42 +00:00
|
|
|
|
2023-02-07 19:22:05 +00:00
|
|
|
def istype(inst, clss):
|
2023-11-11 19:42:56 +00:00
|
|
|
if isinstance(clss, (list, tuple, set)):
|
|
|
|
return type(inst) in clss
|
|
|
|
return type(inst) is clss
|
2023-02-07 19:22:05 +00:00
|
|
|
|
2022-07-23 20:57:42 +00:00
|
|
|
class IntLike(python_object):
|
|
|
|
# Does not support rollback
|
|
|
|
|
|
|
|
def __init__(self, callable):
|
|
|
|
self._callable = callable
|
|
|
|
|
|
|
|
def __call__(self):
|
|
|
|
return self._callable()
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return repr(self())
|
|
|
|
|
|
|
|
def __add__(self, value):
|
|
|
|
raise Exception("IntLike does not support add")
|
|
|
|
|
|
|
|
def __eq__(self, value):
|
|
|
|
return self._callable() == value
|
|
|
|
|
|
|
|
def __gt__(self, value):
|
|
|
|
return self._callable() > value
|
|
|
|
|
|
|
|
def __lt__(self, value):
|
|
|
|
return self._callable() < value
|
|
|
|
|
|
|
|
def __ge__(self, value):
|
|
|
|
return self.__gt__(value) or self.__eq__(value)
|
|
|
|
|
|
|
|
def __le__(self, value):
|
|
|
|
return self.__lt__(value) or self.__eq__(value)
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
return len(self._callable())
|
2023-06-16 14:51:48 +00:00
|
|
|
|
|
|
|
def execute_callbacks(callbacks):
|
2023-10-18 11:48:35 +00:00
|
|
|
for callback in callbacks: callback()
|
|
|
|
|
|
|
|
def extract_number(key):
|
|
|
|
match = re.match(r'^(\d+)', key)
|
|
|
|
if match:
|
|
|
|
return int(match.group(1))
|
|
|
|
return float('inf') # Return a large number for non-numeric keys
|
2023-11-21 20:02:49 +00:00
|
|
|
|
|
|
|
def call_screen_in_new_context(sc_name, *args, **kwargs):
|
|
|
|
"""
|
|
|
|
Calls the `sc_name` screen in a new context, passing it *args and **kwargs.
|
|
|
|
Returns the value returned by the screen, if any.
|
|
|
|
"""
|
|
|
|
return renpy.call_in_new_context("call_screen", sc_name, *args, **kwargs)
|