Dynamic Cum Layering
* Added dynamic cum layering based on clothing and facial states w/ backwards compatibility * Fixed layers zordering * Refactored default layer dicts * Fixed repr class name in DollClothDynamic * Added back and front zorder modifiers to cum layers * Fixed cum layers not updating on call * Fixed skin layers fighting for zorder with the body
This commit is contained in:
parent
2946efbd2b
commit
22a84479dd
@ -2,7 +2,7 @@ init python:
|
||||
class DollCloth(DollMethods):
|
||||
layer_types = {
|
||||
"mask": "-1",
|
||||
"skin": 0,
|
||||
"skin": 1,
|
||||
"armfix": "+1",
|
||||
"outline": None,
|
||||
"extra": None,
|
||||
|
@ -8,7 +8,7 @@ init python:
|
||||
super().__init__(name, categories, type, id, color, zorder, unlocked, level, blacklist, modpath, parent)
|
||||
|
||||
def __repr__(self):
|
||||
return f"DollMakeup(name={self.name}, categories={self.categories}, type={self.type}, id={self.id}, color={self.color}, zorder={self.zorder}, unlocked={self.unlocked}, level={self.level}, blacklist={self.blacklist}, modpath={self.modpath or None}, tracking={self._tracking}, parent={self.parent})"
|
||||
return f"DollClothDynamic(name={self.name}, categories={self.categories}, type={self.type}, id={self.id}, color={self.color}, zorder={self.zorder}, unlocked={self.unlocked}, level={self.level}, blacklist={self.blacklist}, modpath={self.modpath or None}, tracking={self._tracking}, parent={self.parent})"
|
||||
|
||||
@property
|
||||
def tracking(self):
|
||||
|
@ -1,21 +1,24 @@
|
||||
init python:
|
||||
class DollCum(DollMethods):
|
||||
layer_types = {
|
||||
"skin": 0,
|
||||
"mask": "-1",
|
||||
"skin": 1,
|
||||
"cum": 100,
|
||||
}
|
||||
|
||||
layer_modifiers = {
|
||||
"back": "-300",
|
||||
"front": "+300",
|
||||
"zorder": None,
|
||||
}
|
||||
|
||||
def __init__(self, obj):
|
||||
self.char = obj
|
||||
self._cum = {k: None for k in {"hair", "face", "breasts", "body", "crotch", "pussy", "legs"}}
|
||||
self._cum = {k: None for k in (self.char.clothing_layers | self.char.face_layers).keys()}
|
||||
self._hash = None
|
||||
|
||||
def generate_hash(self):
|
||||
salt = str( [self.char.name, self.char.pose, sorted(list(self._cum.items()))] )
|
||||
salt = str( [self.char.name, self.char.pose, str(self.char.face._hash), str(self.char.face._hash), str([x[0]._hash for x in self.char.clothes.values() if x[0] and x[2]]), sorted(list(self._cum.items()))] )
|
||||
return hash(salt)
|
||||
|
||||
def set_cum(self, *args, **kwargs):
|
||||
@ -27,11 +30,19 @@ init python:
|
||||
|
||||
@functools.cache
|
||||
def get_layers(self, hash):
|
||||
|
||||
def _lookahead(path):
|
||||
return any(fp.startswith(path) for fp in renpy.list_files())
|
||||
|
||||
cum = self._cum
|
||||
|
||||
extensions = self.extensions
|
||||
types = self.layer_types
|
||||
modifiers = self.layer_modifiers
|
||||
face_layers = self.char.face_layers
|
||||
|
||||
active_faces = self.char.face._face
|
||||
active_clothes = self.char.clothes
|
||||
|
||||
layers = {}
|
||||
for part, name in cum.items():
|
||||
@ -39,7 +50,32 @@ init python:
|
||||
if name is None:
|
||||
continue
|
||||
|
||||
path = os.path.join("characters", self.char.name, self.char.pose, "cum", part, name)
|
||||
if part in face_layers:
|
||||
zorder = face_layers.get(part)
|
||||
identifier = active_faces.get(part, "default")
|
||||
path = os.path.join("characters", self.char.name, self.char.pose, "cum", part, name, identifier)
|
||||
else:
|
||||
|
||||
cloth, zorder, is_worn = active_clothes.get(part, [None, None, None])
|
||||
|
||||
if is_worn is None:
|
||||
# Backwards compatibility for old layering system
|
||||
path = os.path.join("characters", self.char.name, self.char.pose, "cum", part, name)
|
||||
|
||||
if config.developer:
|
||||
renpy.notify(f"Using old-type cum layer, consider updating the code; Layer: \"{part}\"")
|
||||
else:
|
||||
if cloth is None or is_worn is False:
|
||||
identifier = "default"
|
||||
modpath = ""
|
||||
zorder = None
|
||||
else:
|
||||
identifier = cloth.id
|
||||
modpath = cloth.modpath
|
||||
zorder = cloth.zorder + 1
|
||||
|
||||
path = os.path.join(modpath, "characters", self.char.name, self.char.pose, "cum", part, name, identifier)
|
||||
path = path if _lookahead(path) else os.path.join(os.path.split(path)[0], (identifier := "default"))
|
||||
|
||||
for f in renpy.list_files():
|
||||
fp, fn = os.path.split(f)
|
||||
@ -54,7 +90,7 @@ init python:
|
||||
print("Invalid layer type for file: {}".format(f))
|
||||
continue
|
||||
|
||||
zorder = types.get(ltype)
|
||||
zorder = zorder or types.get(ltype)
|
||||
|
||||
if tails:
|
||||
lmodifier, *tails = tails
|
||||
|
@ -2,9 +2,8 @@ init python:
|
||||
class DollFace(DollMethods):
|
||||
layer_types = {
|
||||
"eyemask": -1,
|
||||
"skin": 0,
|
||||
"expression": 1,
|
||||
"overlay": 2,
|
||||
"skin": 1,
|
||||
"expression": None,
|
||||
}
|
||||
|
||||
layer_modifiers = {
|
||||
@ -13,7 +12,7 @@ init python:
|
||||
|
||||
def __init__(self, obj):
|
||||
self.char = obj
|
||||
self._face = {k: None for k in {"cheeks", "eyebrows", "eyes", "mouth", "pupils", "tears"}}
|
||||
self._face = {k: None for k in self.char.face_layers.keys()}
|
||||
self._hash = None
|
||||
|
||||
def set_face(self, *args, **kwargs):
|
||||
@ -34,6 +33,7 @@ init python:
|
||||
extensions = self.extensions
|
||||
types = self.layer_types
|
||||
modifiers = self.layer_modifiers
|
||||
face_layers = self.char.face_layers
|
||||
|
||||
layers = {}
|
||||
for part, name in face.items():
|
||||
@ -56,7 +56,7 @@ init python:
|
||||
print("Invalid layer type for file: {}".format(f))
|
||||
continue
|
||||
|
||||
zorder = types.get(ltype)
|
||||
zorder = types.get(ltype) or face_layers.get(part)
|
||||
|
||||
if tails:
|
||||
lmodifier, *tails = tails
|
||||
|
@ -2,27 +2,40 @@ init python:
|
||||
import asyncio
|
||||
|
||||
class Doll(DollMethods):
|
||||
layers = [
|
||||
("buttplug", -11),
|
||||
("makeup", 111), # multislot
|
||||
("accessory", 121), # multislot
|
||||
("piercing", 131), # multislot
|
||||
("tattoo", 141), # multislot
|
||||
("pubes", 151),
|
||||
("stockings", 161),
|
||||
("panties", 171),
|
||||
("garterbelt", 181),
|
||||
("bottom", 191),
|
||||
("bra", 201),
|
||||
("top", 211),
|
||||
("gloves", 221),
|
||||
("robe", 231),
|
||||
("neckwear", 241),
|
||||
("hair", 251),
|
||||
("earrings", 261),
|
||||
("glasses", 271),
|
||||
("headgear", 281)
|
||||
]
|
||||
# 0 - 50 = Skin Layers
|
||||
# 51 - 100 = Face Layers
|
||||
# 101 - 300+ = Clothes Layers
|
||||
|
||||
clothing_layers = {
|
||||
"buttplug": -11,
|
||||
"makeup": 111, # multislot
|
||||
"accessory": 121, # multislot
|
||||
"piercing": 131, # multislot
|
||||
"tattoo": 141, # multislot
|
||||
"pubes": 151,
|
||||
"stockings": 161,
|
||||
"panties": 171,
|
||||
"garterbelt": 181,
|
||||
"bottom": 191,
|
||||
"bra": 201,
|
||||
"top": 211,
|
||||
"gloves": 221,
|
||||
"robe": 231,
|
||||
"neckwear": 241,
|
||||
"hair": 251,
|
||||
"earrings": 261,
|
||||
"glasses": 271,
|
||||
"headgear": 281
|
||||
}
|
||||
|
||||
face_layers = {
|
||||
"tears": 75,
|
||||
"eyebrows": 70,
|
||||
"pupils": 65,
|
||||
"eyes": 60,
|
||||
"mouth": 55,
|
||||
"cheeks": 51
|
||||
}
|
||||
|
||||
def __init__(self, name):
|
||||
self.wardrobe = {}
|
||||
@ -30,7 +43,7 @@ init python:
|
||||
self.blacklist = []
|
||||
self.outfits = []
|
||||
self.name = name
|
||||
self.clothes = {layer[0]: [None, layer[1], True] for layer in self.layers}
|
||||
self.clothes = {k: [None, v, True] for k, v in self.clothing_layers.items()}
|
||||
self.face = DollFace(self)
|
||||
self.body = DollBody(self)
|
||||
self.cum = DollCum(self)
|
||||
@ -131,6 +144,7 @@ init python:
|
||||
|
||||
self.rebuild_blacklist()
|
||||
update_chibi(self.name)
|
||||
self.cum.is_stale()
|
||||
self.is_stale()
|
||||
|
||||
if renpy.showing(get_character_tag(self.name), layer=self.layer):
|
||||
@ -191,6 +205,7 @@ init python:
|
||||
|
||||
self.rebuild_blacklist()
|
||||
update_chibi(self.name)
|
||||
self.cum.is_stale()
|
||||
self.is_stale()
|
||||
|
||||
if renpy.showing(get_character_tag(self.name), layer=self.layer):
|
||||
@ -313,6 +328,7 @@ init python:
|
||||
self.face.set_face(*args, **kwargs)
|
||||
|
||||
[x[0].is_stale() for x in self.clothes.values() if isinstance(x[0], DollMakeup) and x[2]]
|
||||
self.cum.is_stale()
|
||||
|
||||
def get_face(self):
|
||||
"""Returns a dictionary containing currently set facial expressions. Used in character studio."""
|
||||
|
Loading…
Reference in New Issue
Block a user