diff --git a/BaseClasses.py b/BaseClasses.py index e818f629..a61efe57 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1177,6 +1177,7 @@ class Spoiler(): return json.dumps(out) def to_file(self, filename): + from worlds.AutoWorld import call_all, call_single, call_stage self.parse_data() def bool_to_text(variable: Union[bool, str]) -> str: @@ -1198,6 +1199,7 @@ class Spoiler(): Utils.__version__, self.world.seed)) outfile.write('Filling Algorithm: %s\n' % self.world.algorithm) outfile.write('Players: %d\n' % self.world.players) + call_stage(self.world, "write_spoiler_header", outfile) for player in range(1, self.world.players + 1): if self.world.players > 1: @@ -1211,6 +1213,7 @@ class Spoiler(): if options: for f_option, option in options.items(): write_option(f_option, option) + call_single(self.world, "write_spoiler_header", player, outfile) if player in self.world.get_game_players("A Link to the Past"): outfile.write('%s%s\n' % ('Hash: ', self.hashes[player])) @@ -1260,13 +1263,8 @@ class Spoiler(): outfile.write('\n\nMedallions:\n') for dungeon, medallion in self.medallions.items(): outfile.write(f'\n{dungeon}: {medallion}') - factorio_players = self.world.get_game_players("Factorio") - if factorio_players: - outfile.write('\n\nRecipes:\n') - for player in factorio_players: - name = self.world.get_player_name(player) - for recipe in self.world.worlds[player].custom_recipes.values(): - outfile.write(f"\n{recipe.name} ({name}): {recipe.ingredients} -> {recipe.products}") + + call_all(self.world, "write_spoiler", outfile) outfile.write('\n\nLocations:\n\n') outfile.write('\n'.join( @@ -1307,6 +1305,7 @@ class Spoiler(): path_listings.append("{}\n {}".format(location, "\n => ".join(path_lines))) outfile.write('\n'.join(path_listings)) + call_all(self.world, "write_spoiler_end", outfile) seeddigits = 20 diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index 6894d665..9ec9bb40 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import Dict, Set, Tuple, List, Optional +from typing import Dict, Set, Tuple, List, Optional, TextIO from BaseClasses import MultiWorld, Item, CollectionState, Location from Options import Option @@ -172,6 +172,20 @@ class World(metaclass=AutoWorldRegister): def get_required_client_version(self) -> Tuple[int, int, int]: return 0, 1, 6 + # Spoiler writing is optional, these may not get called. + def write_spoiler_header(self, spoiler_handle: TextIO): + """Write to the spoiler header. If individual it's right at the end of that player's options, + if as stage it's right under the common header before per-player options.""" + pass + + def write_spoiler(self, spoiler_handle: TextIO): + """Write to the spoiler "middle", this is after the per-player options and before locations, + meant for useful or interesting info.""" + pass + + def write_spoiler_end(self, spoiler_handle: TextIO): + """Write to the end of the spoiler""" + pass # end of ordered Main.py calls def collect_item(self, state: CollectionState, item: Item, remove: bool = False) -> Optional[str]: diff --git a/worlds/factorio/__init__.py b/worlds/factorio/__init__.py index fa446759..1834e4ff 100644 --- a/worlds/factorio/__init__.py +++ b/worlds/factorio/__init__.py @@ -167,6 +167,15 @@ class Factorio(World): options = factorio_options + @classmethod + def stage_write_spoiler(cls, world, spoiler_handle): + factorio_players = world.get_game_players(cls.game) + spoiler_handle.write('\n\nFactorio Recipes:\n') + for player in factorio_players: + name = world.get_player_name(player) + for recipe in world.worlds[player].custom_recipes.values(): + spoiler_handle.write(f"\n{recipe.name} ({name}): {recipe.ingredients} -> {recipe.products}") + def make_balanced_recipe(self, original: Recipe, pool: list, factor: float = 1) -> Recipe: """Generate a recipe from pool with time and cost similar to original * factor""" new_ingredients = {}