diff --git a/prompt_builder.py b/prompt_builder.py index 3e107cb..afc1047 100644 --- a/prompt_builder.py +++ b/prompt_builder.py @@ -1652,6 +1652,7 @@ def _empty_hardcore_position_config() -> dict[str, Any]: "enabled": False, "family": "any", "positions": [], + "require_position": False, "allow_toys": True, "allow_double": True, "allow_penetration": True, @@ -1677,6 +1678,7 @@ def _parse_hardcore_position_config(value: str | dict[str, Any] | None) -> dict[ parsed["enabled"] = bool(parsed.get("enabled", True)) parsed["family"] = _normalize_hardcore_position_family(parsed.get("family")) parsed["positions"] = _normalize_hardcore_position_values(parsed.get("positions")) + parsed["require_position"] = not _is_false(parsed.get("require_position", False)) for key in ("allow_toys", "allow_double", "allow_penetration", "allow_oral", "allow_anal", "allow_climax"): parsed[key] = not _is_false(parsed.get(key, True)) return parsed @@ -1689,6 +1691,8 @@ def _hardcore_position_summary(config: dict[str, Any]) -> str: positions = config.get("positions") or [] if positions: parts.append("positions=" + ",".join(positions)) + elif config.get("require_position"): + parts.append("position_templates=required") disabled = [ label for key, label in ( @@ -1727,6 +1731,7 @@ def build_hardcore_position_pool_json( base["positions"] = existing else: base["positions"] = selected + base["require_position"] = bool(base.get("require_position")) or bool(base["positions"]) or base["family"] != "any" base["summary"] = _hardcore_position_summary(base) return json.dumps(base, ensure_ascii=True, sort_keys=True) @@ -1760,13 +1765,28 @@ def build_hardcore_action_filter_json( config["allow_oral"] = bool(allow_oral) config["allow_anal"] = bool(allow_anal) config["allow_climax"] = bool(allow_climax) - if config["family"] == "oral": + + if not focus_family and config["family"] != "any": + enabled_action_families = { + family + for enabled, family in ( + (config["allow_penetration"], "penetrative"), + (config["allow_oral"], "oral"), + (config["allow_anal"], "anal"), + (config["allow_climax"], "climax"), + ) + if enabled + } + if config["family"] in enabled_action_families and len(enabled_action_families) > 1: + config["family"] = "any" + + if focus == "oral_only": config["allow_oral"] = True config["allow_penetration"] = False - elif config["family"] == "anal": + elif focus == "anal_only": config["allow_anal"] = True config["allow_penetration"] = True - elif config["family"] == "climax": + elif focus == "climax_only": config["allow_climax"] = True config["summary"] = _hardcore_position_summary(config) return json.dumps(config, ensure_ascii=True, sort_keys=True) @@ -1779,7 +1799,7 @@ def _hardcore_position_config_active(config: dict[str, Any]) -> bool: def _hardcore_position_template_required(config: dict[str, Any]) -> bool: if not _hardcore_position_config_active(config): return False - return bool(config.get("positions")) or _normalize_hardcore_position_family(config.get("family")) != "any" + return bool(config.get("require_position")) or bool(config.get("positions")) or _normalize_hardcore_position_family(config.get("family")) != "any" def _is_hardcore_sexual_category(category: dict[str, Any]) -> bool: