Exemple #1
0
 def setUp(self):
     self.world = World(1, {1: 'vanilla'}, {1: 'noglitches'}, {1: 'open'},
                        {1: 'random'}, {1: 'normal'}, {1: 'normal'},
                        {1: False}, {1: 'on'}, {1: 'ganon'}, 'balanced',
                        {1: 'items'}, True, {1: False}, False, None,
                        {1: False})
     self.starting_regions = []  # Where to start exploring
     self.remove_exits = []  # Block dungeon exits
     self.world.difficulty_requirements[1] = difficulties['normal']
     create_regions(self.world, 1)
     create_dungeons(self.world, 1)
     create_shops(self.world, 1)
     for exitname, regionname in mandatory_connections:
         connect_simple(self.world, exitname, regionname, 1)
     connect_simple(self.world, 'Big Bomb Shop', 'Big Bomb Shop', 1)
     self.world.get_region('Menu', 1).exits = []
     self.world.swamp_patch_required[1] = True
     set_rules(self.world, 1)
     generate_itempool(self.world, 1)
     self.world.itempool.extend(get_dungeon_item_pool(self.world))
     self.world.itempool.extend(
         ItemFactory([
             'Green Pendant', 'Red Pendant', 'Blue Pendant',
             'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2',
             'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'
         ], 1))
Exemple #2
0
 def setUp(self):
     self.world = World(1, {1: 'vanilla'}, {1: 'owglitches'}, {1: 'open'},
                        {1: 'random'}, {1: 'normal'}, {1: 'normal'},
                        {1: False}, {1: 'on'}, {1: 'ganon'}, 'balanced',
                        {1: 'items'}, True, {1: False}, False, None,
                        {1: False})
     self.world.difficulty_requirements[1] = difficulties['normal']
     create_regions(self.world, 1)
     create_dungeons(self.world, 1)
     create_shops(self.world, 1)
     link_entrances(self.world, 1)
     generate_itempool(self.world, 1)
     self.world.required_medallions[1] = ['Ether', 'Quake']
     self.world.itempool.extend(get_dungeon_item_pool(self.world))
     self.world.itempool.extend(
         ItemFactory([
             'Green Pendant', 'Red Pendant', 'Blue Pendant',
             'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2',
             'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'
         ], 1))
     self.world.get_location('Agahnim 1', 1).item = None
     self.world.get_location('Agahnim 2', 1).item = None
     self.world.precollected_items.clear()
     self.world.itempool.append(ItemFactory('Pegasus Boots', 1))
     mark_dark_world_regions(self.world, 1)
     set_rules(self.world, 1)
 def setUp(self):
     self.world = World(1, 'vanilla', 'noglitches', 'inverted', 'random',
                        'normal', 'normal', 'none', 'on', 'ganon',
                        'balanced', True, False, False, False, False, False,
                        False, False, False, None, 'none', False)
     self.world.difficulty_requirements = difficulties['normal']
     create_inverted_regions(self.world, 1)
     create_dungeons(self.world, 1)
     link_inverted_entrances(self.world, 1)
     generate_itempool(self.world, 1)
     self.world.required_medallions[1] = ['Ether', 'Quake']
     self.world.itempool.extend(get_dungeon_item_pool(self.world))
     self.world.itempool.extend(
         ItemFactory([
             'Green Pendant', 'Red Pendant', 'Blue Pendant',
             'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2',
             'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'
         ], 1))
     self.world.get_location('Agahnim 1', 1).item = None
     self.world.get_location('Agahnim 2', 1).item = None
     mark_light_world_regions(self.world)
     set_rules(self.world, 1)
 def setUp(self):
     self.world = World(1, 'vanilla', 'noglitches', 'open', 'random',
                        'normal', 'normal', 'none', 'on', 'ganon',
                        'balanced', True, False, False, False, False, False,
                        False, False, False, None, 'none', False)
     self.starting_regions = []
     self.world.difficulty_requirements = difficulties['normal']
     create_regions(self.world, 1)
     create_dungeons(self.world, 1)
     for exitname, regionname in mandatory_connections:
         connect_simple(self.world, exitname, regionname, 1)
     connect_simple(self.world, self.world.get_entrance('Big Bomb Shop', 1),
                    self.world.get_region('Big Bomb Shop', 1), 1)
     self.world.swamp_patch_required[1] = True
     set_rules(self.world, 1)
     generate_itempool(self.world, 1)
     self.world.itempool.extend(get_dungeon_item_pool(self.world))
     self.world.itempool.extend(
         ItemFactory([
             'Green Pendant', 'Red Pendant', 'Blue Pendant',
             'Beat Agahnim 1', 'Beat Agahnim 2', 'Crystal 1', 'Crystal 2',
             'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7'
         ], 1))
