From 82e22eab251d6c559ce67383a161f68befa48765 Mon Sep 17 00:00:00 2001 From: markmental Date: Mon, 2 Nov 2026 19:42:33 -0500 Subject: [PATCH] Add customizable Light Heavyweight division --- README.md | 10 +-- lvpwb/edit_mode.py | 58 ++++++++++++++--- lvpwb/games.py | 29 +++++++-- lvpwb/results.py | 13 +++- lvpwb/seasons.py | 72 ++++++++++++++++++--- test_lvpwb.py | 154 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 309 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 1c75c18..44800ea 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,10 @@ is saved after each edit or result, so you can stop and resume later. The main menu also has a fully randomized one-off show (choose a game first) and Season Mode. Seasons save separately under `seasons/` and book Raw → Thursday -Night SmackDown! → WWF PPV repeatedly. New season champions can be selected, randomized, or left -vacant. Semi-random cards use division rankings and repeat-match rivalries; +Night SmackDown! → WWF PPV repeatedly. New season champions can be selected, +randomized, or left vacant. Built-in seasons ask which wrestlers are eligible +for the Light-Heavyweight division; that selection is saved with the season. +Semi-random cards use division rankings and repeat-match rivalries; title defenses are possible on any show and are weighted more heavily on PPVs. PPV cards may feature up to two title defenses, while weekly shows may feature one. Mark each season match with a ranking division, and separately mark title @@ -69,8 +71,8 @@ federation, not just the built-in WWF games: - **Create a new game and federation** — name the game, pick the federation and platform (PlayStation 1, PlayStation 2, or other), name the federation's three shows, list the roster, edit the suggested match types, and add any - championship/ranking divisions (singles, tag team, or women's). A women's - division asks which roster members are eligible. + championship/ranking divisions (singles, tag team, women's, or + Light-Heavyweight). Restricted divisions let you choose eligible wrestlers. - **Copy a built-in WWF game to edit** — clones any built-in game into your own editable profile; the built-in games themselves stay unchanged. - **Edit a custom game** — reopen any saved profile. diff --git a/lvpwb/edit_mode.py b/lvpwb/edit_mode.py index 15cb025..4ee742b 100644 --- a/lvpwb/edit_mode.py +++ b/lvpwb/edit_mode.py @@ -41,6 +41,10 @@ def edit_custom_roster(config: dict[str, Any]) -> None: 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: @@ -117,19 +121,24 @@ def edit_custom_titles(config: dict[str, Any]) -> None: 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"] - kind_labels = ["Singles / open", "Tag team", "Women's division"] + 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_women_roster(config: dict[str, Any]) -> None: +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("Women's division eligibility", choices, labels=labels) - eligible = config["women_roster"] + 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"] @@ -146,6 +155,16 @@ def edit_women_roster(config: dict[str, Any]) -> None: 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"] @@ -169,13 +188,24 @@ def edit_custom_shows(config: dict[str, Any]) -> None: def edit_custom_profile(config: dict[str, Any]) -> dict[str, Any]: while True: - options = ["identity", "shows", "roster", "match_types", "titles", "women", "save"] + 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'])})", "Validate and save"] + 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() @@ -201,7 +231,12 @@ def edit_custom_profile(config: dict[str, Any]) -> dict[str, Any]: 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: @@ -225,6 +260,7 @@ def builtin_profile_for_copy(game_id: str, custom_id: str) -> dict[str, Any]: "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"}, }) @@ -261,6 +297,7 @@ def create_custom_game() -> dict[str, Any]: "match_types": [], "championships": [], "women_roster": [], + "light_heavyweight_roster": [], "shows": shows, } app.edit_custom_roster(config) @@ -273,6 +310,8 @@ def create_custom_game() -> dict[str, Any]: 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) @@ -290,6 +329,9 @@ def clone_builtin_game() -> dict[str, Any]: 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) @@ -326,4 +368,4 @@ def manage_games() -> None: 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_existing_custom_game', 'edit_women_roster', 'manage_games', 'show_roster'] +__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'] diff --git a/lvpwb/games.py b/lvpwb/games.py index cf52104..1bf0ef6 100644 --- a/lvpwb/games.py +++ b/lvpwb/games.py @@ -61,7 +61,15 @@ def title_definitions_for_game(game_id: str, if game_id in app.CUSTOM_GAME_CONFIGS: return [dict(title) for title in app.CUSTOM_GAME_CONFIGS[game_id]["championships"]] return [ - {"name": name, "kind": "tag" if name == "Tag Team" else "women" if name == "Women's" else "singles"} + { + "name": name, + "kind": ( + "tag" if name == "Tag Team" + else "women" if name == "Women's" + else "light_heavyweight" if name == "Light-Heavyweight" + else "singles" + ), + } for name in app.CHAMPIONSHIPS ] @@ -243,16 +251,27 @@ def validate_custom_game(data: Any) -> dict[str, Any]: for item in raw_titles: if not isinstance(item, dict): raise ValueError("Each championship must be a JSON object with name and kind.") - name, kind = item.get("name"), str(item.get("kind", "singles")).casefold() + name = item.get("name") if not isinstance(name, str) or not name.strip() or name.casefold() in seen_titles: raise ValueError("Championship names must be non-empty and unique.") - if kind not in {"singles", "tag", "women"}: - raise ValueError(f"Championship '{name}' kind must be singles, tag, or women.") + default_kind = "light_heavyweight" if name.casefold() == "light-heavyweight" else "singles" + kind = str(item.get("kind", default_kind)).casefold() + if kind not in {"singles", "tag", "women", "light_heavyweight"}: + raise ValueError( + f"Championship '{name}' kind must be singles, tag, women, or light_heavyweight." + ) championships.append({"name": name.strip(), "kind": kind}) seen_titles.add(name.casefold()) women = data.get("women_roster", []) if not isinstance(women, list) or any(name not in roster for name in women): raise ValueError("women_roster must be a subset of the roster.") + light_heavyweight = data.get("light_heavyweight_roster", []) + if (not isinstance(light_heavyweight, list) + or any(name not in roster for name in light_heavyweight)): + raise ValueError("light_heavyweight_roster must be a subset of the roster.") + if (any(title["kind"] == "light_heavyweight" for title in championships) + and not light_heavyweight): + raise ValueError("light_heavyweight_roster must contain eligible wrestlers.") raw_shows = data.get("shows") if raw_shows is not None and not isinstance(raw_shows, dict): raise ValueError("shows must be an object with Raw, SmackDown, and PPV names.") @@ -278,6 +297,7 @@ def validate_custom_game(data: Any) -> dict[str, Any]: "match_types": match_types, "championships": championships, "women_roster": list(dict.fromkeys(women)), + "light_heavyweight_roster": list(dict.fromkeys(light_heavyweight)), "shows": shows, } @@ -306,6 +326,7 @@ def builtin_game_profile(game_id: str) -> dict[str, Any]: "match_types": app.match_type_definitions(game_id), "championships": app.title_definitions_for_game(game_id), "women_roster": sorted(app.WOMEN_ROSTERS.get(game_id, set())), + "light_heavyweight_roster": None, "shows": {"Raw": "Monday Night Raw", "SmackDown": "Thursday Night SmackDown!", "PPV": "WWF PPV"}, } diff --git a/lvpwb/results.py b/lvpwb/results.py index 13fd322..6842b66 100644 --- a/lvpwb/results.py +++ b/lvpwb/results.py @@ -141,9 +141,16 @@ def record_match_result(card: dict[str, Any], index: int, auto_simulate: bool = if not is_player_match and not auto_simulate: print(f"Only {wrestler}'s matches can be recorded manually in Wrestler control.") return False - if match.get("title_defense") and season and not app.validate_title_defense(season, match): - print("Edit this match's participants or title status before recording its result.") - return False + if season: + valid_division = ( + app.validate_title_defense(season, match) + if match.get("title_defense") + else app.validate_match_division_eligibility(season, match) + ) + if not valid_division: + if match.get("title_defense"): + print("Edit this match's participants or title status before recording its result.") + return False if auto_simulate: app.simulate_match_result(card, index, season) diff --git a/lvpwb/seasons.py b/lvpwb/seasons.py index 8eaaa71..4c38bbe 100644 --- a/lvpwb/seasons.py +++ b/lvpwb/seasons.py @@ -13,9 +13,10 @@ def season_path(season_id: str) -> Path: def new_season_state(name: str, game_id: str, champions: dict[str, list[str] | None] | None = None, - season_id: str | None = None) -> dict[str, Any]: + season_id: str | None = None, + profile: dict[str, Any] | None = None) -> dict[str, Any]: champions = champions or {} - profile = app.game_profile(game_id) + profile = profile or app.game_profile(game_id) title_definitions = [dict(item) for item in profile["championships"]] title_state: dict[str, Any] = {} for definition in title_definitions: @@ -69,6 +70,14 @@ def load_season(path_or_id: Path | str) -> dict[str, Any]: if not payload.get("season_id") or not payload.get("name"): raise ValueError(f"Season save is missing its identity: {path}") payload.setdefault("game_config", app.game_profile(payload["game_id"])) + if payload["game_id"] in app.BUILTIN_GAME_IDS: + for definitions in (payload.get("title_definitions"), + payload["game_config"].get("championships")): + if isinstance(definitions, list): + for definition in definitions: + if (definition.get("name") == "Light-Heavyweight" + and definition.get("kind") == "singles"): + definition["kind"] = "light_heavyweight" payload.setdefault("game_title", payload["game_config"].get("game_title", app.game_title(payload["game_id"]))) payload.setdefault("federation_name", payload["game_config"].get( "federation_name", app.federation_name(payload["game_id"]) @@ -174,13 +183,45 @@ def eligible_roster_for_division(game_id: str, division: str, profile: dict[str, Any] | None = None) -> list[str]: profile = profile or app.game_profile(game_id) roster = list(profile.get("roster", [])) if roster is None else roster - if app.championship_kind(game_id, division, profile) == "women": - eligible_names = profile.get("women_roster", []) + eligibility_field = { + "women": "women_roster", + "light_heavyweight": "light_heavyweight_roster", + }.get(app.championship_kind(game_id, division, profile)) + if eligibility_field: + eligible_names = profile.get(eligibility_field) + # Older seasons do not have a Light-Heavyweight eligibility snapshot. + if eligible_names is None: + return list(roster) eligible = {name.casefold() for name in eligible_names} return [name for name in roster if name.casefold() in eligible] return list(roster) +def validate_match_division_eligibility(season: dict[str, Any], + match: dict[str, Any]) -> bool: + division = match.get("ranking_division") + if division not in app.season_title_names(season): + return True + if app.season_championship_kind(season, division) not in {"women", "light_heavyweight"}: + return True + profile = app.season_game_profile(season) + eligible = { + name.casefold() + for name in app.eligible_roster_for_division( + season["game_id"], division, profile=profile + ) + } + excluded = [ + name for side in match.get("sides", []) for name in side + if name.casefold() not in eligible + ] + if excluded: + names = ", ".join(dict.fromkeys(excluded)) + print(f"{names} is not eligible for the {division} division.") + return False + return True + + def choose_roster_member(names: list[str], prompt: str) -> str: if not names: raise ValueError("No eligible wrestlers are available for that championship.") @@ -217,6 +258,13 @@ def create_season() -> dict[str, Any]: game_id = app.choose_game() profile = app.game_profile(game_id) name = app.ask("Season name", f"{app.game_display_name(game_id)} Season") + has_light_heavyweight = any( + definition.get("kind") == "light_heavyweight" + for definition in profile["championships"] + ) + if has_light_heavyweight and game_id in app.BUILTIN_GAME_IDS: + profile["light_heavyweight_roster"] = [] + app.edit_light_heavyweight_roster(profile) champions: dict[str, list[str] | None] = {} used: set[str] = set() for definition in profile["championships"]: @@ -225,7 +273,7 @@ def create_season() -> dict[str, Any]: champions[division] = holder if holder: used.update(name.casefold() for name in holder) - season = app.new_season_state(name, game_id, champions) + season = app.new_season_state(name, game_id, champions, profile=profile) app.save_season(season) print(f"Season saved: {app.season_path(season['season_id'])}") return season @@ -302,7 +350,9 @@ def season_rivalry_id(sides: list[list[str]]) -> str | None: def record_season_match(season: dict[str, Any], card: dict[str, Any], - match: dict[str, Any], match_index: int) -> None: + match: dict[str, Any], match_index: int) -> bool: + if not app.validate_match_division_eligibility(season, match): + return False division = match.get("ranking_division") winner = match.get("winner_side") if division in app.season_title_names(season) and winner is not None: @@ -351,6 +401,7 @@ def record_season_match(season: dict[str, Any], card: dict[str, Any], if match.get("rivalry_payoff"): rivalry["resolved"] = True rivalry["resolved_at"] = card.get("season_show", "") + return True def validate_title_defense(season: dict[str, Any], match: dict[str, Any]) -> bool: @@ -360,6 +411,8 @@ def validate_title_defense(season: dict[str, Any], match: dict[str, Any]) -> boo if division not in app.season_title_names(season): print("A title defense must be assigned to a championship division.") return False + if not app.validate_match_division_eligibility(season, match): + return False holder = season["champions"][division].get("holder") if holder and not any(app.side_identity(side) == app.side_identity(holder) for side in match.get("sides", [])): @@ -384,9 +437,12 @@ def sync_season_card_results(card: dict[str, Any]) -> None: result_id = f"{season_id}:{card.get('season_show_number', 0)}:{index + 1}" if result_id in processed: continue + if not app.validate_match_division_eligibility(season, match): + continue if match.get("title_defense") and not app.validate_title_defense(season, match): continue - app.record_season_match(season, card, match, index) + if not app.record_season_match(season, card, match, index): + continue processed.add(result_id) season["processed_results"] = sorted(processed) complete = all(match.get("winner_side") is not None for match in card["matches"]) @@ -399,4 +455,4 @@ def sync_season_card_results(card: dict[str, Any]) -> None: season["show_history"].append(card["path"]) app.save_season(season) -__all__ = ['choose_initial_champion', 'choose_roster_member', 'choose_season_control_mode', 'create_season', 'eligible_roster_for_division', 'load_season', 'new_season_state', 'print_power_rankings', 'record_season_match', 'save_season', 'season_control_label', 'season_other_pool', 'season_path', 'season_ranking_entries', 'season_rivalry_id', 'season_show_brand', 'side_display', 'side_identity', 'sync_season_card_results', 'toggle_season_control_mode', 'validate_title_defense'] +__all__ = ['choose_initial_champion', 'choose_roster_member', 'choose_season_control_mode', 'create_season', 'eligible_roster_for_division', 'load_season', 'new_season_state', 'print_power_rankings', 'record_season_match', 'save_season', 'season_control_label', 'season_other_pool', 'season_path', 'season_ranking_entries', 'season_rivalry_id', 'season_show_brand', 'side_display', 'side_identity', 'sync_season_card_results', 'toggle_season_control_mode', 'validate_match_division_eligibility', 'validate_title_defense'] diff --git a/test_lvpwb.py b/test_lvpwb.py index 370cae6..57228fa 100644 --- a/test_lvpwb.py +++ b/test_lvpwb.py @@ -916,6 +916,126 @@ class SeasonControlTests(unittest.TestCase): self.assertEqual(updated["next_show_number"], 2) +class LightHeavyweightTests(unittest.TestCase): + def test_builtin_season_selects_and_snapshots_eligible_wrestlers(self): + def select_eligible(profile): + profile["light_heavyweight_roster"] = ["X-Pac", "Jeff Hardy"] + + def initial_champion(division, _game_id, _used, _profile): + return ["X-Pac"] if division == "Light-Heavyweight" else None + + with tempfile.TemporaryDirectory() as folder, \ + patch.object(app, "SEASON_DIR", Path(folder)), \ + patch.object(app, "choose_game", return_value="sd1"), \ + patch.object(app, "ask", return_value="Lightweight Season"), \ + patch.object(app, "edit_light_heavyweight_roster", side_effect=select_eligible), \ + patch.object(app, "choose_initial_champion", side_effect=initial_champion), \ + contextlib.redirect_stdout(io.StringIO()): + season = app.create_season() + loaded = app.load_season(season["season_id"]) + + self.assertEqual(season["game_config"]["light_heavyweight_roster"], + ["X-Pac", "Jeff Hardy"]) + self.assertEqual( + app.eligible_roster_for_division( + "sd1", "Light-Heavyweight", profile=loaded["game_config"] + ), + ["X-Pac", "Jeff Hardy"], + ) + self.assertEqual(loaded["champions"]["Light-Heavyweight"]["holder"], ["X-Pac"]) + defense = { + "ranking_division": "Light-Heavyweight", "title_defense": True, + "sides": [["X-Pac"], ["Jeff Hardy"]], "winner_side": 1, + } + self.assertTrue(app.validate_title_defense(loaded, defense)) + app.record_season_match(loaded, {"season_show": "Raw"}, defense, 0) + self.assertEqual(loaded["champions"]["Light-Heavyweight"]["holder"], ["Jeff Hardy"]) + + def test_initial_champion_random_choice_uses_only_eligible_wrestlers(self): + profile = app.game_profile("sd1") + profile["light_heavyweight_roster"] = ["X-Pac"] + choices_seen = [] + + def first_choice(options): + choices_seen.append(list(options)) + return options[0] + + with patch.object(app, "ask_choice", return_value=1), \ + patch.object(app.random, "choice", side_effect=first_choice), \ + contextlib.redirect_stdout(io.StringIO()): + champion = app.choose_initial_champion( + "Light-Heavyweight", "sd1", set(), profile + ) + self.assertEqual(champion, ["X-Pac"]) + self.assertEqual(choices_seen, [["X-Pac"]]) + + def test_ineligible_wrestlers_cannot_record_or_sync_division_results(self): + with tempfile.TemporaryDirectory() as folder, \ + patch.object(app, "SEASON_DIR", Path(folder)): + season = app.new_season_state( + "Lightweight Season", "sd1", + champions={"Light-Heavyweight": ["X-Pac"]}, + season_id="lightweight-results", + ) + season["game_config"]["light_heavyweight_roster"] = ["X-Pac"] + card_path = Path(folder) / "card.md" + season["current_card"] = str(card_path) + app.save_season(season) + match = { + "type": "Singles", "sides": [["X-Pac"], ["The Rock"]], + "winner_side": 1, "ranking_division": "Light-Heavyweight", + "title_defense": True, + } + card = { + "season_id": season["season_id"], "season_show_number": 1, + "season_show": "Raw", "path": str(card_path), + "matches": [match], + } + + with contextlib.redirect_stdout(io.StringIO()): + self.assertFalse(app.validate_title_defense(season, match)) + self.assertFalse(app.record_match_result(card, 0, auto_simulate=True)) + app.sync_season_card_results(card) + + updated = app.load_season(season["season_id"]) + self.assertEqual(updated["champions"]["Light-Heavyweight"]["holder"], ["X-Pac"]) + self.assertEqual(updated["rankings"]["Light-Heavyweight"], {}) + self.assertEqual(updated["processed_results"], []) + + def test_legacy_season_without_eligibility_snapshot_remains_unrestricted(self): + season = app.new_season_state("Legacy Season", "sd1", season_id="legacy-lightweight") + season["game_config"].pop("light_heavyweight_roster", None) + self.assertEqual( + app.eligible_roster_for_division( + "sd1", "Light-Heavyweight", profile=season["game_config"] + ), + season["game_config"]["roster"], + ) + + def test_legacy_builtin_light_heavyweight_kind_migrates_without_restricting_roster(self): + season = app.new_season_state( + "Legacy Lightweight", "sd1", season_id="legacy-lightweight-kind" + ) + for definitions in (season["title_definitions"], + season["game_config"]["championships"]): + next(item for item in definitions if item["name"] == "Light-Heavyweight")["kind"] = "singles" + season["game_config"].pop("light_heavyweight_roster", None) + with tempfile.TemporaryDirectory() as folder, \ + patch.object(app, "SEASON_DIR", Path(folder)): + app.save_season(season) + loaded = app.load_season(season["season_id"]) + self.assertEqual( + app.season_championship_kind(loaded, "Light-Heavyweight"), + "light_heavyweight", + ) + self.assertEqual( + app.eligible_roster_for_division( + "sd1", "Light-Heavyweight", profile=loaded["game_config"] + ), + loaded["game_config"]["roster"], + ) + + class BYOGTests(unittest.TestCase): def setUp(self): self._configs = app.CUSTOM_GAME_CONFIGS @@ -954,6 +1074,7 @@ class BYOGTests(unittest.TestCase): {"name": "Fantasy Women", "kind": "women"}, ], "women_roster": ["Cara Storm"], + "light_heavyweight_roster": [], } data.update(overrides) return data @@ -1007,6 +1128,7 @@ class BYOGTests(unittest.TestCase): "invalid side sizes"), ({"match_types": []}, "at least one match type"), ({"championships": [{"name": "Belt", "kind": "hardcore"}]}, "kind"), + ({"light_heavyweight_roster": ["Not Listed"]}, "subset of the roster"), ({"platform": "dreamcast"}, "platform must be ps1"), ({"screenshot_directory": 3}, "screenshot_directory must be a path string"), ] @@ -1053,6 +1175,38 @@ class BYOGTests(unittest.TestCase): app.ROOT / "custom-screens") self.assertTrue(app.game_has_screenshots(overridden["game_id"])) + def test_custom_light_heavyweight_eligibility_is_validated_and_applied(self): + config = self.config( + championships=[ + {"name": "Fantasy Lightweight", "kind": "light_heavyweight"}, + ], + light_heavyweight_roster=["Ava Crusher", "Cara Storm"], + ) + self.register(config) + profile = app.game_profile(config["game_id"]) + self.assertEqual( + app.eligible_roster_for_division( + config["game_id"], "Fantasy Lightweight", profile=profile + ), + ["Ava Crusher", "Cara Storm"], + ) + self.assertEqual( + app.championship_kind(config["game_id"], "Fantasy Lightweight", profile), + "light_heavyweight", + ) + with self.assertRaisesRegex(ValueError, "must contain eligible wrestlers"): + app.validate_custom_game(self.config(championships=[ + {"name": "Fantasy Lightweight", "kind": "light_heavyweight"}, + ])) + + def test_light_heavyweight_eligibility_editor_selects_roster_members(self): + config = {"roster": ["Ava Crusher", "Ben Brawler"], + "light_heavyweight_roster": []} + with patch.object(app, "ask_choice", side_effect=[0, 0, 2]), \ + contextlib.redirect_stdout(io.StringIO()): + app.edit_light_heavyweight_roster(config) + self.assertEqual(config["light_heavyweight_roster"], ["Ava Crusher"]) + def test_custom_game_screenshot_override_can_be_set_in_editor(self): config = app.validate_custom_game(self.config()) with patch.object(app, "ask_choice", side_effect=[0, 0, 6]), \