LVPWB/lvpwb/edit_mode.py

371 lines
17 KiB
Python

from __future__ import annotations
import json
import math
from typing import Any
import lvpwb as app
def show_roster(config: dict[str, Any]) -> None:
names = sorted(config["roster"], key=str.casefold)
if not names:
print("The roster is empty.")
return
print(f"\nRoster ({len(names)} wrestlers):")
for position, name in enumerate(names, 1):
print(f" {position}. {name}")
def edit_custom_roster(config: dict[str, Any]) -> None:
while True:
choices = ["Add wrestler", "Remove wrestler", "View roster", "Done"]
labels = ["Add a wrestler", "Remove a wrestler", "View roster (read-only)",
f"Done ({len(config['roster'])} listed)"]
action = app.ask_choice("Edit roster", choices, labels=labels)
if action == 3:
break
if action == 0:
name = app.ask("Wrestler name").strip()
if not name:
print("Wrestler name cannot be blank.")
elif any(existing.casefold() == name.casefold() for existing in config["roster"]):
print("That wrestler is already in this roster.")
else:
config["roster"].append(name)
elif action == 2:
app.show_roster(config)
elif not config["roster"]:
print("The roster is empty.")
else:
index = app.ask_choice("Remove wrestler", config["roster"])
removed = config["roster"].pop(index)
config["women_roster"] = [name for name in config["women_roster"]
if name.casefold() != removed.casefold()]
config["light_heavyweight_roster"] = [
name for name in config.get("light_heavyweight_roster", [])
if name.casefold() != removed.casefold()
]
def edit_custom_match_types(config: dict[str, Any]) -> None:
while True:
existing = config["match_types"]
choices = list(range(len(existing))) + ["add", "remove", "done"]
labels = [f"{item['name']} ({' vs '.join(map(str, item['sides']))}, "
f"base {item['base_rating']:.1f}%)" for item in existing]
labels.extend(["Add a match type", "Remove a match type", "Done"])
action = app.ask_choice("Edit match types", choices, labels=labels)
if action == len(existing) + 2:
return
if action == len(existing) + 1:
if not existing:
print("Add at least one match type before removing one.")
continue
remove_index = app.ask_choice("Remove which match type", list(range(len(existing))),
labels=[item["name"] for item in existing])
existing.pop(remove_index)
continue
if action == len(existing):
name = app.ask("New match type name").strip()
if not name:
print("Match type name cannot be blank.")
continue
if any(item["name"].casefold() == name.casefold() for item in existing):
print("That match type already exists.")
continue
side_sizes = app.parse_side_sizes(app.ask("Wrestler counts per side, comma-separated (e.g. 1,1)"))
if side_sizes is None:
print("Enter at least two positive side sizes, such as 1,1 or 2,2.")
continue
if sum(side_sizes) > len(config["roster"]):
print("This match type needs more wrestlers than the roster contains.")
continue
base_default = app.MATCH_BASE_RATINGS.get(name, 4.5)
while True:
try:
base_rating = float(app.ask("Base rating percentage", str(base_default)))
if math.isfinite(base_rating) and 0 <= base_rating <= 100:
break
except ValueError:
pass
print("Enter a rating from 0 to 100.")
default_outcomes = app.MATCH_OUTCOME_OPTIONS.get(name, app.STANDARD_MATCH_OUTCOMES)
raw_outcomes = app.ask("Legal outcomes, comma-separated", ", ".join(default_outcomes))
outcomes = [outcome.strip() for outcome in raw_outcomes.split(",") if outcome.strip()]
if not outcomes:
print("At least one legal outcome is required.")
continue
existing.append({"name": name, "sides": side_sizes,
"base_rating": base_rating, "outcomes": outcomes})
def edit_custom_titles(config: dict[str, Any]) -> None:
while True:
existing = config["championships"]
choices = list(range(len(existing))) + ["add", "remove", "done"]
labels = [f"{item['name']} ({item['kind']})" for item in existing]
labels.extend(["Add a championship", "Remove a championship", "Done"])
action = app.ask_choice("Edit championship rankings", choices, labels=labels)
if action == len(existing) + 2:
return
if action == len(existing) + 1:
if not existing:
print("There are no championships to remove.")
continue
remove_index = app.ask_choice("Remove which championship", list(range(len(existing))),
labels=[item["name"] for item in existing])
existing.pop(remove_index)
continue
if action == len(existing):
name = app.ask("Championship name").strip()
if not name or any(item["name"].casefold() == name.casefold() for item in existing):
print("Enter a non-empty championship name not already listed.")
continue
kind_options = ["singles", "tag", "women", "light_heavyweight"]
kind_labels = ["Singles / open", "Tag team", "Women's division",
"Light-Heavyweight division"]
kind = kind_options[app.ask_choice("Championship type", kind_options, labels=kind_labels)]
existing.append({"name": name, "kind": kind})
def edit_eligible_roster(config: dict[str, Any], field: str, division: str,
require_eligible: bool = False) -> None:
eligible = config.setdefault(field, [])
while True:
choices = ["add", "remove", "done"]
labels = ["Add eligible wrestler", "Remove eligible wrestler", "Done"]
action = app.ask_choice(f"{division} eligibility", choices, labels=labels)
if action == 2:
if require_eligible and not eligible:
print(f"Choose at least one eligible wrestler for the {division} division.")
continue
return
if action == 0:
available = [name for name in config["roster"]
if name.casefold() not in {item.casefold() for item in eligible}]
if not available:
print("Every roster member is already listed.")
continue
selected = app.choose_roster_member(available, "Add which wrestler")
eligible.append(selected)
elif not eligible:
print("No eligible wrestlers are listed.")
else:
remove_index = app.ask_choice("Remove eligible wrestler", eligible)
eligible.pop(remove_index)
def edit_women_roster(config: dict[str, Any]) -> None:
edit_eligible_roster(config, "women_roster", "Women's division")
def edit_light_heavyweight_roster(config: dict[str, Any]) -> None:
edit_eligible_roster(
config, "light_heavyweight_roster", "Light-Heavyweight", require_eligible=True
)
def edit_custom_shows(config: dict[str, Any]) -> None:
while True:
shows = config["shows"]
labels = [f"{brand}: {shows[brand]}" for brand in app.SHOW_BRANDS] + ["Done"]
action = app.ask_choice("Edit show names", list(app.SHOW_BRANDS) + ["done"], labels=labels)
if action == len(app.SHOW_BRANDS):
return
brand = app.SHOW_BRANDS[action]
while True:
name = app.ask(f"{brand} show name", shows[brand]).strip()
if not name:
print("Show name cannot be blank.")
continue
others = [shows[other] for other in app.SHOW_BRANDS if other != brand]
if any(other.casefold() == name.casefold() for other in others):
print("Show names must be distinct from each other.")
continue
shows[brand] = name
break
def edit_custom_profile(config: dict[str, Any]) -> dict[str, Any]:
while True:
options = ["identity", "shows", "roster", "match_types", "titles", "women"]
labels = ["Game/federation, platform, screenshot directory",
f"Show names (Raw: {config['shows']['Raw']})",
f"Edit roster ({len(config['roster'])} wrestlers)",
f"Edit match types ({len(config['match_types'])})",
f"Edit championships ({len(config['championships'])})",
f"Edit Women's eligibility ({len(config['women_roster'])})"]
has_light_heavyweight = any(
title.get("kind") == "light_heavyweight" for title in config["championships"]
)
if has_light_heavyweight:
options.append("light_heavyweight")
labels.append(
f"Edit Light-Heavyweight eligibility "
f"({len(config.get('light_heavyweight_roster', []))})"
)
options.append("save")
labels.append("Validate and save")
action = app.ask_choice("BYOG editor", options, labels=labels)
if action == 0:
config["game_title"] = app.ask("Game title", config["game_title"]).strip()
config["federation_name"] = app.ask("Federation name", config["federation_name"]).strip()
platform_options = ["ps1", "ps2", "other"]
platform_labels = ["PlayStation 1", "PlayStation 2", "Other / platform agnostic"]
config["platform"] = platform_options[
app.ask_choice("Platform", platform_options, labels=platform_labels)
]
current_directory = config.get("screenshot_directory") or "platform default"
screenshot_directory = app.ask(
f"Screenshot directory override (absolute, app-relative, or ~; current: "
f"{current_directory}; blank uses platform default)"
).strip()
config["screenshot_directory"] = screenshot_directory or None
elif action == 1:
app.edit_custom_shows(config)
elif action == 2:
app.edit_custom_roster(config)
elif action == 3:
app.edit_custom_match_types(config)
elif action == 4:
app.edit_custom_titles(config)
elif action == 5:
app.edit_women_roster(config)
elif has_light_heavyweight and action == 6:
app.edit_light_heavyweight_roster(config)
else:
if has_light_heavyweight and not config.get("light_heavyweight_roster"):
print("Choose eligible Light-Heavyweight wrestlers before saving this profile.")
continue
try:
return app.save_custom_game(config)
except ValueError as exc:
print(f"Cannot save game profile: {exc}")
def builtin_profile_for_copy(game_id: str, custom_id: str) -> dict[str, Any]:
definitions = [
{"name": name, "sides": list(sides),
"base_rating": app.MATCH_BASE_RATINGS.get(name, 4.5),
"outcomes": list(app.MATCH_OUTCOME_OPTIONS.get(name, app.STANDARD_MATCH_OUTCOMES))}
for name, sides in app.MATCH_TYPES[game_id]
]
return app.validate_custom_game({
"schema_version": 1,
"game_id": custom_id,
"game_title": app.game_title(game_id) + " Custom Edition",
"federation_name": app.federation_name(game_id),
"platform": "ps1" if game_id in app.PS1_GAMES else "ps2",
"roster": app.load_roster(game_id),
"match_types": definitions,
"championships": app.title_definitions_for_game(game_id),
"women_roster": sorted(app.WOMEN_ROSTERS.get(game_id, set())),
"light_heavyweight_roster": app.load_roster(game_id),
"shows": {"Raw": "Monday Night Raw", "SmackDown": "Thursday Night SmackDown!",
"PPV": "WWF PPV"},
})
def create_custom_game() -> dict[str, Any]:
title = app.ask("Game title").strip()
while not title:
title = app.ask("Game title cannot be blank; enter a game title").strip()
federation = app.ask("Federation name", "My Wrestling Federation").strip()
if not federation:
federation = "My Wrestling Federation"
platform_options = ["ps1", "ps2", "other"]
platform_labels = ["PlayStation 1", "PlayStation 2", "Other / platform agnostic"]
platform = platform_options[app.ask_choice("Platform", platform_options, labels=platform_labels)]
shows: dict[str, str] = {}
print("\nName this federation's three shows (weekly #1, weekly #2, and the big event).")
for brand in app.SHOW_BRANDS:
default = app.DEFAULT_CUSTOM_SHOWS[brand]
while True:
name = app.ask(f"{brand} show name", default).strip() or default
if any(other.casefold() == name.casefold() for other in shows.values()):
print("Show names must be distinct from each other.")
continue
shows[brand] = name
break
config: dict[str, Any] = {
"schema_version": 1,
"game_id": app.new_custom_game_id(federation, title),
"game_title": title,
"federation_name": federation,
"platform": platform,
"roster": [],
"match_types": [],
"championships": [],
"women_roster": [],
"light_heavyweight_roster": [],
"shows": shows,
}
app.edit_custom_roster(config)
config["match_types"] = app.default_custom_match_types(len(config["roster"]))
if not config["match_types"]:
config["match_types"] = [{"name": "Singles", "sides": [1, 1],
"base_rating": 4.5,
"outcomes": list(app.STANDARD_MATCH_OUTCOMES)}]
print("\nAdd this federation's championship divisions (or finish with none).")
app.edit_custom_titles(config)
if any(title["kind"] == "women" for title in config["championships"]):
app.edit_women_roster(config)
if any(title["kind"] == "light_heavyweight" for title in config["championships"]):
app.edit_light_heavyweight_roster(config)
return app.edit_custom_profile(config)
def choose_builtin_game() -> str:
ids = list(app.BUILTIN_GAME_IDS)
return ids[app.ask_choice("Built-in game to copy", ids,
labels=[app.GAMES[game_id]["title"] for game_id in ids])]
def clone_builtin_game() -> dict[str, Any]:
app.refresh_custom_games()
source_id = app.choose_builtin_game()
title = app.ask("Custom game title", app.game_title(source_id) + " Custom Edition").strip()
federation = app.ask("Federation name", app.federation_name(source_id)).strip()
config = app.builtin_profile_for_copy(source_id, app.new_custom_game_id(federation, title))
config["game_title"] = title or config["game_title"]
config["federation_name"] = federation or config["federation_name"]
if any(item["kind"] == "light_heavyweight" for item in config["championships"]):
config["light_heavyweight_roster"] = []
app.edit_light_heavyweight_roster(config)
print(f"Copied {app.game_title(source_id)} into the editable BYOG directory.")
return app.edit_custom_profile(config)
def edit_existing_custom_game() -> None:
app.refresh_custom_games()
game_ids = sorted(app.CUSTOM_GAME_CONFIGS)
if not game_ids:
print("No custom games exist yet. Create or copy one first.")
return
labels = [app.game_display_name(game_id) for game_id in game_ids]
game_id = game_ids[app.ask_choice("Choose custom game to edit", game_ids, labels=labels)]
editable = json.loads(json.dumps(app.CUSTOM_GAME_CONFIGS[game_id]))
app.edit_custom_profile(editable)
app.refresh_custom_games()
def manage_games() -> None:
while True:
app.refresh_custom_games()
action = app.ask_choice(
"BYOG / Manage Games",
["create", "copy", "edit", "back"],
labels=["Create a new game and federation", "Copy a built-in WWF game to edit",
f"Edit a custom game ({len(app.CUSTOM_GAME_CONFIGS)} available)",
"Back to main menu"],
)
if action == 0:
app.create_custom_game()
elif action == 1:
app.clone_builtin_game()
elif action == 2:
app.edit_existing_custom_game()
else:
return
__all__ = ['builtin_profile_for_copy', 'choose_builtin_game', 'clone_builtin_game', 'create_custom_game', 'edit_custom_match_types', 'edit_custom_profile', 'edit_custom_roster', 'edit_custom_shows', 'edit_custom_titles', 'edit_eligible_roster', 'edit_existing_custom_game', 'edit_light_heavyweight_roster', 'edit_women_roster', 'manage_games', 'show_roster']