Exemple #5
0
def main(args, seed=None):
    start = time.clock()

    # initialize the world
    world = World(args.bridge, args.open_forest, args.open_door_of_time,
                  not args.nodungeonitems, args.beatableonly, args.hints)
    logger = logging.getLogger('')
    if seed is None:
        random.seed(None)
        world.seed = random.randint(0, 999999999)
    else:
        world.seed = int(seed)
    random.seed(world.seed)

    logger.info('OoT Randomizer Version %s  -  Seed: %s\n\n', __version__,
                world.seed)

    create_regions(world)

    create_dungeons(world)

    logger.info('Shuffling the World about.')

    link_entrances(world)

    logger.info('Calculating Access Rules.')

    set_rules(world)

    logger.info('Generating Item Pool.')

    generate_itempool(world)

    logger.info('Placing Dungeon Items.')

    shuffled_locations = None
    shuffled_locations = world.get_unfilled_locations()
    random.shuffle(shuffled_locations)
    fill_dungeons_restrictive(world, shuffled_locations)

    logger.info('Fill the world.')

    distribute_items_restrictive(world)

    logger.info('Calculating playthrough.')

    create_playthrough(world)

    logger.info('Patching ROM.')

    outfilebase = 'OoT_%s%s%s%s_%s' % (
        world.bridge, "-openforest" if world.open_forest else "",
        "-opendoor" if world.open_door_of_time else "",
        "-beatableonly" if world.check_beatable_only else "", world.seed)

    if not args.suppress_rom:
        rom = LocalRom(args.rom)
        patch_rom(world, rom)
        rom.write_to_file(output_path('%s.z64' % outfilebase))
        if args.compress_rom:
            logger.info('Compressing ROM.')
            if platform.system() == 'Windows':
                subprocess.call([
                    "Compress\Compress.exe",
                    (output_path('%s.z64' % outfilebase)),
                    (output_path('%s-comp.z64' % outfilebase))
                ])
            elif platform.system() == 'Linux':
                subprocess.call(
                    ["Compress/Compress", ('%s.z64' % outfilebase)])
            elif platform.system() == 'Darwin':
                subprocess.call(
                    ["Compress/Compress.out", ('%s.z64' % outfilebase)])
            else:
                logger.info('OS not supported for compression')

    if args.create_spoiler:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.clock() - start)

    return world
