Merge branch 'Archipelago_Main' into new_shops
This commit is contained in:
commit
4ed185a155
116
BaseClasses.py
116
BaseClasses.py
|
@ -10,6 +10,8 @@ from typing import List, Dict, Optional, Set, Iterable, Union, Any, Tuple
|
||||||
import secrets
|
import secrets
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
import Utils
|
||||||
|
|
||||||
|
|
||||||
class MultiWorld():
|
class MultiWorld():
|
||||||
debug_types = False
|
debug_types = False
|
||||||
|
@ -77,14 +79,11 @@ class MultiWorld():
|
||||||
set_player_attr('shuffle', "vanilla")
|
set_player_attr('shuffle', "vanilla")
|
||||||
set_player_attr('logic', "noglitches")
|
set_player_attr('logic', "noglitches")
|
||||||
set_player_attr('mode', 'open')
|
set_player_attr('mode', 'open')
|
||||||
set_player_attr('swordless', False)
|
|
||||||
set_player_attr('difficulty', 'normal')
|
set_player_attr('difficulty', 'normal')
|
||||||
set_player_attr('item_functionality', 'normal')
|
set_player_attr('item_functionality', 'normal')
|
||||||
set_player_attr('timer', False)
|
set_player_attr('timer', False)
|
||||||
set_player_attr('goal', 'ganon')
|
set_player_attr('goal', 'ganon')
|
||||||
set_player_attr('accessibility', 'items')
|
set_player_attr('accessibility', 'items')
|
||||||
set_player_attr('retro', False)
|
|
||||||
set_player_attr('hints', True)
|
|
||||||
set_player_attr('required_medallions', ['Ether', 'Quake'])
|
set_player_attr('required_medallions', ['Ether', 'Quake'])
|
||||||
set_player_attr('swamp_patch_required', False)
|
set_player_attr('swamp_patch_required', False)
|
||||||
set_player_attr('powder_patch_required', False)
|
set_player_attr('powder_patch_required', False)
|
||||||
|
@ -97,12 +96,8 @@ class MultiWorld():
|
||||||
set_player_attr('fix_fake_world', True)
|
set_player_attr('fix_fake_world', True)
|
||||||
set_player_attr('difficulty_requirements', None)
|
set_player_attr('difficulty_requirements', None)
|
||||||
set_player_attr('boss_shuffle', 'none')
|
set_player_attr('boss_shuffle', 'none')
|
||||||
set_player_attr('enemy_shuffle', False)
|
|
||||||
set_player_attr('enemy_health', 'default')
|
set_player_attr('enemy_health', 'default')
|
||||||
set_player_attr('enemy_damage', 'default')
|
set_player_attr('enemy_damage', 'default')
|
||||||
set_player_attr('killable_thieves', False)
|
|
||||||
set_player_attr('tile_shuffle', False)
|
|
||||||
set_player_attr('bush_shuffle', False)
|
|
||||||
set_player_attr('beemizer', 0)
|
set_player_attr('beemizer', 0)
|
||||||
set_player_attr('escape_assist', [])
|
set_player_attr('escape_assist', [])
|
||||||
set_player_attr('open_pyramid', False)
|
set_player_attr('open_pyramid', False)
|
||||||
|
@ -123,7 +118,6 @@ class MultiWorld():
|
||||||
set_player_attr('shuffle_prizes', "g")
|
set_player_attr('shuffle_prizes', "g")
|
||||||
set_player_attr('sprite_pool', [])
|
set_player_attr('sprite_pool', [])
|
||||||
set_player_attr('dark_room_logic', "lamp")
|
set_player_attr('dark_room_logic', "lamp")
|
||||||
set_player_attr('restrict_dungeon_item_on_boss', False)
|
|
||||||
set_player_attr('plando_items', [])
|
set_player_attr('plando_items', [])
|
||||||
set_player_attr('plando_texts', {})
|
set_player_attr('plando_texts', {})
|
||||||
set_player_attr('plando_connections', [])
|
set_player_attr('plando_connections', [])
|
||||||
|
@ -1012,7 +1006,6 @@ class Spoiler():
|
||||||
self.startinventory = []
|
self.startinventory = []
|
||||||
self.locations = {}
|
self.locations = {}
|
||||||
self.paths = {}
|
self.paths = {}
|
||||||
self.metadata = {}
|
|
||||||
self.shops = []
|
self.shops = []
|
||||||
self.bosses = OrderedDict()
|
self.bosses = OrderedDict()
|
||||||
|
|
||||||
|
@ -1107,41 +1100,6 @@ class Spoiler():
|
||||||
self.bosses[str(player)]["Ganons Tower"] = "Agahnim 2"
|
self.bosses[str(player)]["Ganons Tower"] = "Agahnim 2"
|
||||||
self.bosses[str(player)]["Ganon"] = "Ganon"
|
self.bosses[str(player)]["Ganon"] = "Ganon"
|
||||||
|
|
||||||
from Utils import __version__ as APVersion
|
|
||||||
self.metadata = {'version': APVersion,
|
|
||||||
'logic': self.world.logic,
|
|
||||||
'dark_room_logic': self.world.dark_room_logic,
|
|
||||||
'mode': self.world.mode,
|
|
||||||
'retro': self.world.retro,
|
|
||||||
'swordless': self.world.swordless,
|
|
||||||
'goal': self.world.goal,
|
|
||||||
'shuffle': self.world.shuffle,
|
|
||||||
'item_pool': self.world.difficulty,
|
|
||||||
'item_functionality': self.world.item_functionality,
|
|
||||||
'open_pyramid': self.world.open_pyramid,
|
|
||||||
'accessibility': self.world.accessibility,
|
|
||||||
'hints': self.world.hints,
|
|
||||||
'boss_shuffle': self.world.boss_shuffle,
|
|
||||||
'enemy_shuffle': self.world.enemy_shuffle,
|
|
||||||
'enemy_health': self.world.enemy_health,
|
|
||||||
'enemy_damage': self.world.enemy_damage,
|
|
||||||
'killable_thieves': self.world.killable_thieves,
|
|
||||||
'tile_shuffle': self.world.tile_shuffle,
|
|
||||||
'bush_shuffle': self.world.bush_shuffle,
|
|
||||||
'beemizer': self.world.beemizer,
|
|
||||||
'shufflepots': self.world.shufflepots,
|
|
||||||
'players': self.world.players,
|
|
||||||
'progression_balancing': self.world.progression_balancing,
|
|
||||||
'triforce_pieces_available': self.world.triforce_pieces_available,
|
|
||||||
'triforce_pieces_required': self.world.triforce_pieces_required,
|
|
||||||
'shop_shuffle': self.world.shop_shuffle,
|
|
||||||
'shuffle_prizes': self.world.shuffle_prizes,
|
|
||||||
'sprite_pool': self.world.sprite_pool,
|
|
||||||
'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss,
|
|
||||||
'game': self.world.game,
|
|
||||||
'er_seeds': self.world.er_seeds
|
|
||||||
}
|
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
self.parse_data()
|
self.parse_data()
|
||||||
out = OrderedDict()
|
out = OrderedDict()
|
||||||
|
@ -1156,7 +1114,6 @@ class Spoiler():
|
||||||
out['playthrough'] = self.playthrough
|
out['playthrough'] = self.playthrough
|
||||||
out['paths'] = self.paths
|
out['paths'] = self.paths
|
||||||
out['Bosses'] = self.bosses
|
out['Bosses'] = self.bosses
|
||||||
out['meta'] = self.metadata
|
|
||||||
|
|
||||||
return json.dumps(out)
|
return json.dumps(out)
|
||||||
|
|
||||||
|
@ -1171,7 +1128,7 @@ class Spoiler():
|
||||||
with open(filename, 'w', encoding="utf-8-sig") as outfile:
|
with open(filename, 'w', encoding="utf-8-sig") as outfile:
|
||||||
outfile.write(
|
outfile.write(
|
||||||
'Archipelago Version %s - Seed: %s\n\n' % (
|
'Archipelago Version %s - Seed: %s\n\n' % (
|
||||||
self.metadata['version'], self.world.seed))
|
Utils.__version__, self.world.seed))
|
||||||
outfile.write('Filling Algorithm: %s\n' % self.world.algorithm)
|
outfile.write('Filling Algorithm: %s\n' % self.world.algorithm)
|
||||||
outfile.write('Players: %d\n' % self.world.players)
|
outfile.write('Players: %d\n' % self.world.players)
|
||||||
|
|
||||||
|
@ -1181,8 +1138,8 @@ class Spoiler():
|
||||||
outfile.write('Game: %s\n' % self.world.game[player])
|
outfile.write('Game: %s\n' % self.world.game[player])
|
||||||
if self.world.players > 1:
|
if self.world.players > 1:
|
||||||
outfile.write('Progression Balanced: %s\n' % (
|
outfile.write('Progression Balanced: %s\n' % (
|
||||||
'Yes' if self.metadata['progression_balancing'][player] else 'No'))
|
'Yes' if self.world.progression_balancing[player] else 'No'))
|
||||||
outfile.write('Accessibility: %s\n' % self.metadata['accessibility'][player])
|
outfile.write('Accessibility: %s\n' % self.world.accessibility[player])
|
||||||
options = self.world.worlds[player].options
|
options = self.world.worlds[player].options
|
||||||
if options:
|
if options:
|
||||||
for f_option, option in options.items():
|
for f_option, option in options.items():
|
||||||
|
@ -1193,54 +1150,39 @@ class Spoiler():
|
||||||
if player in self.world.get_game_players("A Link to the Past"):
|
if player in self.world.get_game_players("A Link to the Past"):
|
||||||
outfile.write('%s%s\n' % ('Hash: ', self.hashes[player]))
|
outfile.write('%s%s\n' % ('Hash: ', self.hashes[player]))
|
||||||
|
|
||||||
outfile.write('Logic: %s\n' % self.metadata['logic'][player])
|
outfile.write('Logic: %s\n' % self.world.logic[player])
|
||||||
outfile.write('Dark Room Logic: %s\n' % self.metadata['dark_room_logic'][player])
|
outfile.write('Dark Room Logic: %s\n' % self.world.dark_room_logic[player])
|
||||||
outfile.write('Restricted Boss Drops: %s\n' %
|
outfile.write('Mode: %s\n' % self.world.mode[player])
|
||||||
bool_to_text(self.metadata['restrict_dungeon_item_on_boss'][player]))
|
outfile.write('Goal: %s\n' % self.world.goal[player])
|
||||||
|
if "triforce" in self.world.goal[player]: # triforce hunt
|
||||||
outfile.write('Mode: %s\n' % self.metadata['mode'][player])
|
|
||||||
outfile.write('Retro: %s\n' %
|
|
||||||
('Yes' if self.metadata['retro'][player] else 'No'))
|
|
||||||
outfile.write('Swordless: %s\n' % ('Yes' if self.metadata['swordless'][player] else 'No'))
|
|
||||||
outfile.write('Goal: %s\n' % self.metadata['goal'][player])
|
|
||||||
if "triforce" in self.metadata["goal"][player]: # triforce hunt
|
|
||||||
outfile.write("Pieces available for Triforce: %s\n" %
|
outfile.write("Pieces available for Triforce: %s\n" %
|
||||||
self.metadata['triforce_pieces_available'][player])
|
self.world.triforce_pieces_available[player])
|
||||||
outfile.write("Pieces required for Triforce: %s\n" %
|
outfile.write("Pieces required for Triforce: %s\n" %
|
||||||
self.metadata["triforce_pieces_required"][player])
|
self.world.triforce_pieces_required[player])
|
||||||
outfile.write('Difficulty: %s\n' % self.metadata['item_pool'][player])
|
outfile.write('Difficulty: %s\n' % self.world.difficulty[player])
|
||||||
outfile.write('Item Functionality: %s\n' % self.metadata['item_functionality'][player])
|
outfile.write('Item Functionality: %s\n' % self.world.item_functionality[player])
|
||||||
outfile.write('Entrance Shuffle: %s\n' % self.metadata['shuffle'][player])
|
outfile.write('Entrance Shuffle: %s\n' % self.world.shuffle[player])
|
||||||
if self.metadata['shuffle'][player] != "vanilla":
|
if self.world.shuffle[player] != "vanilla":
|
||||||
outfile.write('Entrance Shuffle Seed %s\n' % self.metadata['er_seeds'][player])
|
outfile.write('Entrance Shuffle Seed %s\n' % self.world.er_seeds[player])
|
||||||
outfile.write('Pyramid hole pre-opened: %s\n' % (
|
outfile.write('Pyramid hole pre-opened: %s\n' % (
|
||||||
'Yes' if self.metadata['open_pyramid'][player] else 'No'))
|
'Yes' if self.world.open_pyramid[player] else 'No'))
|
||||||
outfile.write('Shop inventory shuffle: %s\n' %
|
outfile.write('Shop inventory shuffle: %s\n' %
|
||||||
bool_to_text("i" in self.metadata["shop_shuffle"][player]))
|
bool_to_text("i" in self.world.shop_shuffle[player]))
|
||||||
outfile.write('Shop price shuffle: %s\n' %
|
outfile.write('Shop price shuffle: %s\n' %
|
||||||
bool_to_text("p" in self.metadata["shop_shuffle"][player]))
|
bool_to_text("p" in self.world.shop_shuffle[player]))
|
||||||
outfile.write('Shop upgrade shuffle: %s\n' %
|
outfile.write('Shop upgrade shuffle: %s\n' %
|
||||||
bool_to_text("u" in self.metadata["shop_shuffle"][player]))
|
bool_to_text("u" in self.world.shop_shuffle[player]))
|
||||||
outfile.write('New Shop inventory: %s\n' %
|
outfile.write('New Shop inventory: %s\n' %
|
||||||
bool_to_text("g" in self.metadata["shop_shuffle"][player] or
|
bool_to_text("g" in self.world.shop_shuffle[player] or
|
||||||
"f" in self.metadata["shop_shuffle"][player]))
|
"f" in self.world.shop_shuffle[player]))
|
||||||
outfile.write('Custom Potion Shop: %s\n' %
|
outfile.write('Custom Potion Shop: %s\n' %
|
||||||
bool_to_text("w" in self.metadata["shop_shuffle"][player]))
|
bool_to_text("w" in self.world.shop_shuffle[player]))
|
||||||
outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player])
|
outfile.write('Boss shuffle: %s\n' % self.world.boss_shuffle[player])
|
||||||
outfile.write(
|
outfile.write('Enemy health: %s\n' % self.world.enemy_health[player])
|
||||||
'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player]))
|
outfile.write('Enemy damage: %s\n' % self.world.enemy_damage[player])
|
||||||
outfile.write('Enemy health: %s\n' % self.metadata['enemy_health'][player])
|
outfile.write('Beemizer: %s\n' % self.world.beemizer[player])
|
||||||
outfile.write('Enemy damage: %s\n' % self.metadata['enemy_damage'][player])
|
|
||||||
outfile.write(f'Killable thieves: {bool_to_text(self.metadata["killable_thieves"][player])}\n')
|
|
||||||
outfile.write(f'Shuffled tiles: {bool_to_text(self.metadata["tile_shuffle"][player])}\n')
|
|
||||||
outfile.write(f'Shuffled bushes: {bool_to_text(self.metadata["bush_shuffle"][player])}\n')
|
|
||||||
outfile.write(
|
|
||||||
'Hints: %s\n' % ('Yes' if self.metadata['hints'][player] else 'No'))
|
|
||||||
outfile.write('Beemizer: %s\n' % self.metadata['beemizer'][player])
|
|
||||||
outfile.write('Pot shuffle %s\n'
|
|
||||||
% ('Yes' if self.metadata['shufflepots'][player] else 'No'))
|
|
||||||
outfile.write('Prize shuffle %s\n' %
|
outfile.write('Prize shuffle %s\n' %
|
||||||
self.metadata['shuffle_prizes'][player])
|
self.world.shuffle_prizes[player])
|
||||||
if self.entrances:
|
if self.entrances:
|
||||||
outfile.write('\n\nEntrances:\n\n')
|
outfile.write('\n\nEntrances:\n\n')
|
||||||
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_name(entry["player"])}: '
|
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_name(entry["player"])}: '
|
||||||
|
|
18
Generate.py
18
Generate.py
|
@ -121,10 +121,9 @@ def main(args=None, callback=ERmain):
|
||||||
f"A mix is also permitted.")
|
f"A mix is also permitted.")
|
||||||
erargs = parse_arguments(['--multi', str(args.multi)])
|
erargs = parse_arguments(['--multi', str(args.multi)])
|
||||||
erargs.seed = seed
|
erargs.seed = seed
|
||||||
erargs.create_spoiler = args.spoiler > 0
|
|
||||||
erargs.glitch_triforce = options["generator"]["glitch_triforce_room"]
|
erargs.glitch_triforce = options["generator"]["glitch_triforce_room"]
|
||||||
|
erargs.spoiler = args.spoiler
|
||||||
erargs.race = args.race
|
erargs.race = args.race
|
||||||
erargs.skip_playthrough = args.spoiler < 2
|
|
||||||
erargs.outputname = seed_name
|
erargs.outputname = seed_name
|
||||||
erargs.outputpath = args.outputpath
|
erargs.outputpath = args.outputpath
|
||||||
|
|
||||||
|
@ -587,8 +586,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
||||||
if ret.dark_room_logic not in {"lamp", "torches", "none"}:
|
if ret.dark_room_logic not in {"lamp", "torches", "none"}:
|
||||||
raise ValueError(f"Unknown Dark Room Logic: \"{ret.dark_room_logic}\"")
|
raise ValueError(f"Unknown Dark Room Logic: \"{ret.dark_room_logic}\"")
|
||||||
|
|
||||||
ret.restrict_dungeon_item_on_boss = get_choice_legacy('restrict_dungeon_item_on_boss', weights, False)
|
|
||||||
|
|
||||||
entrance_shuffle = get_choice_legacy('entrance_shuffle', weights, 'vanilla')
|
entrance_shuffle = get_choice_legacy('entrance_shuffle', weights, 'vanilla')
|
||||||
if entrance_shuffle.startswith('none-'):
|
if entrance_shuffle.startswith('none-'):
|
||||||
ret.shuffle = 'vanilla'
|
ret.shuffle = 'vanilla'
|
||||||
|
@ -628,11 +625,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
||||||
ret.shop_shuffle = ''
|
ret.shop_shuffle = ''
|
||||||
|
|
||||||
ret.mode = get_choice_legacy("mode", weights)
|
ret.mode = get_choice_legacy("mode", weights)
|
||||||
ret.retro = get_choice_legacy("retro", weights)
|
|
||||||
|
|
||||||
ret.hints = get_choice_legacy('hints', weights)
|
|
||||||
|
|
||||||
ret.swordless = get_choice_legacy('swordless', weights, False)
|
|
||||||
|
|
||||||
ret.difficulty = get_choice_legacy('item_pool', weights)
|
ret.difficulty = get_choice_legacy('item_pool', weights)
|
||||||
|
|
||||||
|
@ -641,12 +633,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
||||||
boss_shuffle = get_choice_legacy('boss_shuffle', weights)
|
boss_shuffle = get_choice_legacy('boss_shuffle', weights)
|
||||||
ret.shufflebosses = get_plando_bosses(boss_shuffle, plando_options)
|
ret.shufflebosses = get_plando_bosses(boss_shuffle, plando_options)
|
||||||
|
|
||||||
ret.enemy_shuffle = bool(get_choice_legacy('enemy_shuffle', weights, False))
|
|
||||||
|
|
||||||
ret.killable_thieves = get_choice_legacy('killable_thieves', weights, False)
|
|
||||||
ret.tile_shuffle = get_choice_legacy('tile_shuffle', weights, False)
|
|
||||||
ret.bush_shuffle = get_choice_legacy('bush_shuffle', weights, False)
|
|
||||||
|
|
||||||
ret.enemy_damage = {None: 'default',
|
ret.enemy_damage = {None: 'default',
|
||||||
'default': 'default',
|
'default': 'default',
|
||||||
'shuffled': 'shuffled',
|
'shuffled': 'shuffled',
|
||||||
|
@ -656,8 +642,6 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
||||||
|
|
||||||
ret.enemy_health = get_choice_legacy('enemy_health', weights)
|
ret.enemy_health = get_choice_legacy('enemy_health', weights)
|
||||||
|
|
||||||
ret.shufflepots = get_choice_legacy('pot_shuffle', weights)
|
|
||||||
|
|
||||||
ret.beemizer = int(get_choice_legacy('beemizer', weights, 0))
|
ret.beemizer = int(get_choice_legacy('beemizer', weights, 0))
|
||||||
|
|
||||||
ret.timer = {'none': False,
|
ret.timer = {'none': False,
|
||||||
|
|
12
Main.py
12
Main.py
|
@ -63,24 +63,17 @@ def main(args, seed=None):
|
||||||
world.customitemarray = args.customitemarray
|
world.customitemarray = args.customitemarray
|
||||||
|
|
||||||
world.accessibility = args.accessibility.copy()
|
world.accessibility = args.accessibility.copy()
|
||||||
world.retro = args.retro.copy()
|
|
||||||
|
|
||||||
world.hints = args.hints.copy()
|
|
||||||
world.open_pyramid = args.open_pyramid.copy()
|
world.open_pyramid = args.open_pyramid.copy()
|
||||||
world.boss_shuffle = args.shufflebosses.copy()
|
world.boss_shuffle = args.shufflebosses.copy()
|
||||||
world.enemy_shuffle = args.enemy_shuffle.copy()
|
world.enemy_shuffle = args.enemy_shuffle.copy()
|
||||||
world.enemy_health = args.enemy_health.copy()
|
world.enemy_health = args.enemy_health.copy()
|
||||||
world.enemy_damage = args.enemy_damage.copy()
|
world.enemy_damage = args.enemy_damage.copy()
|
||||||
world.killable_thieves = args.killable_thieves.copy()
|
|
||||||
world.bush_shuffle = args.bush_shuffle.copy()
|
|
||||||
world.tile_shuffle = args.tile_shuffle.copy()
|
|
||||||
world.beemizer = args.beemizer.copy()
|
world.beemizer = args.beemizer.copy()
|
||||||
world.timer = args.timer.copy()
|
world.timer = args.timer.copy()
|
||||||
world.countdown_start_time = args.countdown_start_time.copy()
|
world.countdown_start_time = args.countdown_start_time.copy()
|
||||||
world.red_clock_time = args.red_clock_time.copy()
|
world.red_clock_time = args.red_clock_time.copy()
|
||||||
world.blue_clock_time = args.blue_clock_time.copy()
|
world.blue_clock_time = args.blue_clock_time.copy()
|
||||||
world.green_clock_time = args.green_clock_time.copy()
|
world.green_clock_time = args.green_clock_time.copy()
|
||||||
world.shufflepots = args.shufflepots.copy()
|
|
||||||
world.dungeon_counters = args.dungeon_counters.copy()
|
world.dungeon_counters = args.dungeon_counters.copy()
|
||||||
world.triforce_pieces_available = args.triforce_pieces_available.copy()
|
world.triforce_pieces_available = args.triforce_pieces_available.copy()
|
||||||
world.triforce_pieces_required = args.triforce_pieces_required.copy()
|
world.triforce_pieces_required = args.triforce_pieces_required.copy()
|
||||||
|
@ -93,7 +86,6 @@ def main(args, seed=None):
|
||||||
world.plando_texts = args.plando_texts.copy()
|
world.plando_texts = args.plando_texts.copy()
|
||||||
world.plando_connections = args.plando_connections.copy()
|
world.plando_connections = args.plando_connections.copy()
|
||||||
world.er_seeds = getattr(args, "er_seeds", {})
|
world.er_seeds = getattr(args, "er_seeds", {})
|
||||||
world.restrict_dungeon_item_on_boss = args.restrict_dungeon_item_on_boss.copy()
|
|
||||||
world.required_medallions = args.required_medallions.copy()
|
world.required_medallions = args.required_medallions.copy()
|
||||||
world.game = args.game.copy()
|
world.game = args.game.copy()
|
||||||
world.set_options(args)
|
world.set_options(args)
|
||||||
|
@ -346,11 +338,11 @@ def main(args, seed=None):
|
||||||
logger.info(f'Generating output files ({i}/{len(output_file_futures)}).')
|
logger.info(f'Generating output files ({i}/{len(output_file_futures)}).')
|
||||||
future.result()
|
future.result()
|
||||||
|
|
||||||
if not args.skip_playthrough:
|
if args.spoiler > 1:
|
||||||
logger.info('Calculating playthrough.')
|
logger.info('Calculating playthrough.')
|
||||||
create_playthrough(world)
|
create_playthrough(world)
|
||||||
|
|
||||||
if args.create_spoiler:
|
if args.spoiler:
|
||||||
world.spoiler.to_file(os.path.join(temp_dir, '%s_Spoiler.txt' % outfilebase))
|
world.spoiler.to_file(os.path.join(temp_dir, '%s_Spoiler.txt' % outfilebase))
|
||||||
|
|
||||||
zipfilename = output_path(f"AP_{world.seed_name}.zip")
|
zipfilename = output_path(f"AP_{world.seed_name}.zip")
|
||||||
|
|
|
@ -74,9 +74,8 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
|
||||||
erargs = parse_arguments(['--multi', str(playercount)])
|
erargs = parse_arguments(['--multi', str(playercount)])
|
||||||
erargs.seed = seed
|
erargs.seed = seed
|
||||||
erargs.name = {x: "" for x in range(1, playercount + 1)} # only so it can be overwrittin in mystery
|
erargs.name = {x: "" for x in range(1, playercount + 1)} # only so it can be overwrittin in mystery
|
||||||
erargs.create_spoiler = not race
|
erargs.spoiler = 0 if race else 2
|
||||||
erargs.race = race
|
erargs.race = race
|
||||||
erargs.skip_playthrough = race
|
|
||||||
erargs.outputname = seedname
|
erargs.outputname = seedname
|
||||||
erargs.outputpath = target.name
|
erargs.outputpath = target.name
|
||||||
erargs.teams = 1
|
erargs.teams = 1
|
||||||
|
|
|
@ -20,7 +20,6 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
multiargs, _ = parser.parse_known_args(argv)
|
multiargs, _ = parser.parse_known_args(argv)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
|
parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
|
||||||
parser.add_argument('--create_spoiler', help='Output a Spoiler File', action='store_true')
|
|
||||||
parser.add_argument('--logic', default=defval('noglitches'), const='noglitches', nargs='?', choices=['noglitches', 'minorglitches', 'owglitches', 'hybridglitches', 'nologic'],
|
parser.add_argument('--logic', default=defval('noglitches'), const='noglitches', nargs='?', choices=['noglitches', 'minorglitches', 'owglitches', 'hybridglitches', 'nologic'],
|
||||||
help='''\
|
help='''\
|
||||||
Select Enforcement of Item Requirements. (default: %(default)s)
|
Select Enforcement of Item Requirements. (default: %(default)s)
|
||||||
|
@ -46,17 +45,6 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
Requires the moon pearl to be Link in the Light World
|
Requires the moon pearl to be Link in the Light World
|
||||||
instead of a bunny.
|
instead of a bunny.
|
||||||
''')
|
''')
|
||||||
parser.add_argument('--swordless', action='store_true',
|
|
||||||
help='''\
|
|
||||||
Toggles Swordless Mode
|
|
||||||
Swordless: No swords. Curtains in Skull Woods and Agahnim\'s
|
|
||||||
Tower are removed, Agahnim\'s Tower barrier can be
|
|
||||||
destroyed with hammer. Misery Mire and Turtle Rock
|
|
||||||
can be opened without a sword. Hammer damages Ganon.
|
|
||||||
Ether and Bombos Tablet can be activated with Hammer
|
|
||||||
(and Book). Bombos pads have been added in Ice
|
|
||||||
Palace, to allow for an alternative to firerod.
|
|
||||||
''')
|
|
||||||
parser.add_argument('--goal', default=defval('ganon'), const='ganon', nargs='?',
|
parser.add_argument('--goal', default=defval('ganon'), const='ganon', nargs='?',
|
||||||
choices=['ganon', 'pedestal', 'bosses', 'triforcehunt', 'localtriforcehunt', 'ganontriforcehunt', 'localganontriforcehunt', 'crystals', 'ganonpedestal'],
|
choices=['ganon', 'pedestal', 'bosses', 'triforcehunt', 'localtriforcehunt', 'ganontriforcehunt', 'localganontriforcehunt', 'crystals', 'ganonpedestal'],
|
||||||
help='''\
|
help='''\
|
||||||
|
@ -206,10 +194,6 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
time).
|
time).
|
||||||
''', type=int)
|
''', type=int)
|
||||||
|
|
||||||
parser.add_argument('--retro', default=defval(False), help='''\
|
|
||||||
Keys are universal, shooting arrows costs rupees,
|
|
||||||
and a few other little things make this more like Zelda-1.
|
|
||||||
''', action='store_true')
|
|
||||||
parser.add_argument('--local_items', default=defval(''),
|
parser.add_argument('--local_items', default=defval(''),
|
||||||
help='Specifies a list of items that will not spread across the multiworld (separated by commas)')
|
help='Specifies a list of items that will not spread across the multiworld (separated by commas)')
|
||||||
parser.add_argument('--non_local_items', default=defval(''),
|
parser.add_argument('--non_local_items', default=defval(''),
|
||||||
|
@ -223,9 +207,6 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
Locations: You will be able to reach every location in the game.
|
Locations: You will be able to reach every location in the game.
|
||||||
None: You will be able to reach enough locations to beat the game.
|
None: You will be able to reach enough locations to beat the game.
|
||||||
''')
|
''')
|
||||||
parser.add_argument('--hints', default=defval(False), help='''\
|
|
||||||
Make telepathic tiles and storytellers give helpful hints.
|
|
||||||
''', action='store_true')
|
|
||||||
# included for backwards compatibility
|
# included for backwards compatibility
|
||||||
parser.add_argument('--shuffleganon', help=argparse.SUPPRESS, action='store_true', default=defval(True))
|
parser.add_argument('--shuffleganon', help=argparse.SUPPRESS, action='store_true', default=defval(True))
|
||||||
parser.add_argument('--no-shuffleganon', help='''\
|
parser.add_argument('--no-shuffleganon', help='''\
|
||||||
|
@ -243,18 +224,13 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
parser.add_argument('--gui', help='Launch the GUI', action='store_true')
|
parser.add_argument('--gui', help='Launch the GUI', action='store_true')
|
||||||
parser.add_argument('--progression_balancing', action='store_true', default=defval(False),
|
parser.add_argument('--progression_balancing', action='store_true', default=defval(False),
|
||||||
help="Enable Multiworld Progression balancing.")
|
help="Enable Multiworld Progression balancing.")
|
||||||
parser.add_argument('--skip_playthrough', action='store_true', default=defval(False))
|
|
||||||
parser.add_argument('--enemizercli', default=defval('EnemizerCLI/EnemizerCLI.Core'))
|
parser.add_argument('--enemizercli', default=defval('EnemizerCLI/EnemizerCLI.Core'))
|
||||||
parser.add_argument('--shufflebosses', default=defval('none'), choices=['none', 'basic', 'normal', 'chaos',
|
parser.add_argument('--shufflebosses', default=defval('none'), choices=['none', 'basic', 'normal', 'chaos',
|
||||||
"singularity"])
|
"singularity"])
|
||||||
parser.add_argument('--enemy_shuffle', action='store_true')
|
|
||||||
parser.add_argument('--killable_thieves', action='store_true')
|
|
||||||
parser.add_argument('--tile_shuffle', action='store_true')
|
|
||||||
parser.add_argument('--bush_shuffle', action='store_true')
|
|
||||||
parser.add_argument('--enemy_health', default=defval('default'),
|
parser.add_argument('--enemy_health', default=defval('default'),
|
||||||
choices=['default', 'easy', 'normal', 'hard', 'expert'])
|
choices=['default', 'easy', 'normal', 'hard', 'expert'])
|
||||||
parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos'])
|
parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos'])
|
||||||
parser.add_argument('--shufflepots', default=defval(False), action='store_true')
|
|
||||||
parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4))
|
parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4))
|
||||||
parser.add_argument('--shop_shuffle', default='', help='''\
|
parser.add_argument('--shop_shuffle', default='', help='''\
|
||||||
combine letters for options:
|
combine letters for options:
|
||||||
|
@ -272,7 +248,6 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
For unlit dark rooms, require the Lamp to be considered in logic by default.
|
For unlit dark rooms, require the Lamp to be considered in logic by default.
|
||||||
Torches means additionally easily accessible Torches that can be lit with Fire Rod are considered doable.
|
Torches means additionally easily accessible Torches that can be lit with Fire Rod are considered doable.
|
||||||
None means full traversal through dark rooms without tools is considered doable.''')
|
None means full traversal through dark rooms without tools is considered doable.''')
|
||||||
parser.add_argument('--restrict_dungeon_item_on_boss', default=defval(False), action="store_true")
|
|
||||||
parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255))
|
parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255))
|
||||||
parser.add_argument('--names', default=defval(''))
|
parser.add_argument('--names', default=defval(''))
|
||||||
parser.add_argument('--outputpath')
|
parser.add_argument('--outputpath')
|
||||||
|
@ -307,19 +282,19 @@ def parse_arguments(argv, no_defaults=False):
|
||||||
for player in range(1, multiargs.multi + 1):
|
for player in range(1, multiargs.multi + 1):
|
||||||
playerargs = parse_arguments(shlex.split(getattr(ret, f"p{player}")), True)
|
playerargs = parse_arguments(shlex.split(getattr(ret, f"p{player}")), True)
|
||||||
|
|
||||||
for name in ['logic', 'mode', 'swordless', 'goal', 'difficulty', 'item_functionality',
|
for name in ['logic', 'mode', 'goal', 'difficulty', 'item_functionality',
|
||||||
'shuffle', 'open_pyramid', 'timer',
|
'shuffle', 'open_pyramid', 'timer',
|
||||||
'countdown_start_time', 'red_clock_time', 'blue_clock_time', 'green_clock_time',
|
'countdown_start_time', 'red_clock_time', 'blue_clock_time', 'green_clock_time',
|
||||||
'local_items', 'non_local_items', 'retro', 'accessibility', 'hints', 'beemizer',
|
'local_items', 'non_local_items', 'accessibility', 'beemizer',
|
||||||
'shufflebosses', 'enemy_shuffle', 'enemy_health', 'enemy_damage', 'shufflepots',
|
'shufflebosses', 'enemy_health', 'enemy_damage',
|
||||||
'sprite',
|
'sprite',
|
||||||
"progression_balancing", "triforce_pieces_available",
|
"progression_balancing", "triforce_pieces_available",
|
||||||
"triforce_pieces_required", "shop_shuffle",
|
"triforce_pieces_required", "shop_shuffle",
|
||||||
"required_medallions", "start_hints",
|
"required_medallions", "start_hints",
|
||||||
"plando_items", "plando_texts", "plando_connections", "er_seeds",
|
"plando_items", "plando_texts", "plando_connections", "er_seeds",
|
||||||
'dungeon_counters', 'killable_thieves',
|
'dungeon_counters',
|
||||||
'tile_shuffle', 'bush_shuffle', 'shuffle_prizes', 'sprite_pool', 'dark_room_logic',
|
'shuffle_prizes', 'sprite_pool', 'dark_room_logic',
|
||||||
'restrict_dungeon_item_on_boss', 'game']:
|
'game']:
|
||||||
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
|
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
|
||||||
if player == 1:
|
if player == 1:
|
||||||
setattr(ret, name, {1: value})
|
setattr(ret, name, {1: value})
|
||||||
|
|
|
@ -126,6 +126,59 @@ class Progressive(Choice):
|
||||||
return random.choice([True, False]) if self.value == self.option_grouped_random else bool(self.value)
|
return random.choice([True, False]) if self.value == self.option_grouped_random else bool(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
class Swordless(Toggle):
|
||||||
|
"""No swords. Curtains in Skull Woods and Agahnim\'s
|
||||||
|
Tower are removed, Agahnim\'s Tower barrier can be
|
||||||
|
destroyed with hammer. Misery Mire and Turtle Rock
|
||||||
|
can be opened without a sword. Hammer damages Ganon.
|
||||||
|
Ether and Bombos Tablet can be activated with Hammer
|
||||||
|
(and Book)."""
|
||||||
|
displayname = "Swordless"
|
||||||
|
|
||||||
|
|
||||||
|
class Retro(Toggle):
|
||||||
|
"""Zelda-1 like mode. You have to purchase a quiver to shoot arrows using rupees
|
||||||
|
and there are randomly placed take-any caves that contain one Sword and choices of Heart Container/Blue Potion."""
|
||||||
|
displayname = "Retro"
|
||||||
|
|
||||||
|
|
||||||
|
class RestrictBossItem(Toggle):
|
||||||
|
"""Don't place dungeon-native items on the dungeon's boss."""
|
||||||
|
displayname = "Prevent Dungeon Item on Boss"
|
||||||
|
|
||||||
|
|
||||||
|
class Hints(DefaultOnToggle):
|
||||||
|
"""Put item and entrance placement hints on telepathic tiles and some NPCs.
|
||||||
|
Additionally King Zora and Bottle Merchant say what they're selling."""
|
||||||
|
displayname = "Hints"
|
||||||
|
|
||||||
|
|
||||||
|
class EnemyShuffle(Toggle):
|
||||||
|
"""Randomize every enemy spawn.
|
||||||
|
If mode is Standard, Hyrule Castle is left out (may result in visually wrong enemy sprites in that area.)"""
|
||||||
|
displayname = "Enemy Shuffle"
|
||||||
|
|
||||||
|
|
||||||
|
class KillableThieves(Toggle):
|
||||||
|
"""Makes Thieves killable."""
|
||||||
|
displayname = "Killable Thieves"
|
||||||
|
|
||||||
|
|
||||||
|
class BushShuffle(Toggle):
|
||||||
|
"""Randomize chance that a bush contains an enemy as well as which enemy may spawn."""
|
||||||
|
displayname = "Bush Shuffle"
|
||||||
|
|
||||||
|
|
||||||
|
class TileShuffle(Toggle):
|
||||||
|
"""Randomize flying tiles floor patterns."""
|
||||||
|
displayname = "Tile Shuffle"
|
||||||
|
|
||||||
|
|
||||||
|
class PotShuffle(Toggle):
|
||||||
|
"""Shuffle contents of pots within "supertiles" (item will still be nearby original placement)."""
|
||||||
|
displayname = "Pot Shuffle"
|
||||||
|
|
||||||
|
|
||||||
class Palette(Choice):
|
class Palette(Choice):
|
||||||
option_default = 0
|
option_default = 0
|
||||||
option_good = 1
|
option_good = 1
|
||||||
|
@ -226,7 +279,16 @@ alttp_options: typing.Dict[str, type(Option)] = {
|
||||||
"compass_shuffle": compass_shuffle,
|
"compass_shuffle": compass_shuffle,
|
||||||
"map_shuffle": map_shuffle,
|
"map_shuffle": map_shuffle,
|
||||||
"progressive": Progressive,
|
"progressive": Progressive,
|
||||||
|
"swordless": Swordless,
|
||||||
|
"retro": Retro,
|
||||||
|
"hints": Hints,
|
||||||
|
"restrict_dungeon_item_on_boss": RestrictBossItem,
|
||||||
|
"pot_shuffle": PotShuffle,
|
||||||
|
"enemy_shuffle": EnemyShuffle,
|
||||||
|
"killable_thieves": KillableThieves,
|
||||||
|
"bush_shuffle": BushShuffle,
|
||||||
"shop_item_slots": ShopItemSlots,
|
"shop_item_slots": ShopItemSlots,
|
||||||
|
"tile_shuffle": TileShuffle,
|
||||||
"ow_palettes": OWPalette,
|
"ow_palettes": OWPalette,
|
||||||
"uw_palettes": UWPalette,
|
"uw_palettes": UWPalette,
|
||||||
"hud_palettes": HUDPalette,
|
"hud_palettes": HUDPalette,
|
||||||
|
|
|
@ -323,7 +323,7 @@ def patch_enemizer(world, player: int, rom: LocalRom, enemizercli, output_direct
|
||||||
'GrayscaleMode': False,
|
'GrayscaleMode': False,
|
||||||
'GenerateSpoilers': False,
|
'GenerateSpoilers': False,
|
||||||
'RandomizeLinkSpritePalette': False,
|
'RandomizeLinkSpritePalette': False,
|
||||||
'RandomizePots': world.shufflepots[player],
|
'RandomizePots': world.pot_shuffle[player],
|
||||||
'ShuffleMusic': False,
|
'ShuffleMusic': False,
|
||||||
'BootlegMagic': True,
|
'BootlegMagic': True,
|
||||||
'CustomBosses': False,
|
'CustomBosses': False,
|
||||||
|
|
|
@ -258,7 +258,7 @@ class ALTTPWorld(World):
|
||||||
try:
|
try:
|
||||||
use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player]
|
use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player]
|
||||||
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
|
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
|
||||||
or world.shufflepots[player] or world.bush_shuffle[player]
|
or world.pot_shuffle[player] or world.bush_shuffle[player]
|
||||||
or world.killable_thieves[player])
|
or world.killable_thieves[player])
|
||||||
|
|
||||||
rom = LocalRom(world.alttp_rom)
|
rom = LocalRom(world.alttp_rom)
|
||||||
|
|
Loading…
Reference in New Issue