Mirror softcore outfit in hard clothing state

This commit is contained in:
2026-06-28 10:14:51 +02:00
parent 5acda5227c
commit f681fe2949
2 changed files with 122 additions and 54 deletions
+104 -51
View File
@@ -269,12 +269,36 @@ def hardcore_row_access_flags(row: dict[str, Any]) -> dict[str, bool]:
def _outfit_without_lower_body_blockers(outfit: str) -> str:
_removed, remaining = _outfit_split_by_terms(
outfit,
LOWER_BODY_CLOTHING_TERMS,
replacements=(
(r"\blingerie set\b", "lingerie top details"),
(r"\bbrief set\b", "bra set"),
(r"\bbodysuit with\b", "upper bodysuit detail with"),
),
)
return remaining
def _outfit_without_upper_body_blockers(outfit: str) -> str:
_removed, remaining = _outfit_split_by_terms(
outfit,
UPPER_BODY_CLOTHING_TERMS,
replacements=(
(r"\blingerie set\b", "lingerie styling"),
(r"\bbalconette bra and brief set\b", "briefs and garter styling"),
),
)
return remaining
def _split_outfit_fragments(outfit: str, replacements: tuple[tuple[str, str], ...] = ()) -> list[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)
return []
for pattern, replacement in replacements:
text = re.sub(pattern, replacement, 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:
@@ -282,12 +306,7 @@ def _outfit_without_lower_body_blockers(outfit: str) -> str:
fragment = re.sub(r"^(?:and|with|under|over)\s+", "", fragment, flags=re.IGNORECASE)
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:
@@ -295,36 +314,82 @@ def _outfit_without_lower_body_blockers(outfit: str) -> str:
if key and key not in seen:
deduped.append(fragment)
seen.add(key)
return ", ".join(deduped)
return deduped
def _outfit_without_upper_body_blockers(outfit: str) -> str:
text = str(outfit or "").strip()
if not text:
return ""
text = re.sub(r"\blingerie set\b", "lingerie styling", text, flags=re.IGNORECASE)
text = re.sub(r"\bbalconette bra and brief set\b", "briefs and garter styling", text, flags=re.IGNORECASE)
fragments = re.split(r"\s*,\s*|\s+\band\s+|\s+\bwith\s+|\s+\bunder\s+|\s+\bover\s+", text)
kept = []
for fragment in fragments:
fragment = fragment.strip(" ,.;")
fragment = re.sub(r"^(?:and|with|under|over)\s+", "", fragment, flags=re.IGNORECASE)
if not fragment:
continue
def _join_fragments(fragments: list[str]) -> str:
return ", ".join(fragment for fragment in fragments if fragment)
def _outfit_split_by_terms(
outfit: str,
terms: tuple[str, ...],
replacements: tuple[tuple[str, str], ...] = (),
) -> tuple[str, str]:
removed: list[str] = []
remaining: list[str] = []
for fragment in _split_outfit_fragments(outfit, replacements):
lower = fragment.lower()
if any(term in lower for term in UPPER_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)
if any(term in lower for term in terms):
removed.append(fragment)
else:
remaining.append(fragment)
return _join_fragments(removed), _join_fragments(remaining)
def _is_plural_clothing_phrase(text: str) -> bool:
lower = text.lower()
if "," in text or " and " in lower:
return True
return any(term in lower for term in ("briefs", "panties", "shorts", "jeans", "trousers", "pants", "stockings"))
def _partially_removed_outfit_state(outfit: str, woman_access: str, implied: bool = False) -> str:
outfit = str(outfit or "").strip()
if not outfit:
return "Woman A's body is partly exposed" if implied else "Woman A's outfit is pushed aside where needed"
if woman_access == "lower":
removed, remaining = _outfit_split_by_terms(
outfit,
LOWER_BODY_CLOTHING_TERMS,
replacements=(
(r"\blingerie set\b", "lingerie top details"),
(r"\bbrief set\b", "bra set"),
(r"\bbodysuit with\b", "upper bodysuit detail with"),
),
)
verb = "are" if _is_plural_clothing_phrase(removed) else "is"
lead = (
f"Woman A's {removed} {verb} pulled aside or removed below the hips"
if removed
else "Woman A's lower body is clear, with the outfit pulled aside below the hips"
)
if remaining:
remain_verb = "remain" if _is_plural_clothing_phrase(remaining) else "remains"
return f"{lead}; {remaining} {remain_verb} visible from the same outfit"
return lead
if woman_access == "upper":
removed, remaining = _outfit_split_by_terms(
outfit,
UPPER_BODY_CLOTHING_TERMS,
replacements=(
(r"\blingerie set\b", "lingerie styling"),
(r"\bbalconette bra and brief set\b", "briefs and garter styling"),
),
)
verb = "are" if _is_plural_clothing_phrase(removed) else "is"
lead = (
f"Woman A's {removed} {verb} pulled open or pushed aside from her breasts and chest"
if removed
else "Woman A's upper body is clear, with the outfit pulled open at the chest"
)
if remaining:
remain_verb = "remain" if _is_plural_clothing_phrase(remaining) else "remains"
return f"{lead}; {remaining} {remain_verb} visible from the same outfit"
return lead
if implied:
return f"Woman A's {outfit} is loosened and partly slipping off, leaving her body partly exposed"
return f"Woman A's {outfit} is pushed aside and partly removed where needed"
def hardcore_clothing_state(
@@ -340,22 +405,10 @@ def hardcore_clothing_state(
base = continuity_map[mode]
if mode == "explicit_nude":
return f"Body exposure: {base}."
if mode == "implied_nude":
return f"Body exposure: {base}."
if mode == "partially_removed" and woman_access == "lower":
detail = _outfit_without_lower_body_blockers(outfit)
base = "Woman A's lower body is clear; 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}."
if mode == "partially_removed" and woman_access == "upper":
detail = _outfit_without_upper_body_blockers(outfit)
base = "Woman A's breasts and upper body are clear; any bra cup, bodice, or top panel is pulled aside or removed"
if detail:
return f"Clothing state: {base}; visible remaining styling: {detail}."
return f"Clothing state: {base}."
if mode == "partially_removed":
return f"Clothing state: Woman A keeps the outfit mostly on; teaser outfit detail: {outfit}."
return f"Clothing state: {_partially_removed_outfit_state(outfit, woman_access)}."
if mode == "implied_nude":
return f"Clothing state: {_partially_removed_outfit_state(outfit, woman_access, implied=True)}."
return f"Clothing state: {base}; teaser outfit detail: {outfit}."