def main(args, seed=None):
    if args.outputpath:
        os.makedirs(args.outputpath, exist_ok=True)
        output_path.cached_path = args.outputpath

    start = time.perf_counter()

    # initialize the world
    world = World(args.multi, args.shuffle, args.logic, args.mode, args.swords,
                  args.difficulty, args.item_functionality, args.timer,
                  args.progressive.copy(), args.goal, args.algorithm,
                  args.accessibility, args.shuffleganon, args.retro,
                  args.custom, args.customitemarray, args.hints)
    logger = logging.getLogger('')
    world.seed = get_seed(seed)
    random.seed(world.seed)

    world.remote_items = args.remote_items.copy()
    world.mapshuffle = args.mapshuffle.copy()
    world.compassshuffle = args.compassshuffle.copy()
    world.keyshuffle = args.keyshuffle.copy()
    world.bigkeyshuffle = args.bigkeyshuffle.copy()
    world.crystals_needed_for_ganon = {
        player: random.randint(0, 7) if args.crystals_ganon[player] == 'random'
        else int(args.crystals_ganon[player])
        for player in range(1, world.players + 1)
    }
    world.crystals_needed_for_gt = {
        player: random.randint(0, 7) if args.crystals_gt[player] == 'random'
        else int(args.crystals_gt[player])
        for player in range(1, world.players + 1)
    }
    world.open_pyramid = args.openpyramid.copy()
    world.boss_shuffle = args.shufflebosses.copy()
    world.enemy_shuffle = args.shuffleenemies.copy()
    world.enemy_health = args.enemy_health.copy()
    world.enemy_damage = args.enemy_damage.copy()
    world.beemizer = args.beemizer.copy()
    world.timer = args.timer.copy()
    world.shufflepots = args.shufflepots.copy()
    world.progressive = args.progressive.copy()
    world.dungeon_counters = args.dungeon_counters.copy()
    world.glitch_boots = args.glitch_boots.copy()
    world.triforce_pieces_available = args.triforce_pieces_available.copy()
    world.triforce_pieces_required = args.triforce_pieces_required.copy()
    world.progression_balancing = {
        player: not balance
        for player, balance in args.skip_progression_balancing.items()
    }

    world.rom_seeds = {
        player: random.randint(0, 999999999)
        for player in range(1, world.players + 1)
    }

    logger.info('ALttP Berserker\'s Multiworld Version %s  -  Seed: %s\n',
                __version__, world.seed)

    parsed_names = parse_player_names(args.names, world.players, args.teams)
    world.teams = len(parsed_names)
    for i, team in enumerate(parsed_names, 1):
        if world.players > 1:
            logger.info('%s%s',
                        'Team%d: ' % i if world.teams > 1 else 'Players: ',
                        ', '.join(team))
        for player, name in enumerate(team, 1):
            world.player_names[player].append(name)

    logger.info('')

    for player in range(1, world.players + 1):
        world.difficulty_requirements[player] = difficulties[
            world.difficulty[player]]

        if world.mode[player] == 'standard' and world.enemy_shuffle[
                player] != 'none':
            world.escape_assist[player].append(
                'bombs'
            )  # enemized escape assumes infinite bombs available and will likely be unbeatable without it

        for tok in filter(None, args.startinventory[player].split(',')):
            item = ItemFactory(tok.strip(), player)
            if item:
                world.push_precollected(item)
        world.local_items[player] = {
            item.strip()
            for item in args.local_items[player].split(',')
        }

        world.triforce_pieces_available[player] = max(
            world.triforce_pieces_available[player],
            world.triforce_pieces_required[player])

        if world.mode[player] != 'inverted':
            create_regions(world, player)
        else:
            create_inverted_regions(world, player)
        create_shops(world, player)
        create_dungeons(world, player)

    logger.info('Shuffling the World about.')

    for player in range(1, world.players + 1):
        if world.mode[player] != 'inverted':
            link_entrances(world, player)
            mark_light_world_regions(world, player)
        else:
            link_inverted_entrances(world, player)
            mark_dark_world_regions(world, player)

    logger.info('Generating Item Pool.')

    for player in range(1, world.players + 1):
        generate_itempool(world, player)

    logger.info('Calculating Access Rules.')

    for player in range(1, world.players + 1):
        set_rules(world, player)

    logger.info('Placing Dungeon Prizes.')

    fill_prizes(world)

    logger.info('Placing Dungeon Items.')

    shuffled_locations = None
    if args.algorithm in ['balanced', 'vt26'] or any(
            list(args.mapshuffle.values()) +
            list(args.compassshuffle.values()) +
            list(args.keyshuffle.values()) +
            list(args.bigkeyshuffle.values())):
        shuffled_locations = world.get_unfilled_locations()
        random.shuffle(shuffled_locations)
        fill_dungeons_restrictive(world, shuffled_locations)
    else:
        fill_dungeons(world)

    logger.info('Fill the world.')

    if args.algorithm == 'flood':
        flood_items(
            world)  # different algo, biased towards early game progress items
    elif args.algorithm == 'vt21':
        distribute_items_cutoff(world, 1)
    elif args.algorithm == 'vt22':
        distribute_items_cutoff(world, 0.66)
    elif args.algorithm == 'freshness':
        distribute_items_staleness(world)
    elif args.algorithm == 'vt25':
        distribute_items_restrictive(world, False)
    elif args.algorithm == 'vt26':

        distribute_items_restrictive(world, True, shuffled_locations)
    elif args.algorithm == 'balanced':
        distribute_items_restrictive(world, True)

    if world.players > 1:
        balance_multiworld_progression(world)

    logger.info('Patching ROM.')

    outfilebase = 'BM_%s' % (args.outputname
                             if args.outputname else world.seed)

    rom_names = []

    def _gen_rom(team: int, player: int):
        sprite_random_on_hit = type(
            args.sprite[player]) is str and args.sprite[player].lower(
            ) == 'randomonhit'
        use_enemizer = (world.boss_shuffle[player] != 'none'
                        or world.enemy_shuffle[player] != 'none'
                        or world.enemy_health[player] != 'default'
                        or world.enemy_damage[player] != 'default'
                        or args.shufflepots[player] or sprite_random_on_hit)

        rom = LocalRom(args.rom)

        patch_rom(world, rom, player, team, use_enemizer)

        if use_enemizer:
            patch_enemizer(world, player, rom, args.enemizercli,
                           sprite_random_on_hit)

        if args.race:
            patch_race_rom(rom)

        world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash)

        apply_rom_settings(rom, args.heartbeep[player],
                           args.heartcolor[player], args.quickswap[player],
                           args.fastmenu[player], args.disablemusic[player],
                           args.sprite[player], args.ow_palettes[player],
                           args.uw_palettes[player])

        mcsb_name = ''
        if all([
                world.mapshuffle[player], world.compassshuffle[player],
                world.keyshuffle[player], world.bigkeyshuffle[player]
        ]):
            mcsb_name = '-keysanity'
        elif [
                world.mapshuffle[player], world.compassshuffle[player],
                world.keyshuffle[player], world.bigkeyshuffle[player]
        ].count(True) == 1:
            mcsb_name = '-mapshuffle' if world.mapshuffle[
                player] else '-compassshuffle' if world.compassshuffle[
                    player] else '-keyshuffle' if world.keyshuffle[
                        player] else '-bigkeyshuffle'
        elif any([
                world.mapshuffle[player], world.compassshuffle[player],
                world.keyshuffle[player], world.bigkeyshuffle[player]
        ]):
            mcsb_name = '-%s%s%s%sshuffle' % (
                'M' if world.mapshuffle[player] else '',
                'C' if world.compassshuffle[player] else '',
                'S' if world.keyshuffle[player] else '',
                'B' if world.bigkeyshuffle[player] else '')

        outfilepname = f'_T{team + 1}' if world.teams > 1 else ''
        if world.players > 1:
            outfilepname += f'_P{player}'
        if world.players > 1 or world.teams > 1:
            outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[
                player][team] != 'Player%d' % player else ''
        outfilesuffix = (
            '_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' %
            (world.logic[player], world.difficulty[player],
             world.difficulty_adjustments[player], world.mode[player],
             world.goal[player],
             "" if world.timer[player] in [False, 'display'] else "-" +
             world.timer[player], world.shuffle[player], world.algorithm,
             mcsb_name, "-retro" if world.retro[player] else "",
             "-prog_" + world.progressive[player] if world.progressive[player]
             in ['off', 'random'] else "", "-nohints" if
             not world.hints[player] else "")) if not args.outputname else ''
        rompath = output_path(
            f'{outfilebase}{outfilepname}{outfilesuffix}.sfc')
        rom.write_to_file(rompath)
        if args.create_diff:
            import Patch
            Patch.create_patch_file(rompath)
        return (player, team, list(rom.name))

    if not args.suppress_rom:
        import concurrent.futures
        futures = []
        with concurrent.futures.ThreadPoolExecutor() as pool:
            for team in range(world.teams):
                for player in range(1, world.players + 1):
                    futures.append(pool.submit(_gen_rom, team, player))
        for future in futures:
            rom_name = future.result()
            rom_names.append(rom_name)

        def get_entrance_to_region(region: Region):
            for entrance in region.entrances:
                if entrance.parent_region.type in (RegionType.DarkWorld,
                                                   RegionType.LightWorld):
                    return entrance
            for entrance in region.entrances:  # BFS might be better here, trying DFS for now.
                return get_entrance_to_region(entrance.parent_region)

        # collect ER hint info
        er_hint_data = {
            player: {}
            for player in range(1, world.players + 1)
            if world.shuffle[player] != "vanilla"
        }
        from Regions import RegionType
        for region in world.regions:
            if region.player in er_hint_data and region.locations:
                main_entrance = get_entrance_to_region(region)
                for location in region.locations:
                    if type(location.address
                            ) == int:  # skips events and crystals
                        if lookup_vanilla_location_to_entrance[
                                location.address] != main_entrance.name:
                            er_hint_data[region.player][
                                location.address] = main_entrance.name

        precollected_items = [[] for player in range(world.players)]
        for item in world.precollected_items:
            precollected_items[item.player - 1].append(item.code)

        multidata = zlib.compress(
            json.dumps({
                "names":
                parsed_names,
                "roms":
                rom_names,
                "remote_items": [
                    player for player in range(1, world.players + 1)
                    if world.remote_items[player]
                ],
                "locations": [((location.address, location.player),
                               (location.item.code, location.item.player))
                              for location in world.get_filled_locations()
                              if type(location.address) is int],
                "server_options":
                get_options()["server_options"],
                "er_hint_data":
                er_hint_data,
                "precollected_items":
                precollected_items
            }).encode("utf-8"), 9)

        with open(output_path('%s.multidata' % outfilebase), 'wb') as f:
            f.write(multidata)

    if not args.skip_playthrough:
        logger.info('Calculating playthrough.')
        create_playthrough(world)

    if args.create_spoiler:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.perf_counter() - start)

    return world
