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):
|
class DollCloth(DollMethods):
|
||||||
layer_types = {
|
layer_types = {
|
||||||
"mask": "-1",
|
"mask": "-1",
|
||||||
"skin": 0,
|
"skin": 1,
|
||||||
"armfix": "+1",
|
"armfix": "+1",
|
||||||
"outline": None,
|
"outline": None,
|
||||||
"extra": None,
|
"extra": None,
|
||||||
|
@ -8,7 +8,7 @@ init python:
|
|||||||
super().__init__(name, categories, type, id, color, zorder, unlocked, level, blacklist, modpath, parent)
|
super().__init__(name, categories, type, id, color, zorder, unlocked, level, blacklist, modpath, parent)
|
||||||
|
|
||||||
def __repr__(self):
|
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
|
@property
|
||||||
def tracking(self):
|
def tracking(self):
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
init python:
|
init python:
|
||||||
class DollCum(DollMethods):
|
class DollCum(DollMethods):
|
||||||
layer_types = {
|
layer_types = {
|
||||||
"skin": 0,
|
"mask": "-1",
|
||||||
|
"skin": 1,
|
||||||
"cum": 100,
|
"cum": 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
layer_modifiers = {
|
layer_modifiers = {
|
||||||
|
"back": "-300",
|
||||||
|
"front": "+300",
|
||||||
"zorder": None,
|
"zorder": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self.char = 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
|
self._hash = None
|
||||||
|
|
||||||
def generate_hash(self):
|
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)
|
return hash(salt)
|
||||||
|
|
||||||
def set_cum(self, *args, **kwargs):
|
def set_cum(self, *args, **kwargs):
|
||||||
@ -27,11 +30,19 @@ init python:
|
|||||||
|
|
||||||
@functools.cache
|
@functools.cache
|
||||||
def get_layers(self, hash):
|
def get_layers(self, hash):
|
||||||
|
|
||||||
|
def _lookahead(path):
|
||||||
|
return any(fp.startswith(path) for fp in renpy.list_files())
|
||||||
|
|
||||||
cum = self._cum
|
cum = self._cum
|
||||||
|
|
||||||
extensions = self.extensions
|
extensions = self.extensions
|
||||||
types = self.layer_types
|
types = self.layer_types
|
||||||
modifiers = self.layer_modifiers
|
modifiers = self.layer_modifiers
|
||||||
|
face_layers = self.char.face_layers
|
||||||
|
|
||||||
|
active_faces = self.char.face._face
|
||||||
|
active_clothes = self.char.clothes
|
||||||
|
|
||||||
layers = {}
|
layers = {}
|
||||||
for part, name in cum.items():
|
for part, name in cum.items():
|
||||||
@ -39,8 +50,33 @@ init python:
|
|||||||
if name is None:
|
if name is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
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)
|
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():
|
for f in renpy.list_files():
|
||||||
fp, fn = os.path.split(f)
|
fp, fn = os.path.split(f)
|
||||||
fn, ext = os.path.splitext(fn)
|
fn, ext = os.path.splitext(fn)
|
||||||
@ -54,7 +90,7 @@ init python:
|
|||||||
print("Invalid layer type for file: {}".format(f))
|
print("Invalid layer type for file: {}".format(f))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
zorder = types.get(ltype)
|
zorder = zorder or types.get(ltype)
|
||||||
|
|
||||||
if tails:
|
if tails:
|
||||||
lmodifier, *tails = tails
|
lmodifier, *tails = tails
|
||||||
|
@ -2,9 +2,8 @@ init python:
|
|||||||
class DollFace(DollMethods):
|
class DollFace(DollMethods):
|
||||||
layer_types = {
|
layer_types = {
|
||||||
"eyemask": -1,
|
"eyemask": -1,
|
||||||
"skin": 0,
|
"skin": 1,
|
||||||
"expression": 1,
|
"expression": None,
|
||||||
"overlay": 2,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layer_modifiers = {
|
layer_modifiers = {
|
||||||
@ -13,7 +12,7 @@ init python:
|
|||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self.char = 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
|
self._hash = None
|
||||||
|
|
||||||
def set_face(self, *args, **kwargs):
|
def set_face(self, *args, **kwargs):
|
||||||
@ -34,6 +33,7 @@ init python:
|
|||||||
extensions = self.extensions
|
extensions = self.extensions
|
||||||
types = self.layer_types
|
types = self.layer_types
|
||||||
modifiers = self.layer_modifiers
|
modifiers = self.layer_modifiers
|
||||||
|
face_layers = self.char.face_layers
|
||||||
|
|
||||||
layers = {}
|
layers = {}
|
||||||
for part, name in face.items():
|
for part, name in face.items():
|
||||||
@ -56,7 +56,7 @@ init python:
|
|||||||
print("Invalid layer type for file: {}".format(f))
|
print("Invalid layer type for file: {}".format(f))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
zorder = types.get(ltype)
|
zorder = types.get(ltype) or face_layers.get(part)
|
||||||
|
|
||||||
if tails:
|
if tails:
|
||||||
lmodifier, *tails = tails
|
lmodifier, *tails = tails
|
||||||
|
@ -2,27 +2,40 @@ init python:
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
class Doll(DollMethods):
|
class Doll(DollMethods):
|
||||||
layers = [
|
# 0 - 50 = Skin Layers
|
||||||
("buttplug", -11),
|
# 51 - 100 = Face Layers
|
||||||
("makeup", 111), # multislot
|
# 101 - 300+ = Clothes Layers
|
||||||
("accessory", 121), # multislot
|
|
||||||
("piercing", 131), # multislot
|
clothing_layers = {
|
||||||
("tattoo", 141), # multislot
|
"buttplug": -11,
|
||||||
("pubes", 151),
|
"makeup": 111, # multislot
|
||||||
("stockings", 161),
|
"accessory": 121, # multislot
|
||||||
("panties", 171),
|
"piercing": 131, # multislot
|
||||||
("garterbelt", 181),
|
"tattoo": 141, # multislot
|
||||||
("bottom", 191),
|
"pubes": 151,
|
||||||
("bra", 201),
|
"stockings": 161,
|
||||||
("top", 211),
|
"panties": 171,
|
||||||
("gloves", 221),
|
"garterbelt": 181,
|
||||||
("robe", 231),
|
"bottom": 191,
|
||||||
("neckwear", 241),
|
"bra": 201,
|
||||||
("hair", 251),
|
"top": 211,
|
||||||
("earrings", 261),
|
"gloves": 221,
|
||||||
("glasses", 271),
|
"robe": 231,
|
||||||
("headgear", 281)
|
"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):
|
def __init__(self, name):
|
||||||
self.wardrobe = {}
|
self.wardrobe = {}
|
||||||
@ -30,7 +43,7 @@ init python:
|
|||||||
self.blacklist = []
|
self.blacklist = []
|
||||||
self.outfits = []
|
self.outfits = []
|
||||||
self.name = name
|
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.face = DollFace(self)
|
||||||
self.body = DollBody(self)
|
self.body = DollBody(self)
|
||||||
self.cum = DollCum(self)
|
self.cum = DollCum(self)
|
||||||
@ -131,6 +144,7 @@ init python:
|
|||||||
|
|
||||||
self.rebuild_blacklist()
|
self.rebuild_blacklist()
|
||||||
update_chibi(self.name)
|
update_chibi(self.name)
|
||||||
|
self.cum.is_stale()
|
||||||
self.is_stale()
|
self.is_stale()
|
||||||
|
|
||||||
if renpy.showing(get_character_tag(self.name), layer=self.layer):
|
if renpy.showing(get_character_tag(self.name), layer=self.layer):
|
||||||
@ -191,6 +205,7 @@ init python:
|
|||||||
|
|
||||||
self.rebuild_blacklist()
|
self.rebuild_blacklist()
|
||||||
update_chibi(self.name)
|
update_chibi(self.name)
|
||||||
|
self.cum.is_stale()
|
||||||
self.is_stale()
|
self.is_stale()
|
||||||
|
|
||||||
if renpy.showing(get_character_tag(self.name), layer=self.layer):
|
if renpy.showing(get_character_tag(self.name), layer=self.layer):
|
||||||
@ -313,6 +328,7 @@ init python:
|
|||||||
self.face.set_face(*args, **kwargs)
|
self.face.set_face(*args, **kwargs)
|
||||||
|
|
||||||
[x[0].is_stale() for x in self.clothes.values() if isinstance(x[0], DollMakeup) and x[2]]
|
[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):
|
def get_face(self):
|
||||||
"""Returns a dictionary containing currently set facial expressions. Used in character studio."""
|
"""Returns a dictionary containing currently set facial expressions. Used in character studio."""
|
||||||
|
Loading…
Reference in New Issue
Block a user