From 3ad2c273e952b8ba731953233105308503d16219 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Thu, 25 Jun 2026 12:25:03 +0200 Subject: [PATCH] Add default visible male hardcore clothing --- prompt_builder.py | 72 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/prompt_builder.py b/prompt_builder.py index cd7a361..a950b4d 100644 --- a/prompt_builder.py +++ b/prompt_builder.py @@ -6386,6 +6386,28 @@ LOWER_BODY_CLOTHING_TERMS = ( "blanket", ) +INSTA_OF_HARDCORE_MEN_CLOTHING_LOWER_ACCESS = [ + "wears an open button shirt with jeans lowered below the hips for sexual contact", + "wears a fitted tee pushed up with trousers lowered below the hips", + "keeps a dark shirt on while pants and underwear are pulled down enough for penetration", + "wears an open overshirt with jeans pushed down at the thighs", + "wears a hoodie lifted at the waist with sweatpants lowered below the hips", + "wears gym shorts pulled down enough for sexual contact with his shirt still on", + "keeps a casual shirt on with belt open and pants lowered below the hips", + "wears a half-open shirt with lower garments pushed down for clear sexual contact", +] + +INSTA_OF_HARDCORE_MEN_CLOTHING_VISIBLE = [ + "wears an open button shirt with jeans unfastened", + "wears a fitted tee with pants opened at the waist", + "keeps a dark shirt on with trousers loosened", + "wears an open overshirt with jeans partly lowered", + "wears gym shorts lowered enough for sexual contact with a towel nearby", + "wears a hoodie lifted at the waist with sweatpants loosened", + "wears a casual shirt with belt open and pants partly lowered", + "wears a half-open shirt with underwear waistband visible", +] + def _hardcore_row_needs_lower_access(row: dict[str, Any]) -> bool: axis_values = row.get("item_axis_values") @@ -6454,6 +6476,30 @@ def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str, needs_low return f"Clothing state: {base}; teaser outfit detail: {outfit}." +def _default_man_hardcore_clothing_entries( + men_count: int, + pov_labels: list[str] | None, + configured_entries: list[str], + rng: random.Random, + needs_lower_access: bool, +) -> list[str]: + pov_set = set(pov_labels or []) + configured_labels = { + match.group(1) + for entry in configured_entries + for match in [re.match(r"^\s*(Man [A-Z])\b", str(entry or ""))] + if match + } + pool = INSTA_OF_HARDCORE_MEN_CLOTHING_LOWER_ACCESS if needs_lower_access else INSTA_OF_HARDCORE_MEN_CLOTHING_VISIBLE + entries = [] + for index in range(max(0, int(men_count))): + label = f"Man {chr(ord('A') + index)}" + if label in pov_set or label in configured_labels: + continue + entries.append(_hardcore_clothing_sentence(label, g.choose(rng, pool))) + return entries + + def _insta_of_partner_styling( seed_config: dict[str, int], seed: int, @@ -6732,14 +6778,31 @@ def build_insta_of_pair( pov_character_labels, hard_content_rng, ) + needs_lower_access = _hardcore_row_needs_lower_access(hard_row) + default_man_hardcore_clothing_entries = _default_man_hardcore_clothing_entries( + hard_men_count, + pov_character_labels, + character_hardcore_clothing_entries, + hard_content_rng, + needs_lower_access, + ) has_primary_hardcore_clothing = any(entry.startswith("Woman A") for entry in character_hardcore_clothing_entries) 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), + needs_lower_access=needs_lower_access, ) - hard_clothing_parts = [part for part in (fallback_hard_clothing_state, *character_hardcore_clothing_entries) if part] - hard_clothing_state = " ".join(hard_clothing_parts) + hard_clothing_parts = [ + part.strip().rstrip(".") + for part in ( + fallback_hard_clothing_state, + *character_hardcore_clothing_entries, + *default_man_hardcore_clothing_entries, + ) + if str(part or "").strip() + ] + hard_clothing_state = "; ".join(hard_clothing_parts) + hard_clothing_sentence = f"{hard_clothing_state}. " if hard_clothing_state else "" if "body is fully exposed" in hard_clothing_state.lower() or "bare skin unobstructed" in hard_clothing_state.lower(): hard_scene = _body_exposure_scene_text(hard_scene) hard_row["source_scene_text"] = hard_row.get("source_scene_text") or hard_row.get("scene_text", "") @@ -6776,7 +6839,7 @@ def build_insta_of_pair( f"Cast descriptors: {cast_descriptor_text}. " f"{pov_directive + ' ' if pov_directive else ''}" f"{'Keep Woman A visually central from the POV camera. ' if pov_character_labels else 'Keep Woman A visually central. '}" - f"{hard_clothing_state} " + f"{hard_clothing_sentence}" f"Role graph: {hard_row['role_graph']} Sexual scene: {hard_row['item']}. " f"Setting: {hard_scene}. " f"{_labeled_expression_sentence('Facial expressions', hard_row.get('expression'))}" @@ -6829,6 +6892,7 @@ def build_insta_of_pair( "pov_prompt_directive": pov_directive, "softcore_partner_styling": soft_partner_styling, "character_hardcore_clothing": character_hardcore_clothing_entries, + "default_man_hardcore_clothing": default_man_hardcore_clothing_entries, "hardcore_clothing_state": hard_clothing_state, "hardcore_detail_density": hard_detail_density, "hardcore_position_config": hard_row.get("hardcore_position_config", {}),