Exemple #7
0
def main(settings):
    start = time.clock()

    # initialize the world

    worlds = []

    if not settings.world_count:
        settings.world_count = 1
    if settings.world_count < 1:
        raise Exception('World Count must be at least 1')
    if settings.player_num > settings.world_count or settings.player_num < 1:
        raise Exception('Player Num must be between 1 and %d' %
                        settings.world_count)

    for i in range(0, settings.world_count):
        worlds.append(World(settings))

    logger = logging.getLogger('')

    random.seed(worlds[0].numeric_seed)

    logger.info('OoT Randomizer Version %s  -  Seed: %s\n\n', __version__,
                worlds[0].seed)

    for id, world in enumerate(worlds):
        world.id = id
        logger.info('Generating World %d.' % id)

        logger.info('Creating Overworld')
        create_regions(world)
        logger.info('Creating Dungeons')
        create_dungeons(world)
        logger.info('Linking Entrances')
        link_entrances(world)
        logger.info('Calculating Access Rules.')
        set_rules(world)
        logger.info('Generating Item Pool.')
        generate_itempool(world)

    logger.info('Fill the world.')
    distribute_items_restrictive(worlds)

    if settings.create_spoiler:
        logger.info('Calculating playthrough.')
        create_playthrough(worlds)
    CollectionState.update_required_items(worlds)

    logger.info('Patching ROM.')

    if settings.world_count > 1:
        outfilebase = 'OoT_%s_%s_W%dP%d' % (
            worlds[0].settings_string, worlds[0].seed, worlds[0].world_count,
            worlds[0].player_num)
    else:
        outfilebase = 'OoT_%s_%s' % (worlds[0].settings_string, worlds[0].seed)

    output_dir = default_output_path(settings.output_dir)

    if not settings.suppress_rom:
        rom = LocalRom(settings)
        patch_rom(worlds[settings.player_num - 1], rom)

        rom_path = os.path.join(output_dir, '%s.z64' % outfilebase)

        rom.write_to_file(rom_path)
        if settings.compress_rom:
            logger.info('Compressing ROM.')
            if platform.system() == 'Windows':
                subprocess.call([
                    "Compress\\Compress.exe", rom_path,
                    os.path.join(output_dir, '%s-comp.z64' % outfilebase)
                ])
            elif platform.system() == 'Linux':
                subprocess.call([
                    "Compress/Compress", rom_path,
                    os.path.join(output_dir, '%s-comp.z64' % outfilebase)
                ])
            elif platform.system() == 'Darwin':
                subprocess.call(
                    ["Compress/Compress.out", ('%s.z64' % outfilebase)])
            else:
                logger.info('OS not supported for compression')

    if settings.create_spoiler:
        worlds[settings.player_num - 1].spoiler.to_file(
            os.path.join(output_dir, '%s_Spoiler.txt' % outfilebase))
    os.remove('hints.txt')
    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.clock() - start)

    return worlds[settings.player_num - 1]
Exemple #8
0
def main(args, seed=None):
    start = time.clock()

    # initialize the world
    world = World(args.shuffle, args.logic, args.mode, args.difficulty, args.timer, args.progressive, args.goal, args.algorithm, not args.nodungeonitems, args.beatableonly, args.shuffleganon, args.quickswap, args.fastmenu, args.disablemusic, args.keysanity, args.retro, args.custom, args.customitemarray)
    logger = logging.getLogger('')
    if seed is None:
        random.seed(None)
        world.seed = random.randint(0, 999999999)
    else:
        world.seed = int(seed)
    random.seed(world.seed)

    logger.info('ALttP Entrance Randomizer Version %s  -  Seed: %s\n\n', __version__, world.seed)

    world.difficulty_requirements = difficulties[world.difficulty]

    create_regions(world)

    create_dungeons(world)

    logger.info('Shuffling the World about.')

    link_entrances(world)
    mark_light_world_regions(world)

    logger.info('Calculating Access Rules.')

    set_rules(world)

    logger.info('Generating Item Pool.')

    generate_itempool(world)

    logger.info('Placing Dungeon Items.')

    shuffled_locations = None
    if args.algorithm in ['balanced', 'vt26'] or args.keysanity:
        shuffled_locations = world.get_unfilled_locations()
        random.shuffle(shuffled_locations)
        fill_dungeons_restrictive(world, shuffled_locations)
    else:
        fill_dungeons(world)

    logger.info('Fill the world.')

    if args.algorithm == 'flood':
        flood_items(world)  # different algo, biased towards early game progress items
    elif args.algorithm == 'vt21':
        distribute_items_cutoff(world, 1)
    elif args.algorithm == 'vt22':
        distribute_items_cutoff(world, 0.66)
    elif args.algorithm == 'freshness':
        distribute_items_staleness(world)
    elif args.algorithm == 'vt25':
        distribute_items_restrictive(world, 0)
    elif args.algorithm == 'vt26':

        distribute_items_restrictive(world, gt_filler(world), shuffled_locations)
    elif args.algorithm == 'balanced':
        distribute_items_restrictive(world, gt_filler(world))

    logger.info('Calculating playthrough.')

    create_playthrough(world)

    logger.info('Patching ROM.')

    if args.sprite is not None:
        if isinstance(args.sprite, Sprite):
            sprite = args.sprite
        else:
            sprite = Sprite(args.sprite)
    else:
        sprite = None

    outfilebase = 'ER_%s_%s-%s-%s%s_%s-%s%s%s%s_%s' % (world.logic, world.difficulty, world.mode, world.goal, "" if world.timer in ['none', 'display'] else "-" + world.timer, world.shuffle, world.algorithm, "-keysanity" if world.keysanity else "", "-retro" if world.retro else "", "-prog_" + world.progressive if world.progressive in ['off', 'random'] else "", world.seed)

    if not args.suppress_rom:
        if args.jsonout:
            rom = JsonRom()
        else:
            rom = LocalRom(args.rom)
        patch_rom(world, rom, bytearray(logic_hash), args.heartbeep, args.heartcolor, sprite)
        if args.jsonout:
            print(json.dumps({'patch': rom.patches, 'spoiler': world.spoiler.to_json()}))
        else:
            rom.write_to_file(args.jsonout or output_path('%s.sfc' % outfilebase))

    if args.create_spoiler and not args.jsonout:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.clock() - start)

    return world
