2022-05-16 23:48:22 +00:00
|
|
|
|
|
|
|
init -1 python:
|
|
|
|
|
|
|
|
### Classes ###
|
|
|
|
|
|
|
|
class DollDisplayable(renpy.Displayable):
|
|
|
|
def __init__(self, child, **properties):
|
|
|
|
super(DollDisplayable, self).__init__(**properties)
|
|
|
|
self.focusable = None
|
|
|
|
self.child = child
|
|
|
|
|
|
|
|
def render(self, width, height, st, at):
|
|
|
|
rv = renpy.Render(width, height)
|
|
|
|
c = self.child
|
|
|
|
cr = renpy.render(c, width, height, st, at)
|
|
|
|
|
|
|
|
# We need to find the 'true' size of the displayable
|
|
|
|
# otherwise it may end up being the size of a null,
|
|
|
|
# or any other irrelevant element.
|
|
|
|
|
|
|
|
xsize, ysize = cr.get_size()
|
|
|
|
xoffset, yoffset = c.place(rv, 0, 0, width, height, cr)
|
|
|
|
|
|
|
|
width = max(xoffset + xsize, width)
|
|
|
|
height = max(yoffset + ysize, height)
|
|
|
|
|
|
|
|
rv.width = width
|
|
|
|
rv.height = height
|
|
|
|
|
|
|
|
return rv
|
|
|
|
|
|
|
|
def event(self, ev, x, y, st):
|
|
|
|
return None
|
|
|
|
#raise renpy.IgnoreEvent() # Seems to work similar to NullAction
|
|
|
|
|
|
|
|
def focus(self, default=False):
|
|
|
|
raise Exception("Not Implemented")
|
|
|
|
|
|
|
|
def unfocus(self, default=False):
|
|
|
|
raise Exception("Not Implemented")
|
|
|
|
|
|
|
|
def is_focused(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def visit_all(self, callback, seen=None):
|
|
|
|
return
|
|
|
|
|
|
|
|
def visit(self):
|
|
|
|
return []
|
|
|
|
|
2023-04-20 18:59:55 +00:00
|
|
|
class DollMethods(SlottedObject):
|
2022-05-16 23:48:22 +00:00
|
|
|
"""Container class for commonly used methods and attributes"""
|
2023-04-20 18:59:55 +00:00
|
|
|
|
2023-07-11 21:57:49 +00:00
|
|
|
_loading = Text("Loading", align=(0.5, 0.5))
|
IO Overhaul, Refactoring, and more
* Refactored DollFace
* Refactored DollBody
* Refactored DollCum
* Refactored DollCloth
* Refactored Doll
* Refactored clothing item zorders
* Refactored implementation of body, face, cum, clothing layers
* Refactored function calls
* Removed DollLipstick
* Added DollMakeup class, allowing adding dynamic clothes tracking face states
* Added DollClothDynamic, allowing dynamic clothes tracking other cloth states with bangs support
* Added cache to frequently called functions, drastically reducing the overhead
* Added hash system, reducing clone redundancy
* Added layer modifiers support for all types (face, body, cum, clothes etc.)
* Added support for an arbitrary number of equipped multislot clothing items (makeup, tattoos, piercings, etc.)
* Simplified initialization for clothing items and dolls
* Simplified class function calls
* Reduced the number of image creation calls
* Added hue support for additional skin layers
* Added displayable support to image cropping function
* Replaced store cache with built-in functools cache for _list_files function
* Refactored all character files
* and more...
2023-01-14 23:04:54 +00:00
|
|
|
_image = Null()
|
|
|
|
_image_cached = False
|
2022-05-16 23:48:22 +00:00
|
|
|
blacklist_toggles = ("hair", "glasses", "pubes", "piercing", "makeup", "tattoo", "earrings")
|
2022-10-19 21:19:05 +00:00
|
|
|
blacklist_unequip = ("hair",)
|
2023-07-05 20:56:53 +00:00
|
|
|
blacklist_strip = ("pubes", "piercing", "tattoo")
|
2022-05-16 23:48:22 +00:00
|
|
|
multislots = ("makeup", "accessory", "piercing", "tattoo")
|
2023-01-18 20:22:59 +00:00
|
|
|
extensions = {".webp", ".png", ".jxl", ".avif"}
|
2022-05-16 23:48:22 +00:00
|
|
|
sizes = (1010, 1200) # Default sizes used for defining rare cases
|
|
|
|
|
IO Overhaul, Refactoring, and more
* Refactored DollFace
* Refactored DollBody
* Refactored DollCum
* Refactored DollCloth
* Refactored Doll
* Refactored clothing item zorders
* Refactored implementation of body, face, cum, clothing layers
* Refactored function calls
* Removed DollLipstick
* Added DollMakeup class, allowing adding dynamic clothes tracking face states
* Added DollClothDynamic, allowing dynamic clothes tracking other cloth states with bangs support
* Added cache to frequently called functions, drastically reducing the overhead
* Added hash system, reducing clone redundancy
* Added layer modifiers support for all types (face, body, cum, clothes etc.)
* Added support for an arbitrary number of equipped multislot clothing items (makeup, tattoos, piercings, etc.)
* Simplified initialization for clothing items and dolls
* Simplified class function calls
* Reduced the number of image creation calls
* Added hue support for additional skin layers
* Added displayable support to image cropping function
* Replaced store cache with built-in functools cache for _list_files function
* Refactored all character files
* and more...
2023-01-14 23:04:54 +00:00
|
|
|
@property
|
|
|
|
def image(self):
|
2022-05-16 23:48:22 +00:00
|
|
|
if not renpy.is_skipping():
|
IO Overhaul, Refactoring, and more
* Refactored DollFace
* Refactored DollBody
* Refactored DollCum
* Refactored DollCloth
* Refactored Doll
* Refactored clothing item zorders
* Refactored implementation of body, face, cum, clothing layers
* Refactored function calls
* Removed DollLipstick
* Added DollMakeup class, allowing adding dynamic clothes tracking face states
* Added DollClothDynamic, allowing dynamic clothes tracking other cloth states with bangs support
* Added cache to frequently called functions, drastically reducing the overhead
* Added hash system, reducing clone redundancy
* Added layer modifiers support for all types (face, body, cum, clothes etc.)
* Added support for an arbitrary number of equipped multislot clothing items (makeup, tattoos, piercings, etc.)
* Simplified initialization for clothing items and dolls
* Simplified class function calls
* Reduced the number of image creation calls
* Added hue support for additional skin layers
* Added displayable support to image cropping function
* Replaced store cache with built-in functools cache for _list_files function
* Refactored all character files
* and more...
2023-01-14 23:04:54 +00:00
|
|
|
if not self._image_cached:
|
|
|
|
self._image_cached = True
|
|
|
|
self._image = self.build_image()
|
|
|
|
return self._image
|
2023-01-18 20:22:59 +00:00
|
|
|
|
|
|
|
def is_stale(self):
|
|
|
|
curr_hash = self.generate_hash()
|
2024-09-10 13:31:48 +00:00
|
|
|
if (stale := curr_hash != self._hash):
|
|
|
|
self.remove_disk_cache(self._hash)
|
2023-01-18 20:22:59 +00:00
|
|
|
self._hash = curr_hash
|
|
|
|
return stale
|
2023-07-13 23:59:26 +00:00
|
|
|
|
2024-09-10 13:31:48 +00:00
|
|
|
def create_disk_cache(self, d, hash, size=None, type="img"):
|
|
|
|
width, height = size or self.sizes
|
2024-09-10 15:21:25 +00:00
|
|
|
filepath = os.path.join("cache", type, f"{hash}.png").replace("\\", "/") # Windows bleh
|
2024-09-10 13:31:48 +00:00
|
|
|
rendpath = os.path.join("game", filepath)
|
|
|
|
syspath = os.path.join(config.gamedir, "cache", type)
|
|
|
|
|
|
|
|
try:
|
|
|
|
os.makedirs(syspath, exist_ok=True)
|
2024-09-10 13:38:51 +00:00
|
|
|
except OSError:
|
|
|
|
print(f"Warning! Failed to create cache directory: {cache_dir}")
|
2024-09-10 13:31:48 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
if not renpy.loadable(filepath):
|
|
|
|
renpy.render_to_file(d, rendpath, width=width, height=height, resize=True)
|
|
|
|
return Image(filepath)
|
|
|
|
except Exception as e:
|
|
|
|
print(f"Warning! Failed to return cached file: {filepath} - {e}")
|
2024-09-10 13:38:51 +00:00
|
|
|
return d
|
2024-09-10 13:31:48 +00:00
|
|
|
|
|
|
|
def get_disk_cache(self, hash, type="img"):
|
2024-09-10 15:21:25 +00:00
|
|
|
filepath = os.path.join("cache", type, f"{hash}.png").replace("\\", "/") # Windows bleh
|
2024-09-10 13:31:48 +00:00
|
|
|
|
|
|
|
return Image(filepath) if renpy.loadable(filepath) else None
|
|
|
|
|
|
|
|
def remove_disk_cache(self, hash, type="img"):
|
|
|
|
syspath = os.path.join(config.gamedir, "cache", type, f"{hash}.png")
|
|
|
|
|
|
|
|
try:
|
|
|
|
os.unlink(syspath)
|
|
|
|
except FileNotFoundError:
|
2024-09-24 18:59:59 +00:00
|
|
|
print(f"Warning! Cannot remove non-existent cached file: {syspath}")
|
2024-09-10 13:31:48 +00:00
|
|
|
except PermissionError:
|
|
|
|
print(f"Warning! Permission denied to remove cached file: {syspath}")
|
|
|
|
except Exception as e:
|
|
|
|
print(f"Warning! Failed to remove cached file: {syspath} - {e}")
|
|
|
|
|
2023-07-13 23:59:26 +00:00
|
|
|
def DollRebuild():
|
|
|
|
for i in states.dolls:
|
|
|
|
doll = getattr(store, i)
|
2023-07-23 16:40:03 +00:00
|
|
|
|
|
|
|
if doll.is_stale() and not settings.get("multithreading"):
|
|
|
|
doll.show(ignore_skipping=True)
|
|
|
|
|
2023-07-14 01:33:58 +00:00
|
|
|
renpy.restart_interaction()
|
2023-07-13 23:59:26 +00:00
|
|
|
|
|
|
|
config.after_load_callbacks.append(DollRebuild)
|
2023-07-23 16:40:03 +00:00
|
|
|
end_skip_callbacks.append(DollRebuild)
|