mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
LTTP: Move LTTP spoiler writing out of core (#1467)
This commit is contained in:
201
BaseClasses.py
201
BaseClasses.py
@@ -1260,13 +1260,9 @@ class Spoiler():
|
||||
self.multiworld = world
|
||||
self.hashes = {}
|
||||
self.entrances = OrderedDict()
|
||||
self.medallions = {}
|
||||
self.playthrough = {}
|
||||
self.unreachables = set()
|
||||
self.locations = {}
|
||||
self.paths = {}
|
||||
self.shops = []
|
||||
self.bosses = OrderedDict()
|
||||
|
||||
def set_entrance(self, entrance: str, exit_: str, direction: str, player: int):
|
||||
if self.multiworld.players == 1:
|
||||
@@ -1276,126 +1272,6 @@ class Spoiler():
|
||||
self.entrances[(entrance, direction, player)] = OrderedDict(
|
||||
[('player', player), ('entrance', entrance), ('exit', exit_), ('direction', direction)])
|
||||
|
||||
def parse_data(self):
|
||||
from worlds.alttp.SubClasses import LTTPRegionType
|
||||
self.medallions = OrderedDict()
|
||||
for player in self.multiworld.get_game_players("A Link to the Past"):
|
||||
self.medallions[f'Misery Mire ({self.multiworld.get_player_name(player)})'] = \
|
||||
self.multiworld.required_medallions[player][0]
|
||||
self.medallions[f'Turtle Rock ({self.multiworld.get_player_name(player)})'] = \
|
||||
self.multiworld.required_medallions[player][1]
|
||||
|
||||
self.locations = OrderedDict()
|
||||
listed_locations = set()
|
||||
lw_locations = []
|
||||
dw_locations = []
|
||||
cave_locations = []
|
||||
for loc in self.multiworld.get_locations():
|
||||
if loc.game == "A Link to the Past":
|
||||
if loc not in listed_locations and loc.parent_region and \
|
||||
loc.parent_region.type == LTTPRegionType.LightWorld and loc.show_in_spoiler:
|
||||
lw_locations.append(loc)
|
||||
elif loc not in listed_locations and loc.parent_region and \
|
||||
loc.parent_region.type == LTTPRegionType.DarkWorld and loc.show_in_spoiler:
|
||||
dw_locations.append(loc)
|
||||
elif loc not in listed_locations and loc.parent_region and \
|
||||
loc.parent_region.type == LTTPRegionType.Cave and loc.show_in_spoiler:
|
||||
cave_locations.append(loc)
|
||||
|
||||
self.locations['Light World'] = OrderedDict(
|
||||
[(str(location), str(location.item) if location.item is not None else 'Nothing') for location in
|
||||
lw_locations])
|
||||
listed_locations.update(lw_locations)
|
||||
|
||||
self.locations['Dark World'] = OrderedDict(
|
||||
[(str(location), str(location.item) if location.item is not None else 'Nothing') for location in
|
||||
dw_locations])
|
||||
listed_locations.update(dw_locations)
|
||||
|
||||
self.locations['Caves'] = OrderedDict(
|
||||
[(str(location), str(location.item) if location.item is not None else 'Nothing') for location in
|
||||
cave_locations])
|
||||
listed_locations.update(cave_locations)
|
||||
|
||||
for dungeon in self.multiworld.dungeons.values():
|
||||
dungeon_locations = [loc for loc in self.multiworld.get_locations() if
|
||||
loc not in listed_locations and loc.parent_region and loc.parent_region.dungeon == dungeon and loc.show_in_spoiler]
|
||||
self.locations[str(dungeon)] = OrderedDict(
|
||||
[(str(location), str(location.item) if location.item is not None else 'Nothing') for location in
|
||||
dungeon_locations])
|
||||
listed_locations.update(dungeon_locations)
|
||||
|
||||
other_locations = [loc for loc in self.multiworld.get_locations() if
|
||||
loc not in listed_locations and loc.show_in_spoiler]
|
||||
if other_locations:
|
||||
self.locations['Other Locations'] = OrderedDict(
|
||||
[(str(location), str(location.item) if location.item is not None else 'Nothing') for location in
|
||||
other_locations])
|
||||
listed_locations.update(other_locations)
|
||||
|
||||
self.shops = []
|
||||
from worlds.alttp.Shops import ShopType, price_type_display_name, price_rate_display
|
||||
for shop in self.multiworld.shops:
|
||||
if not shop.custom:
|
||||
continue
|
||||
shopdata = {
|
||||
'location': str(shop.region),
|
||||
'type': 'Take Any' if shop.type == ShopType.TakeAny else 'Shop'
|
||||
}
|
||||
for index, item in enumerate(shop.inventory):
|
||||
if item is None:
|
||||
continue
|
||||
my_price = item['price'] // price_rate_display.get(item['price_type'], 1)
|
||||
shopdata['item_{}'.format(
|
||||
index)] = f"{item['item']} — {my_price} {price_type_display_name[item['price_type']]}"
|
||||
|
||||
if item['player'] > 0:
|
||||
shopdata['item_{}'.format(index)] = shopdata['item_{}'.format(index)].replace('—',
|
||||
'(Player {}) — '.format(
|
||||
item['player']))
|
||||
|
||||
if item['max'] == 0:
|
||||
continue
|
||||
shopdata['item_{}'.format(index)] += " x {}".format(item['max'])
|
||||
|
||||
if item['replacement'] is None:
|
||||
continue
|
||||
shopdata['item_{}'.format(
|
||||
index)] += f", {item['replacement']} - {item['replacement_price']} {price_type_display_name[item['replacement_price_type']]}"
|
||||
self.shops.append(shopdata)
|
||||
|
||||
for player in self.multiworld.get_game_players("A Link to the Past"):
|
||||
self.bosses[str(player)] = OrderedDict()
|
||||
self.bosses[str(player)]["Eastern Palace"] = self.multiworld.get_dungeon("Eastern Palace", player).boss.name
|
||||
self.bosses[str(player)]["Desert Palace"] = self.multiworld.get_dungeon("Desert Palace", player).boss.name
|
||||
self.bosses[str(player)]["Tower Of Hera"] = self.multiworld.get_dungeon("Tower of Hera", player).boss.name
|
||||
self.bosses[str(player)]["Hyrule Castle"] = "Agahnim"
|
||||
self.bosses[str(player)]["Palace Of Darkness"] = self.multiworld.get_dungeon("Palace of Darkness",
|
||||
player).boss.name
|
||||
self.bosses[str(player)]["Swamp Palace"] = self.multiworld.get_dungeon("Swamp Palace", player).boss.name
|
||||
self.bosses[str(player)]["Skull Woods"] = self.multiworld.get_dungeon("Skull Woods", player).boss.name
|
||||
self.bosses[str(player)]["Thieves Town"] = self.multiworld.get_dungeon("Thieves Town", player).boss.name
|
||||
self.bosses[str(player)]["Ice Palace"] = self.multiworld.get_dungeon("Ice Palace", player).boss.name
|
||||
self.bosses[str(player)]["Misery Mire"] = self.multiworld.get_dungeon("Misery Mire", player).boss.name
|
||||
self.bosses[str(player)]["Turtle Rock"] = self.multiworld.get_dungeon("Turtle Rock", player).boss.name
|
||||
if self.multiworld.mode[player] != 'inverted':
|
||||
self.bosses[str(player)]["Ganons Tower Basement"] = \
|
||||
self.multiworld.get_dungeon('Ganons Tower', player).bosses['bottom'].name
|
||||
self.bosses[str(player)]["Ganons Tower Middle"] = self.multiworld.get_dungeon('Ganons Tower', player).bosses[
|
||||
'middle'].name
|
||||
self.bosses[str(player)]["Ganons Tower Top"] = self.multiworld.get_dungeon('Ganons Tower', player).bosses[
|
||||
'top'].name
|
||||
else:
|
||||
self.bosses[str(player)]["Ganons Tower Basement"] = \
|
||||
self.multiworld.get_dungeon('Inverted Ganons Tower', player).bosses['bottom'].name
|
||||
self.bosses[str(player)]["Ganons Tower Middle"] = \
|
||||
self.multiworld.get_dungeon('Inverted Ganons Tower', player).bosses['middle'].name
|
||||
self.bosses[str(player)]["Ganons Tower Top"] = \
|
||||
self.multiworld.get_dungeon('Inverted Ganons Tower', player).bosses['top'].name
|
||||
|
||||
self.bosses[str(player)]["Ganons Tower"] = "Agahnim 2"
|
||||
self.bosses[str(player)]["Ganon"] = "Ganon"
|
||||
|
||||
def create_playthrough(self, create_paths: bool = True):
|
||||
"""Destructive to the world while it is run, damage gets repaired afterwards."""
|
||||
from itertools import chain
|
||||
@@ -1547,30 +1423,7 @@ class Spoiler():
|
||||
self.paths[str(multiworld.get_region('Inverted Big Bomb Shop', player))] = \
|
||||
get_path(state, multiworld.get_region('Inverted Big Bomb Shop', player))
|
||||
|
||||
def to_json(self):
|
||||
self.parse_data()
|
||||
out = OrderedDict()
|
||||
out['Entrances'] = list(self.entrances.values())
|
||||
out.update(self.locations)
|
||||
out['Special'] = self.medallions
|
||||
if self.hashes:
|
||||
out['Hashes'] = self.hashes
|
||||
if self.shops:
|
||||
out['Shops'] = self.shops
|
||||
out['playthrough'] = self.playthrough
|
||||
out['paths'] = self.paths
|
||||
out['Bosses'] = self.bosses
|
||||
|
||||
return json.dumps(out)
|
||||
|
||||
def to_file(self, filename: str):
|
||||
self.parse_data()
|
||||
|
||||
def bool_to_text(variable: Union[bool, str]) -> str:
|
||||
if type(variable) == str:
|
||||
return variable
|
||||
return 'Yes' if variable else 'No'
|
||||
|
||||
def write_option(option_key: str, option_obj: type(Options.Option)):
|
||||
res = getattr(self.multiworld, option_key)[player]
|
||||
display_name = getattr(option_obj, "display_name", option_key)
|
||||
@@ -1600,38 +1453,6 @@ class Spoiler():
|
||||
write_option(f_option, option)
|
||||
AutoWorld.call_single(self.multiworld, "write_spoiler_header", player, outfile)
|
||||
|
||||
if player in self.multiworld.get_game_players("A Link to the Past"):
|
||||
outfile.write('%s%s\n' % ('Hash: ', self.hashes[player]))
|
||||
|
||||
outfile.write('Logic: %s\n' % self.multiworld.logic[player])
|
||||
outfile.write('Dark Room Logic: %s\n' % self.multiworld.dark_room_logic[player])
|
||||
outfile.write('Mode: %s\n' % self.multiworld.mode[player])
|
||||
outfile.write('Goal: %s\n' % self.multiworld.goal[player])
|
||||
if "triforce" in self.multiworld.goal[player]: # triforce hunt
|
||||
outfile.write("Pieces available for Triforce: %s\n" %
|
||||
self.multiworld.triforce_pieces_available[player])
|
||||
outfile.write("Pieces required for Triforce: %s\n" %
|
||||
self.multiworld.triforce_pieces_required[player])
|
||||
outfile.write('Difficulty: %s\n' % self.multiworld.difficulty[player])
|
||||
outfile.write('Item Functionality: %s\n' % self.multiworld.item_functionality[player])
|
||||
outfile.write('Entrance Shuffle: %s\n' % self.multiworld.shuffle[player])
|
||||
if self.multiworld.shuffle[player] != "vanilla":
|
||||
outfile.write('Entrance Shuffle Seed %s\n' % self.multiworld.worlds[player].er_seed)
|
||||
outfile.write('Shop inventory shuffle: %s\n' %
|
||||
bool_to_text("i" in self.multiworld.shop_shuffle[player]))
|
||||
outfile.write('Shop price shuffle: %s\n' %
|
||||
bool_to_text("p" in self.multiworld.shop_shuffle[player]))
|
||||
outfile.write('Shop upgrade shuffle: %s\n' %
|
||||
bool_to_text("u" in self.multiworld.shop_shuffle[player]))
|
||||
outfile.write('New Shop inventory: %s\n' %
|
||||
bool_to_text("g" in self.multiworld.shop_shuffle[player] or
|
||||
"f" in self.multiworld.shop_shuffle[player]))
|
||||
outfile.write('Custom Potion Shop: %s\n' %
|
||||
bool_to_text("w" in self.multiworld.shop_shuffle[player]))
|
||||
outfile.write('Enemy health: %s\n' % self.multiworld.enemy_health[player])
|
||||
outfile.write('Enemy damage: %s\n' % self.multiworld.enemy_damage[player])
|
||||
outfile.write('Prize shuffle %s\n' %
|
||||
self.multiworld.shuffle_prizes[player])
|
||||
if self.entrances:
|
||||
outfile.write('\n\nEntrances:\n\n')
|
||||
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.multiworld.get_player_name(entry["player"])}: '
|
||||
@@ -1640,30 +1461,14 @@ class Spoiler():
|
||||
'<=' if entry['direction'] == 'exit' else '=>',
|
||||
entry['exit']) for entry in self.entrances.values()]))
|
||||
|
||||
if self.medallions:
|
||||
outfile.write('\n\nMedallions:\n')
|
||||
for dungeon, medallion in self.medallions.items():
|
||||
outfile.write(f'\n{dungeon}: {medallion}')
|
||||
|
||||
AutoWorld.call_all(self.multiworld, "write_spoiler", outfile)
|
||||
|
||||
locations = [(str(location), str(location.item) if location.item is not None else "Nothing")
|
||||
for location in self.multiworld.get_locations()]
|
||||
outfile.write('\n\nLocations:\n\n')
|
||||
outfile.write('\n'.join(
|
||||
['%s: %s' % (location, item) for grouping in self.locations.values() for (location, item) in
|
||||
grouping.items()]))
|
||||
['%s: %s' % (location, item) for location, item in locations]))
|
||||
|
||||
if self.shops:
|
||||
outfile.write('\n\nShops:\n\n')
|
||||
outfile.write('\n'.join("{} [{}]\n {}".format(shop['location'], shop['type'], "\n ".join(
|
||||
item for item in [shop.get('item_0', None), shop.get('item_1', None), shop.get('item_2', None)] if
|
||||
item)) for shop in self.shops))
|
||||
|
||||
for player in self.multiworld.get_game_players("A Link to the Past"):
|
||||
if self.multiworld.boss_shuffle[player] != 'none':
|
||||
bossmap = self.bosses[str(player)] if self.multiworld.players > 1 else self.bosses
|
||||
outfile.write(
|
||||
f'\n\nBosses{(f" ({self.multiworld.get_player_name(player)})" if self.multiworld.players > 1 else "")}:\n')
|
||||
outfile.write(' ' + '\n '.join([f'{x}: {y}' for x, y in bossmap.items()]))
|
||||
outfile.write('\n\nPlaythrough:\n\n')
|
||||
outfile.write('\n'.join(['%s: {\n%s\n}' % (sphere_nr, '\n'.join(
|
||||
[' %s: %s' % (location, item) for (location, item) in sphere.items()] if sphere_nr != '0' else [
|
||||
|
Reference in New Issue
Block a user