Exemple #9
0
def main(args, seed=None):
    start = time.clock()

    # initialize the world
    world = World(args.shuffle, args.bridge, args.open_forest, not args.nodungeonitems, args.beatableonly)
    logger = logging.getLogger('')
    if seed is None:
        random.seed(None)
        world.seed = random.randint(0, 999999999)
    else:
        world.seed = int(seed)
    random.seed(world.seed)

    logger.info('ALttP Entrance Randomizer Version %s  -  Seed: %s\n\n', __version__, world.seed)

    create_regions(world)

    create_dungeons(world)

    logger.info('Shuffling the World about.')

    link_entrances(world)

    logger.info('Calculating Access Rules.')

    set_rules(world)

    logger.info('Generating Item Pool.')

    generate_itempool(world)

    logger.info('Placing Dungeon Items.')

    shuffled_locations = None
    shuffled_locations = world.get_unfilled_locations()
    random.shuffle(shuffled_locations)
    fill_dungeons_restrictive(world, shuffled_locations)

    logger.info('Fill the world.')

    distribute_items_restrictive(world)

    logger.info('Calculating playthrough.')

    create_playthrough(world)

    logger.info('Patching ROM.')

    outfilebase = 'OoT_%s_%s_%s' % (world.shuffle, world.bridge, world.seed)

    if not args.suppress_rom:
        rom = LocalRom(args.rom)
        patch_rom(world, rom)
        rom.write_to_file(output_path('%s.z64' % outfilebase))

    if args.create_spoiler:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.clock() - start)

    return world
Exemple #10
0
def main(settings, window=dummy_window()):

    start = time.clock()

    logger = logging.getLogger('')

    # verify that the settings are valid
    if settings.free_scarecrow:
        verify_scarecrow_song_str(settings.scarecrow_song,
                                  settings.ocarina_songs)

    # initialize the world

    worlds = []
    if settings.compress_rom == 'None':
        settings.create_spoiler = True
        settings.update()

    if not settings.world_count:
        settings.world_count = 1
    if settings.world_count < 1:
        raise Exception('World Count must be at least 1')
    if settings.player_num > settings.world_count or settings.player_num < 1:
        raise Exception('Player Num must be between 1 and %d' %
                        settings.world_count)

    for i in range(0, settings.world_count):
        worlds.append(World(settings))

    random.seed(worlds[0].numeric_seed)

    logger.info('OoT Randomizer Version %s  -  Seed: %s\n\n', __version__,
                worlds[0].seed)

    window.update_status('Creating the Worlds')
    for id, world in enumerate(worlds):
        world.id = id
        logger.info('Generating World %d.' % id)

        window.update_progress(0 + (((id + 1) / settings.world_count) * 1))
        logger.info('Creating Overworld')
        if world.quest == 'master':
            for dungeon in world.dungeon_mq:
                world.dungeon_mq[dungeon] = True
        elif world.quest == 'mixed':
            for dungeon in world.dungeon_mq:
                world.dungeon_mq[dungeon] = random.choice([True, False])
        else:
            for dungeon in world.dungeon_mq:
                world.dungeon_mq[dungeon] = False
        create_regions(world)

        window.update_progress(0 + (((id + 1) / settings.world_count) * 2))
        logger.info('Creating Dungeons')
        create_dungeons(world)

        window.update_progress(0 + (((id + 1) / settings.world_count) * 3))
        logger.info('Linking Entrances')
        link_entrances(world)

        if settings.shopsanity != 'off':
            world.random_shop_prices()

        window.update_progress(0 + (((id + 1) / settings.world_count) * 4))
        logger.info('Calculating Access Rules.')
        set_rules(world)

        window.update_progress(0 + (((id + 1) / settings.world_count) * 5))
        logger.info('Generating Item Pool.')
        generate_itempool(world)

    window.update_status('Placing the Items')
    logger.info('Fill the world.')
    distribute_items_restrictive(window, worlds)
    window.update_progress(35)

    if settings.create_spoiler:
        window.update_status('Calculating Spoiler Data')
        logger.info('Calculating playthrough.')
        create_playthrough(worlds)
        window.update_progress(50)
    if settings.hints != 'none':
        window.update_status('Calculating Hint Data')
        CollectionState.update_required_items(worlds)
        buildGossipHints(worlds[settings.player_num - 1])
        window.update_progress(55)

    logger.info('Patching ROM.')

    if settings.world_count > 1:
        outfilebase = 'OoT_%s_%s_W%dP%d' % (
            worlds[0].settings_string, worlds[0].seed, worlds[0].world_count,
            worlds[0].player_num)
    else:
        outfilebase = 'OoT_%s_%s' % (worlds[0].settings_string, worlds[0].seed)

    output_dir = default_output_path(settings.output_dir)

    if settings.compress_rom != 'None':
        window.update_status('Patching ROM')
        rom = LocalRom(settings)
        patch_rom(worlds[settings.player_num - 1], rom)
        window.update_progress(65)

        rom_path = os.path.join(output_dir, '%s.z64' % outfilebase)

        window.update_status('Saving Uncompressed ROM')
        rom.write_to_file(rom_path)
        if settings.compress_rom == 'True':
            window.update_status('Compressing ROM')
            logger.info('Compressing ROM.')

            compressor_path = ""
            if platform.system() == 'Windows':
                if 8 * struct.calcsize("P") == 64:
                    compressor_path = "Compress\\Compress.exe"
                else:
                    compressor_path = "Compress\\Compress32.exe"
            elif platform.system() == 'Linux':
                compressor_path = "Compress/Compress"
            elif platform.system() == 'Darwin':
                compressor_path = "Compress/Compress.out"
            else:
                logger.info('OS not supported for compression')

            run_process(window, logger, [
                compressor_path, rom_path,
                os.path.join(output_dir, '%s-comp.z64' % outfilebase)
            ])
            os.remove(rom_path)
            window.update_progress(95)

    if settings.create_spoiler:
        window.update_status('Creating Spoiler Log')
        worlds[settings.player_num - 1].spoiler.to_file(
            os.path.join(output_dir, '%s_Spoiler.txt' % outfilebase))

    window.update_progress(100)
    window.update_status('Success: Rom patched successfully')
    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.clock() - start)

    return worlds[settings.player_num - 1]
