Clarify partially removed clothing for penetration

This commit is contained in:
2026-06-25 11:42:47 +02:00
parent b4abd24b35
commit 9f84e56381
2 changed files with 102 additions and 2 deletions
+101 -1
View File
@@ -6342,7 +6342,98 @@ def _insta_of_softcore_pose(rng: random.Random, level: str) -> str:
return g.choose(rng, pool)
def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str) -> str:
PENETRATION_LOWER_ACCESS_TERMS = (
"penetrat",
"thrust",
"vaginal",
"anal",
"rear-entry",
"rear entry",
"front-and-back",
"front and back",
"double",
"doggy",
"missionary",
"cowgirl",
"straddles",
"hips aligned",
"penis into",
"penis inside",
"penis entering",
"toy aligned",
"second penetration point",
)
LOWER_BODY_CLOTHING_TERMS = (
"panty",
"panties",
"brief",
"briefs",
"thong",
"bottom",
"bottoms",
"bodysuit",
"teddy",
"dress",
"skirt",
"shorts",
"jeans",
"trousers",
"pants",
"bikini",
"towel",
"sheet",
"blanket",
)
def _hardcore_row_needs_lower_access(row: dict[str, Any]) -> bool:
axis_values = row.get("item_axis_values")
axis_text = " ".join(str(value) for value in axis_values.values()) if isinstance(axis_values, dict) else ""
text = " ".join(
str(part or "")
for part in (
row.get("source_role_graph"),
row.get("role_graph"),
row.get("item"),
row.get("source_composition"),
row.get("composition"),
axis_text,
)
).lower()
return any(term in text for term in PENETRATION_LOWER_ACCESS_TERMS)
def _outfit_without_lower_body_blockers(outfit: str) -> str:
text = str(outfit or "").strip()
if not text:
return ""
text = re.sub(r"\blingerie set\b", "lingerie top details", text, flags=re.IGNORECASE)
text = re.sub(r"\bbrief set\b", "bra set", text, flags=re.IGNORECASE)
text = re.sub(r"\bbodysuit with\b", "upper bodysuit detail with", text, flags=re.IGNORECASE)
fragments = re.split(r"\s*,\s*|\s+\band\b\s+|\s+\bwith\b\s+|\s+\bunder\b\s+|\s+\bover\b\s+", text)
kept = []
for fragment in fragments:
fragment = fragment.strip(" ,.;")
if not fragment:
continue
lower = fragment.lower()
if any(term in lower for term in LOWER_BODY_CLOTHING_TERMS):
continue
kept.append(fragment)
if not kept:
return ""
deduped = []
seen = set()
for fragment in kept:
key = re.sub(r"\W+", " ", fragment.lower()).strip()
if key and key not in seen:
deduped.append(fragment)
seen.add(key)
return ", ".join(deduped)
def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str, needs_lower_access: bool = False) -> str:
mode = mode if mode in INSTA_OF_HARDCORE_CLOTHING_CONTINUITY else "none"
outfit = str(softcore_outfit or "").strip()
if mode == "none" or not outfit:
@@ -6352,6 +6443,14 @@ def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str) -> str:
return f"Body exposure: {base}."
if mode == "implied_nude":
return f"Body exposure: {base}."
if mode == "partially_removed" and needs_lower_access:
detail = _outfit_without_lower_body_blockers(outfit)
base = (
"Woman A's lower body is clear for penetration; any lower garment is pulled aside or removed below the hips"
)
if detail:
return f"Clothing state: {base}; visible remaining styling: {detail}."
return f"Clothing state: {base}."
return f"Clothing state: {base}; teaser outfit detail: {outfit}."
@@ -6637,6 +6736,7 @@ def build_insta_of_pair(
fallback_hard_clothing_state = "" if has_primary_hardcore_clothing else _insta_of_hardcore_clothing_state(
options["hardcore_clothing_continuity"],
soft_row["item"],
needs_lower_access=_hardcore_row_needs_lower_access(hard_row),
)
hard_clothing_parts = [part for part in (fallback_hard_clothing_state, *character_hardcore_clothing_entries) if part]
hard_clothing_state = " ".join(hard_clothing_parts)
+1 -1
View File
@@ -145,7 +145,7 @@ def _split_tag_text(text: Any) -> list[str]:
text = re.sub(r"\bWoman [A-Z]\b", "woman", text)
text = re.sub(r"\bMan [A-Z]\b", "man", text)
text = re.sub(
r"\b(?:Clothing state|Visual clothing state|teaser outfit detail|softcore visual reference|Sexual scene|Role graph):\s*",
r"\b(?:Clothing state|Visual clothing state|visible remaining styling|teaser outfit detail|softcore visual reference|Sexual scene|Role graph):\s*",
"",
text,
flags=re.IGNORECASE,