WTS/game/scripts/doll/face.rpy

131 lines
4.1 KiB
Plaintext
Raw Normal View History

2022-05-16 23:48:22 +00:00
init python:
class DollFace(DollMethods):
layer_types = {
"eyemask": -1,
"skin": 0,
"expression": 1,
"overlay": 2,
}
layer_modifiers = {
"zorder": None,
}
def __init__(self, obj):
self.char = obj
self.layers = None
self._face = {k: None for k in {"cheeks", "eyebrows", "eyes", "mouth", "pupils", "tears"}}
self._hash = None
2022-05-16 23:48:22 +00:00
def set_face(self, *args, **kwargs):
if args:
self._face = {k: args[0] for k in self._face}
2022-05-16 23:48:22 +00:00
self._face.update(kwargs)
self.layers = self.get_layers()
self.rebuild_image()
2022-05-16 23:48:22 +00:00
def generate_hash(self):
salt = str( [self.char.name] + sorted( list( self._face.items() ) ))
return hash(salt)
def get_layers(self):
face = self._face
extensions = self.extensions
types = self.layer_types
modifiers = self.layer_modifiers
layers = {}
for part, name in face.items():
if name is None:
continue
path = os.path.join("characters", self.char.name, self.char.pose, "face", part, name)
for f in renpy.list_files():
fp, fn = os.path.split(f)
fn, ext = os.path.splitext(fn)
if not fp == path or not ext in extensions:
continue
ltype, *tails = fn.rsplit("_")
if not ltype in types:
print("Invalid layer type for file: {}".format(f))
continue
zorder = types.get(ltype)
if tails:
lmodifier, *tails = tails
if not lmodifier in modifiers:
print("Invalid modifier for file: {}".format(f))
continue
zorder_mod = modifiers.get(lmodifier)
zorder = (zorder + int(zorder_mod))
layers.setdefault(" ".join([part, name, ltype, lmodifier]), [f, zorder])
else:
layers.setdefault(" ".join([part, name, ltype]), [f, zorder])
2022-05-16 23:48:22 +00:00
return layers
2022-05-16 23:48:22 +00:00
@functools.cache
def build_image(self, hash, matrix=None):
self.layers = layers = self.layers or self.get_layers()
2022-05-16 23:48:22 +00:00
try:
eyemask = layers.pop(next(k for k in layers if "eyemask" in k), [None])[0]
except StopIteration:
eyemask = None
2022-05-16 23:48:22 +00:00
if matrix is None:
matrix = self.char.body.hue
2022-05-16 23:48:22 +00:00
processors = {
"skin": lambda file: Transform(file, matrixcolor=matrix),
"pupils": lambda file: AlphaMask(file, eyemask),
"default": lambda file: Image(file),
}
2022-05-16 23:48:22 +00:00
sprites = []
for identifier, (file, zorder) in layers.items():
2022-05-16 23:48:22 +00:00
expr_type, name, ltype = identifier.rsplit(" ")
if expr_type == "pupils":
if not eyemask:
continue
processor = processors["pupils"]
else:
processor = processors.get(identifier, processors["default"])
processed_file = processor(file)
sprites.append((identifier, processed_file, zorder))
return sprites
@property
def image(self):
if not renpy.is_skipping():
if not self._image_cached:
self._image_cached = True
sprites = self.build_image(self._hash)
sprites.sort(key=itemgetter(2))
sprites = [x[1] for x in sprites]
2022-05-16 23:48:22 +00:00
self._image = Fixed(*sprites, fit_first=True)
return self._image
2022-05-16 23:48:22 +00:00
def rebuild_image(self):
self._hash = self.generate_hash()
self._image_cached = False
2022-05-16 23:48:22 +00:00
# def get_face(self):
# return dict((k, v[0]) for k, v in self.face.items())