Exemple #11
0
def main(args, seed=None):
    if args.outputpath:
        os.makedirs(args.outputpath, exist_ok=True)
        output_path.cached_path = args.outputpath

    start = time.process_time()

    # initialize the world
    world = World(args.multi, args.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('')
    if seed is None:
        random.seed(None)
        world.seed = random.randint(0, 999999999)
    else:
        world.seed = int(seed)
    random.seed(world.seed)

    world.remote_items = args.remote_items.copy()
    world.mapshuffle = args.mapshuffle.copy()
    world.compassshuffle = args.compassshuffle.copy()
    world.keyshuffle = args.keyshuffle.copy()
    world.bigkeyshuffle = args.bigkeyshuffle.copy()
    world.crystals_needed_for_ganon = {
        player: random.randint(0, 7) if args.crystals_ganon[player] == 'random'
        else int(args.crystals_ganon[player])
        for player in range(1, world.players + 1)
    }
    world.crystals_needed_for_gt = {
        player: random.randint(0, 7) if args.crystals_gt[player] == 'random'
        else int(args.crystals_gt[player])
        for player in range(1, world.players + 1)
    }
    world.open_pyramid = args.openpyramid.copy()
    world.boss_shuffle = args.shufflebosses.copy()
    world.enemy_shuffle = args.shuffleenemies.copy()
    world.enemy_health = args.enemy_health.copy()
    world.enemy_damage = args.enemy_damage.copy()
    world.beemizer = args.beemizer.copy()

    world.rom_seeds = {
        player: random.randint(0, 999999999)
        for player in range(1, world.players + 1)
    }

    logger.info('ALttP Entrance Randomizer Version %s  -  Seed: %s\n',
                __version__, world.seed)

    parsed_names = parse_player_names(args.names, world.players, args.teams)
    world.teams = len(parsed_names)
    for i, team in enumerate(parsed_names, 1):
        if world.players > 1:
            logger.info('%s%s',
                        'Team%d: ' % i if world.teams > 1 else 'Players: ',
                        ', '.join(team))
        for player, name in enumerate(team, 1):
            world.player_names[player].append(name)
    logger.info('')

    for player in range(1, world.players + 1):
        world.difficulty_requirements[player] = difficulties[
            world.difficulty[player]]

        if world.mode[player] == 'standard' and world.enemy_shuffle[
                player] != 'none':
            world.escape_assist[player].append(
                'bombs'
            )  # enemized escape assumes infinite bombs available and will likely be unbeatable without it

        for tok in filter(None, args.startinventory[player].split(',')):
            item = ItemFactory(tok.strip(), player)
            if item:
                world.push_precollected(item)

        if world.mode[player] != 'inverted':
            create_regions(world, player)
        else:
            create_inverted_regions(world, player)
        create_shops(world, player)
        create_dungeons(world, player)

    logger.info('Shuffling the World about.')

    for player in range(1, world.players + 1):
        if world.mode[player] != 'inverted':
            link_entrances(world, player)
            mark_light_world_regions(world, player)
        else:
            link_inverted_entrances(world, player)
            mark_dark_world_regions(world, player)

    logger.info('Generating Item Pool.')

    for player in range(1, world.players + 1):
        generate_itempool(world, player)

    logger.info('Calculating Access Rules.')

    for player in range(1, world.players + 1):
        set_rules(world, player)

    logger.info('Placing Dungeon Prizes.')

    fill_prizes(world)

    logger.info('Placing Dungeon Items.')

    shuffled_locations = None
    if args.algorithm in ['balanced', 'vt26'] or any(
            list(args.mapshuffle.values()) +
            list(args.compassshuffle.values()) +
            list(args.keyshuffle.values()) +
            list(args.bigkeyshuffle.values())):
        shuffled_locations = world.get_unfilled_locations()
        random.shuffle(shuffled_locations)
        fill_dungeons_restrictive(world, shuffled_locations)
    else:
        fill_dungeons(world)

    logger.info('Fill the world.')

    if args.algorithm == 'flood':
        flood_items(
            world)  # different algo, biased towards early game progress items
    elif args.algorithm == 'vt21':
        distribute_items_cutoff(world, 1)
    elif args.algorithm == 'vt22':
        distribute_items_cutoff(world, 0.66)
    elif args.algorithm == 'freshness':
        distribute_items_staleness(world)
    elif args.algorithm == 'vt25':
        distribute_items_restrictive(world, False)
    elif args.algorithm == 'vt26':

        distribute_items_restrictive(world, True, shuffled_locations)
    elif args.algorithm == 'balanced':
        distribute_items_restrictive(world, True)

    if world.players > 1:
        logger.info('Balancing multiworld progression.')
        balance_multiworld_progression(world)

    logger.info('Patching ROM.')

    outfilebase = 'ER_%s' % (args.outputname
                             if args.outputname else world.seed)

    rom_names = []
    jsonout = {}
    if not args.suppress_rom:
        for team in range(world.teams):
            for player in range(1, world.players + 1):
                sprite_random_on_hit = type(
                    args.sprite[player]) is str and args.sprite[player].lower(
                    ) == 'randomonhit'
                use_enemizer = (world.boss_shuffle[player] != 'none'
                                or world.enemy_shuffle[player] != 'none'
                                or world.enemy_health[player] != 'default'
                                or world.enemy_damage[player] != 'default'
                                or args.shufflepots[player]
                                or sprite_random_on_hit)

                rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(
                    args.rom)

                patch_rom(world, rom, player, team, use_enemizer)

                if use_enemizer and (args.enemizercli or not args.jsonout):
                    patch_enemizer(world, player, rom, args.rom,
                                   args.enemizercli, args.shufflepots[player],
                                   sprite_random_on_hit)
                    if not args.jsonout:
                        rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000)

                if args.race:
                    patch_race_rom(rom)

                rom_names.append((player, team, list(rom.name)))
                world.spoiler.hashes[(player,
                                      team)] = get_hash_string(rom.hash)

                apply_rom_settings(
                    rom, args.heartbeep[player], args.heartcolor[player],
                    args.quickswap[player], args.fastmenu[player],
                    args.disablemusic[player], args.sprite[player],
                    args.ow_palettes[player], args.uw_palettes[player])

                if args.jsonout:
                    jsonout[f'patch_t{team}_p{player}'] = rom.patches
                else:
                    mcsb_name = ''
                    if all([
                            world.mapshuffle[player],
                            world.compassshuffle[player],
                            world.keyshuffle[player],
                            world.bigkeyshuffle[player]
                    ]):
                        mcsb_name = '-keysanity'
                    elif [
                            world.mapshuffle[player],
                            world.compassshuffle[player],
                            world.keyshuffle[player],
                            world.bigkeyshuffle[player]
                    ].count(True) == 1:
                        mcsb_name = '-mapshuffle' if world.mapshuffle[
                            player] else '-compassshuffle' if world.compassshuffle[
                                player] else '-keyshuffle' if world.keyshuffle[
                                    player] else '-bigkeyshuffle'
                    elif any([
                            world.mapshuffle[player],
                            world.compassshuffle[player],
                            world.keyshuffle[player],
                            world.bigkeyshuffle[player]
                    ]):
                        mcsb_name = '-%s%s%s%sshuffle' % (
                            'M' if world.mapshuffle[player] else '',
                            'C' if world.compassshuffle[player] else '',
                            'S' if world.keyshuffle[player] else '',
                            'B' if world.bigkeyshuffle[player] else '')

                    outfilepname = f'_T{team+1}' if world.teams > 1 else ''
                    if world.players > 1:
                        outfilepname += f'_P{player}'
                    if world.players > 1 or world.teams > 1:
                        outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[
                            player][team] != 'Player %d' % player else ''
                    outfilesuffix = (
                        '_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' %
                        (world.logic[player], world.difficulty[player],
                         world.difficulty_adjustments[player],
                         world.mode[player], world.goal[player],
                         "" if world.timer in ['none', 'display'] else "-" +
                         world.timer, world.shuffle[player], world.algorithm,
                         mcsb_name, "-retro" if world.retro[player] else "",
                         "-prog_" + world.progressive
                         if world.progressive in ['off', 'random'] else "",
                         "-nohints" if not world.hints[player] else "")
                    ) if not args.outputname else ''
                    rom.write_to_file(
                        output_path(
                            f'{outfilebase}{outfilepname}{outfilesuffix}.sfc'))

        multidata = zlib.compress(
            json.dumps({
                "names":
                parsed_names,
                "roms":
                rom_names,
                "remote_items": [
                    player for player in range(1, world.players + 1)
                    if world.remote_items[player]
                ],
                "locations": [((location.address, location.player),
                               (location.item.code, location.item.player))
                              for location in world.get_filled_locations()
                              if type(location.address) is int]
            }).encode("utf-8"))
        if args.jsonout:
            jsonout["multidata"] = list(multidata)
        else:
            with open(output_path('%s_multidata' % outfilebase), 'wb') as f:
                f.write(multidata)

    if args.create_spoiler and not args.jsonout:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    if not args.skip_playthrough:
        logger.info('Calculating playthrough.')
        create_playthrough(world)

    if args.jsonout:
        print(json.dumps({**jsonout, 'spoiler': world.spoiler.to_json()}))
    elif args.create_spoiler and not args.skip_playthrough:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.process_time() - start)

    return world
