diff --git a/CLI.py b/CLI.py index 96d3be21..0497069a 100644 --- a/CLI.py +++ b/CLI.py @@ -8,8 +8,6 @@ import textwrap import shlex import sys -from Main import main - import source.classes.constants as CONST from source.classes.BabelFish import BabelFish @@ -26,7 +24,15 @@ def parse_arguments(argv, no_defaults=False): # get settings settings = get_settings() - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") + lang = "en" + if argv is not None: + priority = get_args_priority(None, None, argv) + if "load" in priority: + priority = priority["load"] + if "lang" in priority: + lang = priority["lang"] + + fish = BabelFish(lang=lang) # we need to know how many players we have first parser = argparse.ArgumentParser(add_help=False) diff --git a/DoorShuffle.py b/DoorShuffle.py index 7b084fa4..249f9c20 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -5,9 +5,6 @@ import operator as op import time from enum import unique, Flag -from source.classes.BabelFish import BabelFish -import CLI as cli - from functools import reduce from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier from Regions import key_only_locations @@ -308,9 +305,6 @@ def pair_existing_key_doors(world, player, door_a, door_b): # paired_door.pair = False def within_dungeon(world, player): - settings = cli.get_settings() - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - fix_big_key_doors_with_ugly_smalls(world, player) overworld_prep(world, player) entrances_map, potentials, connections = determine_entrance_list(world, player) @@ -322,7 +316,7 @@ def within_dungeon(world, player): dungeon_builders[key] = simple_dungeon_builder(key, sector_list) dungeon_builders[key].entrance_list = list(entrances_map[key]) recombinant_builders = {} - handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map) + handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, world.fish) main_dungeon_generation(dungeon_builders, recombinant_builders, connections_tuple, world, player) paths = determine_required_paths(world, player) @@ -332,15 +326,15 @@ def within_dungeon(world, player): start = time.process_time() for builder in world.dungeon_layouts[player].values(): shuffle_key_doors(builder, world, player) - logging.getLogger('').info('%s: %s', fish.translate("cli","cli","keydoor.shuffle.time"), time.process_time()-start) + logging.getLogger('').info('%s: %s', world.fish.translate("cli","cli","keydoor.shuffle.time"), time.process_time()-start) smooth_door_pairs(world, player) -def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map): +def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, fish): for name, split_list in split_region_starts.items(): builder = dungeon_builders.pop(name) recombinant_builders[name] = builder - split_builders = split_dungeon_builder(builder, split_list) + split_builders = split_dungeon_builder(builder, split_list, fish) dungeon_builders.update(split_builders) for sub_name, split_entrances in split_list.items(): sub_builder = dungeon_builders[name+' '+sub_name] @@ -353,11 +347,6 @@ def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map) def main_dungeon_generation(dungeon_builders, recombinant_builders, connections_tuple, world, player): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - entrances_map, potentials, connections = connections_tuple enabled_entrances = {} sector_queue = deque(dungeon_builders.values()) @@ -377,7 +366,7 @@ def main_dungeon_generation(dungeon_builders, recombinant_builders, connections_ sector_queue.append(builder) last_key = builder.name else: - logging.getLogger('').info('%s: %s', fish.translate("cli","cli","generating.dungeon"), builder.name) + logging.getLogger('').info('%s: %s', world.fish.translate("cli","cli","generating.dungeon"), builder.name) ds = generate_dungeon(builder, origin_list_sans_drops, split_dungeon, world, player) find_new_entrances(ds, connections, potentials, enabled_entrances, world, player) ds.name = name @@ -724,9 +713,6 @@ def cross_dungeon(world, player): def assign_cross_keys(dungeon_builders, world, player): - settings = cli.get_settings() - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - start = time.process_time() total_keys = remaining = 29 total_candidates = 0 @@ -806,7 +792,7 @@ def assign_cross_keys(dungeon_builders, world, player): dungeon.small_keys = [] else: dungeon.small_keys = [ItemFactory(dungeon_keys[name], player)] * actual_chest_keys - logging.getLogger('').info('%s: %s', fish.translate("cli","cli","keydoor.shuffle.time.crossed"), time.process_time()-start) + logging.getLogger('').info('%s: %s', world.fish.translate("cli","cli","keydoor.shuffle.time.crossed"), time.process_time()-start) def reassign_boss(boss_region, boss_key, builder, gt, world, player): @@ -962,18 +948,15 @@ def calc_used_dungeon_items(builder): def find_valid_combination(builder, start_regions, world, player, drop_keys=True): - settings = cli.get_settings() - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - logger = logging.getLogger('') - logger.info('%s %s', fish.translate("cli","cli","shuffling.keydoors"), builder.name) + logger.info('%s %s', world.fish.translate("cli","cli","shuffling.keydoors"), builder.name) # find valid combination of candidates if len(builder.candidates) < builder.key_doors_num: if not drop_keys: logger.info('No valid layouts for %s with %s doors', builder.name, builder.key_doors_num) return False builder.key_doors_num = len(builder.candidates) # reduce number of key doors - logger.info('%s: %s', fish.translate("cli","cli","lowering.keys.candidates"), builder.name) + logger.info('%s: %s', world.fish.translate("cli","cli","lowering.keys.candidates"), builder.name) combinations = ncr(len(builder.candidates), builder.key_doors_num) itr = 0 start = time.process_time() @@ -993,7 +976,7 @@ def find_valid_combination(builder, start_regions, world, player, drop_keys=True if not drop_keys: logger.info('No valid layouts for %s with %s doors', builder.name, builder.key_doors_num) return False - logger.info('%s: %s', fish.translate("cli","cli","lowering.keys.layouts"), builder.name) + logger.info('%s: %s', world.fish.translate("cli","cli","lowering.keys.layouts"), builder.name) builder.key_doors_num -= 1 if builder.key_doors_num < 0: raise Exception('Bad dungeon %s - 0 key doors not valid' % builder.name) diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 25f15e36..2c009437 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -8,9 +8,6 @@ from functools import reduce import operator as op from typing import List -from source.classes.BabelFish import BabelFish -import CLI as cli - from BaseClasses import DoorType, Direction, CrystalBarrier, RegionType, Polarity, Sector, PolSlot, flooded_keys from Regions import key_only_locations, dungeon_events, flooded_keys_reverse from Dungeons import dungeon_regions @@ -1097,11 +1094,6 @@ def simple_dungeon_builder(name, sector_list): def create_dungeon_builders(all_sectors, world, player, dungeon_entrances=None): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - logger = logging.getLogger('') logger.info('Shuffling Dungeon Sectors') if dungeon_entrances is None: @@ -1157,8 +1149,8 @@ def create_dungeon_builders(all_sectors, world, player, dungeon_entrances=None): # polarity: if not global_pole.is_valid(dungeon_map): raise NeutralizingException('Either free location/crystal assignment is already globally invalid - lazy dev check this earlier!') - logger.info(fish.translate("cli","cli","balance.doors")) - assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger) + logger.info(world.fish.translate("cli","cli","balance.doors")) + assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger, world.fish) # the rest assign_the_rest(dungeon_map, neutral_sectors, global_pole) return dungeon_map @@ -1442,12 +1434,7 @@ def sum_polarity(sector_list): return pol -def assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - +def assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger, fish): # step 1: fix polarity connection issues logger.info(fish.translate("cli","cli","basic.traversal")) unconnected_builders = identify_polarity_issues(dungeon_map) @@ -1487,7 +1474,7 @@ def assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger problem_builders = identify_simple_branching_issues(problem_builders) # step 3: fix neutrality issues - polarity_step_3(dungeon_map, polarized_sectors, global_pole, logger) + polarity_step_3(dungeon_map, polarized_sectors, global_pole, logger, fish) # step 4: fix dead ends again neutral_choices: List[List] = neutralize_the_rest(polarized_sectors) @@ -1536,12 +1523,7 @@ def assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger tries += 1 -def polarity_step_3(dungeon_map, polarized_sectors, global_pole, logger): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - +def polarity_step_3(dungeon_map, polarized_sectors, global_pole, logger, fish): builder_order = list(dungeon_map.values()) random.shuffle(builder_order) for builder in builder_order: @@ -1849,12 +1831,7 @@ def assign_the_rest(dungeon_map, neutral_sectors, global_pole): assign_sector(sector_list[i], builder, neutral_sectors, global_pole) -def split_dungeon_builder(builder, split_list): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - +def split_dungeon_builder(builder, split_list, fish): logger = logging.getLogger('') logger.info(fish.translate("cli","cli","splitting.up") + ' ' + 'Desert/Skull') candidate_sectors = dict.fromkeys(builder.sectors) @@ -1867,15 +1844,10 @@ def split_dungeon_builder(builder, split_list): sub_builder.all_entrances = split_entrances for r_name in split_entrances: assign_sector(find_sector(r_name, candidate_sectors), sub_builder, candidate_sectors, global_pole) - return balance_split(candidate_sectors, dungeon_map, global_pole) + return balance_split(candidate_sectors, dungeon_map, global_pole, fish) -def balance_split(candidate_sectors, dungeon_map, global_pole): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - +def balance_split(candidate_sectors, dungeon_map, global_pole, fish): logger = logging.getLogger('') # categorize sectors crystal_switches, crystal_barriers, neutral_sectors, polarized_sectors = categorize_sectors(candidate_sectors) @@ -1889,7 +1861,7 @@ def balance_split(candidate_sectors, dungeon_map, global_pole): assign_crystal_barrier_sectors(dungeon_map, crystal_barriers, global_pole) # polarity: logger.info(fish.translate("cli","cli","re-balancing") + ' ' + next(iter(dungeon_map.keys())) + ' et al') - assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger) + assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger, fish) # the rest assign_the_rest(dungeon_map, neutral_sectors, global_pole) return dungeon_map diff --git a/DungeonRandomizer.py b/DungeonRandomizer.py index a66a7238..4a0c04e3 100755 --- a/DungeonRandomizer.py +++ b/DungeonRandomizer.py @@ -19,11 +19,6 @@ from Fill import FillError def start(): args = parse_arguments(None) - settings = get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - if is_bundled() and len(sys.argv) == 1: # for the bundled builds, if we have no arguments, the user # probably wants the gui. Users of the bundled build who want the command line @@ -49,6 +44,12 @@ def start(): loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[args.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) + settings = get_args_priority(None, None, None) + lang = "en" + if "load" in settings and "lang" in settings["load"]: + lang = settings["load"]["lang"] + fish = BabelFish(lang=lang) + if args.gui: from Gui import guiMain guiMain(args) @@ -58,7 +59,7 @@ def start(): logger = logging.getLogger('') for _ in range(args.count): try: - main(seed=seed, args=args) + main(seed=seed, args=args, fish=fish) logger.info('%s %s', fish.translate("cli","cli","finished.run"), _+1) except (FillError, Exception, RuntimeError) as err: failures.append((err, seed)) @@ -73,7 +74,7 @@ def start(): logger.info('Generation fail rate: ' + str(fail_rate[0] ).rjust(3, " ") + '.' + str(fail_rate[1] ).ljust(6, '0') + '%') logger.info('Generation success rate: ' + str(success_rate[0]).rjust(3, " ") + '.' + str(success_rate[1]).ljust(6, '0') + '%') else: - main(seed=args.seed, args=args) + main(seed=args.seed, args=args, fish=fish) if __name__ == '__main__': diff --git a/Main.py b/Main.py index 33ca7548..b34518fe 100644 --- a/Main.py +++ b/Main.py @@ -8,9 +8,6 @@ import random import time import zlib -from source.classes.BabelFish import BabelFish -import CLI as cli - from BaseClasses import World, CollectionState, Item, Region, Location, Shop from Items import ItemFactory from KeyDoorShuffle import validate_key_placement @@ -30,18 +27,13 @@ from Utils import output_path, parse_player_names, print_wiki_doors_by_room __version__ = '0.0.18.4d' -def main(args, seed=None): +def main(args, seed=None, fish=None): if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) output_path.cached_path = args.outputpath start = time.perf_counter() - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - # initialize the world world = World(args.multi, args.shuffle, args.door_shuffle, args.logic, args.mode, args.swords, args.difficulty, args.item_functionality, args.timer, args.progressive, args.goal, args.algorithm, args.accessibility, args.shuffleganon, args.retro, args.custom, args.customitemarray, args.hints) logger = logging.getLogger('') @@ -67,15 +59,16 @@ def main(args, seed=None): world.beemizer = args.beemizer.copy() world.experimental = args.experimental.copy() world.dungeon_counters = args.dungeon_counters.copy() + world.fish = fish world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} logger.info( '%s %s %s - %s: %s\n', - fish.translate("cli","cli","app.title"), - fish.translate("cli","cli","version"), + world.fish.translate("cli","cli","app.title"), + world.fish.translate("cli","cli","version"), __version__, - fish.translate("cli","cli","seed"), + world.fish.translate("cli","cli","seed"), world.seed ) @@ -110,7 +103,7 @@ def main(args, seed=None): create_rooms(world, player) create_dungeons(world, player) - logger.info(fish.translate("cli","cli","shuffling.world")) + logger.info(world.fish.translate("cli","cli","shuffling.world")) for player in range(1, world.players + 1): if world.mode[player] != 'inverted': @@ -118,7 +111,7 @@ def main(args, seed=None): else: link_inverted_entrances(world, player) - logger.info(fish.translate("cli","cli","shuffling.dungeons")) + logger.info(world.fish.translate("cli","cli","shuffling.dungeons")) for player in range(1, world.players + 1): link_doors(world, player) @@ -126,21 +119,21 @@ def main(args, seed=None): mark_light_world_regions(world, player) else: mark_dark_world_regions(world, player) - logger.info(fish.translate("cli","cli","generating.itempool")) + logger.info(world.fish.translate("cli","cli","generating.itempool")) for player in range(1, world.players + 1): generate_itempool(world, player) - logger.info(fish.translate("cli","cli","calc.access.rules")) + logger.info(world.fish.translate("cli","cli","calc.access.rules")) for player in range(1, world.players + 1): set_rules(world, player) - logger.info(fish.translate("cli","cli","placing.dungeon.prizes")) + logger.info(world.fish.translate("cli","cli","placing.dungeon.prizes")) fill_prizes(world) - logger.info(fish.translate("cli","cli","placing.dungeon.items")) + logger.info(world.fish.translate("cli","cli","placing.dungeon.items")) shuffled_locations = None if args.algorithm in ['balanced', 'vt26'] or any(list(args.mapshuffle.values()) + list(args.compassshuffle.values()) + @@ -157,14 +150,14 @@ def main(args, seed=None): raise RuntimeError( "%s: %s (%s %d)" % ( - fish.translate("cli","cli","keylock.detected"), + world.fish.translate("cli","cli","keylock.detected"), key_layout.sector.name, - fish.translate("cli","cli","player"), + world.fish.translate("cli","cli","player"), player ) ) - logger.info(fish.translate("cli","cli","fill.world")) + logger.info(world.fish.translate("cli","cli","fill.world")) if args.algorithm == 'flood': flood_items(world) # different algo, biased towards early game progress items @@ -183,14 +176,14 @@ def main(args, seed=None): distribute_items_restrictive(world, True) if world.players > 1: - logger.info(fish.translate("cli","cli","balance.multiworld")) + logger.info(world.fish.translate("cli","cli","balance.multiworld")) balance_multiworld_progression(world) # if we only check for beatable, we can do this sanity check first before creating the rom if not world.can_beat_game(): - raise RuntimeError(fish.translate("cli","cli","cannot.beat.game")) + raise RuntimeError(world.fish.translate("cli","cli","cannot.beat.game")) - logger.info(fish.translate("cli","cli","patching.rom")) + logger.info(world.fish.translate("cli","cli","patching.rom")) outfilebase = 'DR_%s' % (args.outputname if args.outputname else world.seed) @@ -214,8 +207,8 @@ def main(args, seed=None): if not args.jsonout: rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000) else: - logging.warning(fish.translate("cli","cli","enemizer.not.found") + ': ' + args.enemizercli) - logging.warning(fish.translate("cli","cli","enemizer.nothing.applied")) + logging.warning(world.fish.translate("cli","cli","enemizer.not.found") + ': ' + args.enemizercli) + logging.warning(world.fish.translate("cli","cli","enemizer.nothing.applied")) if args.race: patch_race_rom(rom) @@ -269,7 +262,7 @@ def main(args, seed=None): world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase)) if not args.skip_playthrough: - logger.info(fish.translate("cli","cli","calc.playthrough")) + logger.info(world.fish.translate("cli","cli","calc.playthrough")) create_playthrough(world) if args.jsonout: @@ -277,8 +270,8 @@ def main(args, seed=None): elif args.create_spoiler and not args.skip_playthrough: world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase)) - logger.info(fish.translate("cli","cli","done")) - logger.info('%s: %s', fish.translate("cli","cli","total.time"), time.perf_counter() - start) + logger.info(world.fish.translate("cli","cli","done")) + logger.info('%s: %s', world.fish.translate("cli","cli","total.time"), time.perf_counter() - start) # print_wiki_doors_by_room(dungeon_regions,world,1) @@ -414,11 +407,6 @@ def copy_dynamic_regions_and_locations(world, ret): def create_playthrough(world): - settings = cli.get_args_priority(None, None, None) - if "load" in settings: - settings = settings["load"] - fish = BabelFish(lang=settings["lang"] if "lang" in settings else "en") - # create a copy as we will modify it old_world = world world = copy_world(world) @@ -429,7 +417,7 @@ def create_playthrough(world): collection_spheres = [] state = CollectionState(world) sphere_candidates = list(prog_locations) - logging.getLogger('').debug(fish.translate("cli","cli","building.collection.spheres")) + logging.getLogger('').debug(world.fish.translate("cli","cli","building.collection.spheres")) while sphere_candidates: state.sweep_for_events(key_only=True) state.sweep_for_crystal_access() @@ -452,7 +440,7 @@ def create_playthrough(world): if not sphere: logging.getLogger('').debug('The following items could not be reached: %s', ['%s (Player %d) at %s (Player %d)' % (location.item.name, location.item.player, location.name, location.player) for location in sphere_candidates]) if any([world.accessibility[location.item.player] != 'none' for location in sphere_candidates]): - raise RuntimeError(fish.translate("cli","cli","cannot.reach.progression")) + raise RuntimeError(world.fish.translate("cli","cli","cannot.reach.progression")) else: old_world.spoiler.unreachables = sphere_candidates.copy() break @@ -506,7 +494,7 @@ def create_playthrough(world): logging.getLogger('').debug('Calculated final sphere %i, containing %i of %i progress items.', len(collection_spheres), len(sphere), len(required_locations)) if not sphere: - raise RuntimeError(fish.translate("cli","cli","cannot.reach.required")) + raise RuntimeError(world.fish.translate("cli","cli","cannot.reach.required")) # store the required locations for statistical analysis old_world.required_locations = [(location.name, location.player) for sphere in collection_spheres for location in sphere]