WTS/game/scripts/utility/common_functions.rpy
LoafyLemon 7069cc1294 Refactoring
* Refactored old house points references
* Updates set_points method to use a dict to work with multiple changes at once.
2024-04-27 15:24:14 +01:00

240 lines
8.4 KiB
Plaintext

init python early:
# Import commonly used python modules
import time
import datetime
import math
import random
import pygame
import fnmatch
import posixpath
import re
import functools
import timeit as timeit_module
from operator import itemgetter
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)
groups = (len(s)+2)//3
s = s.zfill(groups*3)
for i in range(0, groups*3, 3):
h,t,u = int(s[i]), int(s[i+1]), int(s[i+2])
g = groups-(i//3+1)
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)
pygame.scrap.put(pygame.scrap.SCRAP_TEXT, txt.encode())
def get_clipboard():
clipboard = pygame.scrap.get(pygame.scrap.SCRAP_TEXT)
if clipboard:
return clipboard.decode()
return None
def evaluate(txt):
try:
return __import__('ast').literal_eval(txt)
except Exception as e:
print("Error evaluating data:")
print(e)
def reset_variables(*args):
"""
Resets the given variables to their default values.
As of Ren'py version 8.2.1:
After reevaluating this function and the underlying Ren'py code, this function is deemed safe to use because Ren'Py employs a similar implementation internally, and it is also utilized for user-defined statements. Essentially, it calls execute_default on a node marked as ever_been_changed, followed by running py_eval_bytecode to add it to the global store. The potential side effects to consider is when config.after_default_callbacks is provided, or direct object references are in use. However, this can be easily patched if necessary.
"""
# Refer to renpy.ast.Default.set_default for implementation details
defaults_set = renpy.store._defaults_set
changed_set = renpy.store.__dict__.ever_been_changed
for arg in args:
if arg in defaults_set:
if arg in changed_set:
defaults_set.remove(arg)
changed_set.remove(arg)
elif config.developer:
raise Exception(f"The variable {arg!r} was not previously set with a default value.")
renpy.execute_default_statement(False)
def disable_game_menu():
global _game_menu_screen
_game_menu_screen = None
def enable_game_menu():
global _game_menu_screen
_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):
return dict((make_revertable(k), make_revertable(v)) for (k,v) in obj.items())
else:
return obj
def is_integer(s):
s = str(s)
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
def timeit(func, loops=10000, args=(), kwargs={}):
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)")
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):
if isinstance(house, str):
house = getattr(states.env, house)
return (house == max(states.env.gryffindor, states.env.slytherin, states.env.ravenclaw, states.env.hufflepuff))
def play_potion_return(who):
if states.env.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)
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, "")
def istype(inst, clss):
if isinstance(clss, (list, tuple, set)):
return type(inst) in clss
return type(inst) is clss
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())
def execute_callbacks(callbacks):
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