← Files QuestforgeARCHIVED FILE
scripts/action_options.py
3.15 KB · Sep 30, 2026 · 23:13 UTC
"""Format player-facing Questforge action options with modifiers and risk."""
from __future__ import annotations
import argparse
import json
import sys
from dataclasses import asdict, dataclass
from typing import Iterable
@dataclass(frozen=True)
class ActionOption:
"""One suggested action the player may choose or ignore."""
action: str
check: str
modifier: str
difficulty: str
risk: str
success: str
failure_forward: str
def parse_option(value: str) -> ActionOption:
parts = [part.strip() for part in value.split("|")]
if len(parts) != 7:
raise ValueError(
"Options must use 7 pipe-separated fields: action|check|modifier|"
"difficulty|risk|success|failure_forward."
)
return ActionOption(*parts)
def format_option_table(options: list[ActionOption]) -> str:
if not options:
raise ValueError("At least one action option is required.")
rows = [
"| Option | Check | Mod | Difficulty | Visible Risk |",
"| --- | --- | ---: | --- | --- |",
]
for option in options:
rows.append(
(
f"| {cell(option.action)} | {cell(option.check)} | "
f"{cell(option.modifier)} | {cell(option.difficulty)} | "
f"{cell(option.risk)} |"
)
)
rows.extend(
[
"",
"You can also describe a different action.",
"",
"Resolution notes:",
]
)
for option in options:
rows.append(
(
f"- **{option.action}**: success means "
f"{sentence(option.success)} Failure still moves play: "
f"{sentence(option.failure_forward)}"
)
)
return "\n".join(rows)
def cell(value: str) -> str:
return " ".join(value.split()).replace("|", "\\|")
def sentence(value: str) -> str:
stripped_value = value.strip()
if stripped_value.endswith((".", "!", "?")):
return stripped_value
return stripped_value + "."
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Render Questforge action options with modifiers."
)
parser.add_argument(
"--option",
action="append",
required=True,
help=(
"Pipe-separated action option: action|check|modifier|difficulty|"
"risk|success|failure_forward"
),
)
parser.add_argument(
"--format", choices=("markdown", "json"), default="markdown"
)
return parser
def main(arguments: Iterable[str] | None = None) -> int:
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8")
parsed_arguments = build_parser().parse_args(arguments)
options = [parse_option(value) for value in parsed_arguments.option]
if parsed_arguments.format == "json":
print(
json.dumps(
[asdict(option) for option in options],
indent=2,
ensure_ascii=False,
)
)
else:
print(format_option_table(options))
return 0
if __name__ == "__main__":
raise SystemExit(main())
SHA-256: 7e31b489ac1cf688dbb62d97accf147a2c64acf148e7dd8c9ab24fa75481983e