def main(args, seed=None):
    start = time.perf_counter()

    # initialize the world
    world = World(args.multi, args.shuffle, args.logic, args.mode, args.swords,
                  args.difficulty, args.item_functionality, args.timer,
                  args.progressive, args.goal, args.algorithm,
                  not args.nodungeonitems, args.accessibility,
                  args.shuffleganon, args.quickswap, args.fastmenu,
                  args.disablemusic, args.keysanity, args.retro, args.custom,
                  args.customitemarray, args.shufflebosses, args.hints)
    logger = logging.getLogger('')
    if seed is None:
        random.seed(None)
        world.seed = random.randint(0, 999999999)
    else:
        world.seed = int(seed)
    random.seed(world.seed)

    world.crystals_needed_for_ganon = random.randint(
        0, 7) if args.crystals_ganon == 'random' else int(args.crystals_ganon)
    world.crystals_needed_for_gt = random.randint(
        0, 7) if args.crystals_gt == 'random' else int(args.crystals_gt)

    world.rom_seeds = {
        player: random.randint(0, 999999999)
        for player in range(1, world.players + 1)
    }

    logger.info('ALttP Entrance Randomizer Version %s  -  Seed: %s\n\n',
                __version__, world.seed)

    world.difficulty_requirements = difficulties[world.difficulty]

    if world.mode != 'inverted':
        for player in range(1, world.players + 1):
            create_regions(world, player)
            create_dungeons(world, player)
    else:
        for player in range(1, world.players + 1):
            create_inverted_regions(world, player)
            create_dungeons(world, player)

    logger.info('Shuffling the World about.')

    if world.mode != 'inverted':
        for player in range(1, world.players + 1):
            link_entrances(world, player)

        mark_light_world_regions(world)
    else:
        for player in range(1, world.players + 1):
            link_inverted_entrances(world, player)

        mark_dark_world_regions(world)

    logger.info('Generating Item Pool.')

    for player in range(1, world.players + 1):
        generate_itempool(world, player)

    logger.info('Calculating Access Rules.')

    for player in range(1, world.players + 1):
        set_rules(world, player)

    logger.info('Placing Dungeon Prizes.')

    fill_prizes(world)

    logger.info('Placing Dungeon Items.')

    shuffled_locations = None
    if args.algorithm in ['balanced', 'vt26'] or args.keysanity:
        shuffled_locations = world.get_unfilled_locations()
        random.shuffle(shuffled_locations)
        fill_dungeons_restrictive(world, shuffled_locations)
    else:
        fill_dungeons(world)

    logger.info('Fill the world.')

    if args.algorithm == 'flood':
        flood_items(
            world)  # different algo, biased towards early game progress items
    elif args.algorithm == 'vt21':
        distribute_items_cutoff(world, 1)
    elif args.algorithm == 'vt22':
        distribute_items_cutoff(world, 0.66)
    elif args.algorithm == 'freshness':
        distribute_items_staleness(world)
    elif args.algorithm == 'vt25':
        distribute_items_restrictive(world, 0)
    elif args.algorithm == 'vt26':

        distribute_items_restrictive(world, gt_filler(world),
                                     shuffled_locations)
    elif args.algorithm == 'balanced':
        distribute_items_restrictive(world, gt_filler(world))

    if world.players > 1:
        logger.info('Balancing multiworld progression.')
        balance_multiworld_progression(world)

    logger.info('Patching ROM.')

    if args.sprite is not None:
        if isinstance(args.sprite, Sprite):
            sprite = args.sprite
        else:
            sprite = Sprite(args.sprite)
    else:
        sprite = None

    outfilebase = 'ER_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s_%s' % (
        world.logic, world.difficulty, world.difficulty_adjustments,
        world.mode, world.goal, "" if world.timer in ['none', 'display'] else
        "-" + world.timer, world.shuffle, world.algorithm, "-keysanity"
        if world.keysanity else "", "-retro" if world.retro else "", "-prog_" +
        world.progressive if world.progressive in ['off', 'random'] else "",
        "-nohints" if not world.hints else "", world.seed)

    use_enemizer = args.enemizercli and (
        args.shufflebosses != 'none' or args.shuffleenemies
        or args.enemy_health != 'default' or args.enemy_health != 'default'
        or args.enemy_damage or args.shufflepalette or args.shufflepots)

    jsonout = {}
    if not args.suppress_rom:
        if world.players > 1:
            raise NotImplementedError(
                "Multiworld rom writes have not been implemented")
        else:
            player = 1

            local_rom = None
            if args.jsonout:
                rom = JsonRom()
            else:
                if use_enemizer:
                    local_rom = LocalRom(args.rom)
                    rom = JsonRom()
                else:
                    rom = LocalRom(args.rom)

            patch_rom(world, player, rom)

            enemizer_patch = []
            if use_enemizer:
                enemizer_patch = get_enemizer_patch(
                    world, player, rom, args.rom, args.enemizercli,
                    args.shuffleenemies, args.enemy_health, args.enemy_damage,
                    args.shufflepalette, args.shufflepots)

            if args.jsonout:
                jsonout['patch'] = rom.patches
                if use_enemizer:
                    jsonout['enemizer' % player] = enemizer_patch
            else:
                if use_enemizer:
                    local_rom.patch_enemizer(
                        rom.patches,
                        os.path.join(os.path.dirname(args.enemizercli),
                                     "enemizerBasePatch.json"), enemizer_patch)
                    rom = local_rom

                apply_rom_settings(rom, args.heartbeep, args.heartcolor,
                                   world.quickswap, world.fastmenu,
                                   world.disable_music, sprite)
                rom.write_to_file(output_path('%s.sfc' % outfilebase))

    if args.create_spoiler and not args.jsonout:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    if not args.skip_playthrough:
        logger.info('Calculating playthrough.')
        create_playthrough(world)

    if args.jsonout:
        print(json.dumps({**jsonout, 'spoiler': world.spoiler.to_json()}))
    elif args.create_spoiler and not args.skip_playthrough:
        world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))

    logger.info('Done. Enjoy.')
    logger.debug('Total Time: %s', time.perf_counter() - start)

    return world