Ejemplo n.º 1
0
def create_regions(world: MultiWorld, player: int):
    regOvr = Region("Menu", RegionType.Generic, "Dimension VVVVVV", player, world)
    locOvr_names = ["Overworld (Pipe-shaped Segment)", "Overworld (Left of Ship)", "Overworld (Square Room)", "Overworld (Sad Elephant)",
                    "It's a Secret to Nobody", "Trench Warfare", "NPC Trinket", "V"]
    regOvr.locations += [V6Location(player, loc_name, location_table[loc_name], regOvr) for loc_name in locOvr_names]
    world.regions.append(regOvr)

    regLab = Region("Laboratory", RegionType.Generic, "Laboratory", player, world)
    locLab_names = ["Young Man, It's Worth the Challenge", "Overworld (Outside Entanglement Generator)", "The Tantalizing Trinket", "Purest Unobtainium"]
    regLab.locations += [V6Location(player, loc_name, location_table[loc_name], regLab) for loc_name in locLab_names]
    world.regions.append(regLab)

    regTow = Region("The Tower", RegionType.Generic, "The Tower", player, world)
    locTow_names = ["The Tower 1", "The Tower 2"]
    regTow.locations += [V6Location(player, loc_name, location_table[loc_name], regTow) for loc_name in locTow_names]
    world.regions.append(regTow)

    regSp2 = Region("Space Station 2", RegionType.Generic, "Space Station 2", player, world)
    locSp2_names = ["One Way Room", "You Just Keep Coming Back", "Clarion Call", "Prize for the Reckless", "Doing things the hard way"]
    regSp2.locations += [V6Location(player, loc_name, location_table[loc_name], regSp2) for loc_name in locSp2_names]
    world.regions.append(regSp2)

    regWrp = Region("Warp Zone", RegionType.Generic, "Warp Zone", player, world)
    locWrp_names = ["Edge Games"]
    regWrp.locations += [V6Location(player, loc_name, location_table[loc_name], regWrp) for loc_name in locWrp_names]
    world.regions.append(regWrp)
Ejemplo n.º 2
0
def create_region(world: MultiWorld,
                  player: int,
                  name: str,
                  locat: WitnessPlayerLocations,
                  region_locations=None,
                  exits=None):
    """
    Create an Archipelago Region for The Witness
    """

    ret = Region(name, RegionType.Generic, name, player)
    ret.world = world
    if region_locations:
        for location in region_locations:
            loc_id = locat.CHECK_LOCATION_TABLE[location]

            check_hex = -1
            if location in StaticWitnessLogic.CHECKS_BY_NAME:
                check_hex = int(
                    StaticWitnessLogic.CHECKS_BY_NAME[location]["checkHex"], 0)
            location = WitnessLocation(player, location, loc_id, ret,
                                       check_hex)

            ret.locations.append(location)
    if exits:
        for single_exit in exits:
            ret.exits.append(Entrance(player, single_exit, ret))

    return ret
Ejemplo n.º 3
0
def copy_dynamic_regions_and_locations(world, ret):
    for region in world.dynamic_regions:
        new_reg = Region(region.name, region.type, region.hint_text,
                         region.player)
        ret.regions.append(new_reg)
        ret.initialize_regions([new_reg])
        ret.dynamic_regions.append(new_reg)

        # Note: ideally exits should be copied here, but the current use case (Take anys) do not require this

        if region.shop:
            new_reg.shop = Shop(new_reg, region.shop.room_id, region.shop.type,
                                region.shop.shopkeeper_config,
                                region.shop.custom, region.shop.locked)
            ret.shops.append(new_reg.shop)

    for location in world.dynamic_locations:
        new_reg = ret.get_region(location.parent_region.name,
                                 location.parent_region.player)
        new_loc = Location(location.player, location.name, location.address,
                           location.crystal, location.hint_text, new_reg)
        # todo: this is potentially dangerous. later refactor so we
        # can apply dynamic region rules on top of copied world like other rules
        new_loc.access_rule = location.access_rule
        new_loc.always_allow = location.always_allow
        new_loc.item_rule = location.item_rule
        new_reg.locations.append(new_loc)

        ret.clear_location_cache()
Ejemplo n.º 4
0
    def create_regions(self):
        player = self.player
        menu = Region("Menu", RegionType.Generic, "Menu", player, self.world)
        crash = Entrance(player, "Crash Land", menu)
        menu.exits.append(crash)
        nauvis = Region("Nauvis", RegionType.Generic, "Nauvis", player,
                        self.world)

        skip_silo = self.world.silo[self.player].value == Silo.option_spawn
        for tech_name, tech_id in base_tech_table.items():
            if skip_silo and tech_name == "rocket-silo":
                continue
            tech = Location(player, tech_name, tech_id, nauvis)
            nauvis.locations.append(tech)
            tech.game = "Factorio"
        location = Location(player, "Rocket Launch", None, nauvis)
        nauvis.locations.append(location)
        location.game = "Factorio"
        event = FactorioItem("Victory", ItemClassification.progression, None,
                             player)
        event.game = "Factorio"
        self.world.push_item(location, event, False)
        location.event = location.locked = True
        for ingredient in self.world.max_science_pack[
                self.player].get_allowed_packs():
            location = Location(player, f"Automate {ingredient}", None, nauvis)
            location.game = "Factorio"
            nauvis.locations.append(location)
            event = FactorioItem(f"Automated {ingredient}",
                                 ItemClassification.progression, None, player)
            self.world.push_item(location, event, False)
            location.event = location.locked = True
        crash.connect(nauvis)
        self.world.regions += [menu, nauvis]
Ejemplo n.º 5
0
 def ChecksFinderRegion(region_name: str, exits=[]):
     ret = Region(region_name, RegionType.Generic, region_name, self.player, self.world)
     ret.locations = [ChecksFinderAdvancement(self.player, loc_name, loc_data.id, ret)
         for loc_name, loc_data in advancement_table.items()
         if loc_data.region == region_name]
     for exit in exits:
         ret.exits.append(Entrance(self.player, exit, ret))
     return ret
Ejemplo n.º 6
0
 def MCRegion(region_name: str, exits=[]):
     ret = Region(region_name, None, region_name, self.player,
                  self.world)
     ret.locations = [
         MinecraftAdvancement(self.player, loc_name, loc_data.id, ret)
         for loc_name, loc_data in advancement_table.items()
         if loc_data.region == region_name
     ]
     for exit in exits:
         ret.exits.append(Entrance(self.player, exit, ret))
     return ret
Ejemplo n.º 7
0
def factorio_create_regions(world: MultiWorld, player: int):
    menu = Region("Menu", None, "Menu", player)
    crash = Entrance(player, "Crash Land", menu)
    menu.exits.append(crash)
    nauvis = Region("Nauvis", None, "Nauvis", player)
    nauvis.world = menu.world = world
    for tech_name, tech_id in tech_table.items():
        tech = Location(player, tech_name, tech_id, nauvis)
        nauvis.locations.append(tech)
        tech.game = "Factorio"
    crash.connect(nauvis)
    world.regions += [menu, nauvis]
Ejemplo n.º 8
0
def create_region(world: MultiWorld, player: int, name: str, location_names=None, exits=None) -> Region:
    ret = Region(name, RegionType.Generic, name, player)
    ret.world = world
    if location_names:
        for location in location_names:
            loc_id = HKWorld.location_name_to_id.get(location, None)
            location = HKLocation(player, location, loc_id, ret)
            ret.locations.append(location)
    if exits:
        for exit in exits:
            ret.exits.append(Entrance(player, exit, ret))
    return ret
Ejemplo n.º 9
0
 def create_region(self, world: MultiWorld, player: int, name: str, locations=None, exits=None):
     ret = Region(name, RegionType.LightWorld, name, player)
     ret.world = world
     if locations:
         for loc in locations:
             location = self.locations[loc]
             location.parent_region = ret
             ret.locations.append(location)
     if exits:
         for exit in exits:
             ret.exits.append(Entrance(player, exit, ret))
     return ret
Ejemplo n.º 10
0
def create_region(world: MultiWorld, player: int,
                  locations_per_region: Dict[str, List[LocationData]],
                  location_cache: List[Location], name: str) -> Region:
    region = Region(name, RegionType.Generic, name, player)
    region.world = world

    if name in locations_per_region:
        for location_data in locations_per_region[name]:
            location = create_location(player, location_data, region,
                                       location_cache)
            region.locations.append(location)

    return region
Ejemplo n.º 11
0
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
    ret = Region(name, None, name, player)
    ret.world = world
    if locations:
        for location in locations:
            loc_id = lookup_name_to_id.get(location, 0)
            location = HKLocation(player, location, loc_id, ret)
            ret.locations.append(location)
    if exits:
        for exit in exits:
            ret.exits.append(Entrance(player, exit, ret))

    return ret
Ejemplo n.º 12
0
def copy_dynamic_regions_and_locations(world, ret):
    for region in world.dynamic_regions:
        new_reg = Region(region.name, region.type)
        ret.regions.append(new_reg)
        ret.dynamic_regions.append(new_reg)

        # Note: ideally exits should be copied here, but the current use case (Take anys) do not require this

        if region.shop:
            new_reg.shop = Shop(new_reg, region.shop.room_id, region.shop.type, region.shop.shopkeeper_config, region.shop.replaceable)
            ret.shops.append(new_reg.shop)

    for location in world.dynamic_locations:
        new_loc = Location(location.name, location.address, location.crystal, location.hint_text, location.parent_region)
        new_reg = ret.get_region(location.parent_region.name)
        new_reg.locations.append(new_loc)
Ejemplo n.º 13
0
def create_region(world: MultiWorld,
                  player: int,
                  name: str,
                  locations=None,
                  exits=None):
    ret = Region(name, RegionType.Generic, name, player)
    ret.world = world
    if locations:
        for location in locations:
            loc_id = location_table.get(location, 0)
            location = SpireLocation(player, location, loc_id, ret)
            ret.locations.append(location)
    if exits:
        for exit in exits:
            ret.exits.append(Entrance(player, exit, ret))

    return ret
Ejemplo n.º 14
0
def create_region(world: MultiWorld,
                  player: int,
                  name: str,
                  locations=None,
                  exits=None):
    # Shamelessly stolen from the ROR2 definition, lol
    ret = Region(name, RegionType.Generic, name, player)
    ret.world = world
    if locations:
        for location in locations:
            loc_id = location_table.get(location, 0)
            location = LegacyLocation(player, location, loc_id, ret)
            ret.locations.append(location)
    if exits:
        for exit in exits:
            ret.exits.append(Entrance(player, exit, ret))

    return ret
Ejemplo n.º 15
0
def create_region(world: MultiWorld,
                  player: int,
                  name: str,
                  locations=None,
                  exits=None):
    ret = Region(name, RegionType.Generic, name, player)
    ret.world = world
    if locations:
        for location in locations:
            loc_id = locations_lookup_name_to_id.get(location, 0)
            locationObj = RaftLocation(player, location, loc_id, ret)
            ret.locations.append(locationObj)
    if exits:
        for exit in exits:
            ret.exits.append(
                Entrance(player, getConnectionName(name, exit), ret))

    return ret
Ejemplo n.º 16
0
def create_region(world: MultiWorld,
                  player: int,
                  name: str,
                  locations=None,
                  exits=None):
    region = Region(name, RegionType.Generic, name, player)
    region.world = world
    if locations:
        for location_name in locations.keys():
            location = ArchipIDLELocation(player, location_name,
                                          locations[location_name], region)
            region.locations.append(location)

    if exits:
        for _exit in exits:
            region.exits.append(Entrance(player, _exit, region))

    return region
Ejemplo n.º 17
0
def create_region(world: MultiWorld,
                  player: int,
                  active_locations,
                  name: str,
                  locations=None,
                  exits=None):
    # Shamelessly stolen from the ROR2 definition
    ret = Region(name, None, name, player)
    ret.world = world
    if locations:
        for location in locations:
            loc_id = active_locations.get(location, 0)
            if loc_id:
                location = SA2BLocation(player, location, loc_id, ret)
                ret.locations.append(location)
    if exits:
        for exit in exits:
            ret.exits.append(Entrance(player, exit, ret))

    return ret
Ejemplo n.º 18
0
def _create_region(name, type, locations=None, exits=None):
    ret = Region(name, type)
    if locations is None:
        locations = []
    if exits is None:
        exits = []

    for exit in exits:
        ret.exits.append(Entrance(exit, ret))
    for location in locations:
        address, address2, default, type = location_table[location]
        ret.locations.append(Location(location, address, address2, default, type, ret))
    return ret
Ejemplo n.º 19
0
def create_region(name, locations=None, exits=None):
    ret = Region(name)
    if locations is None:
        locations = []
    if exits is None:
        exits = []

    for exit in exits:
        ret.exits.append(Entrance(exit, ret))
    for location in locations:
        address, crystal, hint_text = location_table[location]
        ret.locations.append(
            Location(location, address, crystal, hint_text, ret))
    return ret
Ejemplo n.º 20
0
def create_region(name, locations=None, exits=None):
    ret = Region(name)
    if locations is None:
        locations = []
    if exits is None:
        exits = []
    ret.add_exits(*exits)
    ret.add_locations(*locations)
    return ret
Ejemplo n.º 21
0
def set_up_take_anys(world, player):
    # these are references, do not modify these lists in-place
    if world.mode[player] == 'inverted':
        take_any_locs = take_any_locations_inverted
    else:
        take_any_locs = take_any_locations

    regions = world.random.sample(take_any_locs, 5)

    old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave,
                              'the sword cave', player)
    world.regions.append(old_man_take_any)
    world.dynamic_regions.append(old_man_take_any)

    reg = regions.pop()
    entrance = world.get_region(reg, player).entrances[0]
    connect_entrance(world, entrance.name, old_man_take_any.name, player)
    entrance.target = 0x58
    old_man_take_any.shop = TakeAny(old_man_take_any, 0x0112, 0xE2, True, True,
                                    total_shop_slots)
    world.shops.append(old_man_take_any.shop)

    swords = [
        item for item in world.itempool
        if item.type == 'Sword' and item.player == player
    ]
    if swords:
        sword = world.random.choice(swords)
        world.itempool.remove(sword)
        world.itempool.append(ItemFactory('Rupees (20)', player))
        old_man_take_any.shop.add_inventory(0,
                                            sword.name,
                                            0,
                                            0,
                                            create_location=True)
    else:
        old_man_take_any.shop.add_inventory(0, 'Rupees (300)', 0, 0)

    for num in range(4):
        take_any = Region("Take-Any #{}".format(num + 1), RegionType.Cave,
                          'a cave of choice', player)
        world.regions.append(take_any)
        world.dynamic_regions.append(take_any)

        target, room_id = world.random.choice([(0x58, 0x0112), (0x60, 0x010F),
                                               (0x46, 0x011F)])
        reg = regions.pop()
        entrance = world.get_region(reg, player).entrances[0]
        connect_entrance(world, entrance.name, take_any.name, player)
        entrance.target = target
        take_any.shop = TakeAny(take_any, room_id, 0xE3, True, True,
                                total_shop_slots + num + 1)
        world.shops.append(take_any.shop)
        take_any.shop.add_inventory(0, 'Blue Potion', 0, 0)
        take_any.shop.add_inventory(1, 'Boss Heart Container', 0, 0)

    world.initialize_regions()
Ejemplo n.º 22
0
def set_up_take_anys(world, player):
    if world.mode == 'inverted' and 'Dark Sanctuary Hint' in take_any_locations:
        take_any_locations.remove('Dark Sanctuary Hint')

    regions = random.sample(take_any_locations, 5)

    old_man_take_any = Region("Old Man Sword Cave", RegionType.Cave,
                              'the sword cave', player)
    world.regions.append(old_man_take_any)
    world.dynamic_regions.append(old_man_take_any)

    reg = regions.pop()
    entrance = world.get_region(reg, player).entrances[0]
    connect_entrance(world, entrance, old_man_take_any, player)
    entrance.target = 0x58
    old_man_take_any.shop = Shop(old_man_take_any, 0x0112, ShopType.TakeAny,
                                 0xE2, True)
    world.shops.append(old_man_take_any.shop)
    old_man_take_any.shop.active = True

    swords = [
        item for item in world.itempool
        if item.type == 'Sword' and item.player == player
    ]
    if swords:
        sword = random.choice(swords)
        world.itempool.remove(sword)
        world.itempool.append(ItemFactory('Rupees (20)', player))
        old_man_take_any.shop.add_inventory(0,
                                            sword.name,
                                            0,
                                            0,
                                            create_location=True)
    else:
        old_man_take_any.shop.add_inventory(0, 'Rupees (300)', 0, 0)

    for num in range(4):
        take_any = Region("Take-Any #{}".format(num + 1), RegionType.Cave,
                          'a cave of choice', player)
        world.regions.append(take_any)
        world.dynamic_regions.append(take_any)

        target, room_id = random.choice([(0x58, 0x0112), (0x60, 0x010F),
                                         (0x46, 0x011F)])
        reg = regions.pop()
        entrance = world.get_region(reg, player).entrances[0]
        connect_entrance(world, entrance, take_any, player)
        entrance.target = target
        take_any.shop = Shop(take_any, room_id, ShopType.TakeAny, 0xE3, True)
        world.shops.append(take_any.shop)
        take_any.shop.active = True
        take_any.shop.add_inventory(0, 'Blue Potion', 0, 0)
        take_any.shop.add_inventory(1, 'Boss Heart Container', 0, 0)

    world.intialize_regions()
Ejemplo n.º 23
0
def generate_multi_world(players: int = 1) -> MultiWorld:
    multi_world = MultiWorld(players)
    multi_world.player_name = {}
    for i in range(players):
        player_id = i + 1
        world = World(multi_world, player_id)
        multi_world.game[player_id] = world
        multi_world.worlds[player_id] = world
        multi_world.player_name[player_id] = "Test Player " + str(player_id)
        region = Region("Menu", RegionType.Generic, "Menu Region Hint",
                        player_id, multi_world)
        multi_world.regions.append(region)

    multi_world.set_seed(0)
    multi_world.set_default_common_options()

    return multi_world
Ejemplo n.º 24
0
    def create_regions(self):
        # TODO: generate *some* regions from locations' requirements?
        r = Region('Menu', RegionType.Generic, 'Menu', self.player, self.world)
        r.exits = [Entrance(self.player, 'New Game', r)]
        self.world.regions += [r]

        r = Region('Ingame', RegionType.Generic, 'Ingame', self.player, self.world)
        r.locations = [SoELocation(self.player, loc.name, self.location_name_to_id[loc.name], r)
                       for loc in _locations]
        r.locations.append(SoELocation(self.player, 'Done', None, r))
        self.world.regions += [r]

        self.world.get_entrance('New Game', self.player).connect(self.world.get_region('Ingame', self.player))
Ejemplo n.º 25
0
    def create_menu_region(player: int, locations: Dict[str, int],
                           rules: Dict[str, List[List[str]]]) -> Region:
        menu_region = Region("Menu", RegionType.Generic, "Menu", player)
        for name, address in locations.items():
            location = Location(player, name, address, menu_region)
            ## TODO REMOVE WHEN LOGIC FOR TOFR IS CORRECT
            if "ToFR" in name:
                rules_list = [[
                    "Rod", "Cube", "Lute", "Key", "Chime", "Oxyale", "Ship",
                    "Canoe", "Floater", "Canal", "Crown", "Crystal", "Herb",
                    "Tnt", "Adamant", "Slab", "Ruby", "Bottle"
                ]]
                location.access_rule = generate_rule(rules_list, player)
            elif name in rules:
                rules_list = rules[name]
                location.access_rule = generate_rule(rules_list, player)
            menu_region.locations.append(location)

        return menu_region
Ejemplo n.º 26
0
    def generate_region(
            self,
            parent: Region,
            size: int,
            access_rule: CollectionRule = lambda state: True) -> Region:
        region_tag = "_region" + str(len(self.regions))
        region_name = "player" + str(self.id) + region_tag
        region = Region("player" + str(self.id) + region_tag,
                        RegionType.Generic, "Region Hint", self.id, self.world)
        self.locations += generate_locations(size, self.id, None, region,
                                             region_tag)

        entrance = Entrance(self.id, region_name + "_entrance", parent)
        parent.exits.append(entrance)
        entrance.connect(region)
        entrance.access_rule = access_rule

        self.regions.append(region)
        self.world.regions.append(region)

        return region
Ejemplo n.º 27
0
def create_regions(world: MultiWorld, player: int):
    regSS = Region("Menu", RegionType.Generic, "Castle Area", player, world)
    locSS_names = [name for name, id in locSS_table.items()]
    locSS_names += [name for name, id in locCap_table.items()]
    regSS.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regSS)
        for loc_name in locSS_names
    ]
    world.regions.append(regSS)

    regBoB = Region("Bob-omb Battlefield", RegionType.Generic,
                    "Bob-omb Battlefield", player, world)
    locBoB_names = [name for name, id in locBoB_table.items()]
    regBoB.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regBoB)
        for loc_name in locBoB_names
    ]
    if (world.EnableCoinStars[player].value):
        regBoB.locations.append(
            SM64Location(player, "BoB: 100 Coins",
                         location_table["BoB: 100 Coins"], regBoB))
    world.regions.append(regBoB)

    regWhomp = Region("Whomp's Fortress", RegionType.Generic,
                      "Whomp's Fortress", player, world)
    locWhomp_names = [name for name, id in locWhomp_table.items()]
    regWhomp.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regWhomp)
        for loc_name in locWhomp_names
    ]
    if (world.EnableCoinStars[player].value):
        regWhomp.locations.append(
            SM64Location(player, "WF: 100 Coins",
                         location_table["WF: 100 Coins"], regWhomp))
    world.regions.append(regWhomp)

    regJRB = Region("Jolly Roger Bay", RegionType.Generic, "Jolly Roger Bay",
                    player, world)
    locJRB_names = [name for name, id in locJRB_table.items()]
    regJRB.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regJRB)
        for loc_name in locJRB_names
    ]
    if (world.EnableCoinStars[player].value):
        regJRB.locations.append(
            SM64Location(player, "JRB: 100 Coins",
                         location_table["JRB: 100 Coins"], regJRB))
    world.regions.append(regJRB)

    regCCM = Region("Cool, Cool Mountain", RegionType.Generic,
                    "Cool, Cool Mountain", player, world)
    locCCM_names = [name for name, id in locCCM_table.items()]
    regCCM.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regCCM)
        for loc_name in locCCM_names
    ]
    if (world.EnableCoinStars[player].value):
        regCCM.locations.append(
            SM64Location(player, "CCM: 100 Coins",
                         location_table["CCM: 100 Coins"], regCCM))
    world.regions.append(regCCM)

    regBBH = Region("Big Boo's Haunt", RegionType.Generic, "Big Boo's Haunt",
                    player, world)
    locBBH_names = [name for name, id in locBBH_table.items()]
    regBBH.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regBBH)
        for loc_name in locBBH_names
    ]
    if (world.EnableCoinStars[player].value):
        regBBH.locations.append(
            SM64Location(player, "BBH: 100 Coins",
                         location_table["BBH: 100 Coins"], regBBH))
    world.regions.append(regBBH)

    regBitDW = Region("Bowser in the Dark World", RegionType.Generic,
                      "Bowser in the Dark World", player, world)
    locBitDW_names = [name for name, id in locBitDW_table.items()]
    regBitDW.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regBitDW)
        for loc_name in locBitDW_names
    ]
    world.regions.append(regBitDW)

    regBasement = Region("Basement", RegionType.Generic, "Basement", player,
                         world)
    world.regions.append(regBasement)

    regHMC = Region("Hazy Maze Cave", RegionType.Generic, "Hazy Maze Cave",
                    player, world)
    locHMC_names = [name for name, id in locHMC_table.items()]
    regHMC.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regHMC)
        for loc_name in locHMC_names
    ]
    if (world.EnableCoinStars[player].value):
        regHMC.locations.append(
            SM64Location(player, "HMC: 100 Coins",
                         location_table["HMC: 100 Coins"], regHMC))
    world.regions.append(regHMC)

    regLLL = Region("Lethal Lava Land", RegionType.Generic, "Lethal Lava Land",
                    player, world)
    locLLL_names = [name for name, id in locLLL_table.items()]
    regLLL.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regLLL)
        for loc_name in locLLL_names
    ]
    if (world.EnableCoinStars[player].value):
        regLLL.locations.append(
            SM64Location(player, "LLL: 100 Coins",
                         location_table["LLL: 100 Coins"], regLLL))
    world.regions.append(regLLL)

    regSSL = Region("Shifting Sand Land", RegionType.Generic,
                    "Shifting Sand Land", player, world)
    locSSL_names = [name for name, id in locSSL_table.items()]
    regSSL.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regSSL)
        for loc_name in locSSL_names
    ]
    if (world.EnableCoinStars[player].value):
        regSSL.locations.append(
            SM64Location(player, "SSL: 100 Coins",
                         location_table["SSL: 100 Coins"], regSSL))
    world.regions.append(regSSL)

    regDDD = Region("Dire, Dire Docks", RegionType.Generic, "Dire, Dire Docks",
                    player, world)
    locDDD_names = [name for name, id in locDDD_table.items()]
    regDDD.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regDDD)
        for loc_name in locDDD_names
    ]
    if (world.EnableCoinStars[player].value):
        regDDD.locations.append(
            SM64Location(player, "DDD: 100 Coins",
                         location_table["DDD: 100 Coins"], regDDD))
    world.regions.append(regDDD)

    regBitFS = Region("Bowser in the Fire Sea", RegionType.Generic,
                      "Bowser in the Fire Sea", player, world)
    locBitFS_names = [name for name, id in locBitFS_table.items()]
    regBitFS.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regBitFS)
        for loc_name in locBitFS_names
    ]
    world.regions.append(regBitFS)

    regFloor2 = Region("Second Floor", RegionType.Generic, "Second Floor",
                       player, world)
    world.regions.append(regFloor2)

    regSL = Region("Snowman's Land", RegionType.Generic, "Snowman's Land",
                   player, world)
    locSL_names = [name for name, id in locSL_table.items()]
    regSL.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regSL)
        for loc_name in locSL_names
    ]
    if (world.EnableCoinStars[player].value):
        regSL.locations.append(
            SM64Location(player, "SL: 100 Coins",
                         location_table["SL: 100 Coins"], regSL))
    world.regions.append(regSL)

    regWDW = Region("Wet-Dry World", RegionType.Generic, "Wet-Dry World",
                    player, world)
    locWDW_names = [name for name, id in locWDW_table.items()]
    regWDW.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regWDW)
        for loc_name in locWDW_names
    ]
    if (world.EnableCoinStars[player].value):
        regWDW.locations.append(
            SM64Location(player, "WDW: 100 Coins",
                         location_table["WDW: 100 Coins"], regWDW))
    world.regions.append(regWDW)

    regTTM = Region("Tall, Tall Mountain", RegionType.Generic,
                    "Tall, Tall Mountain", player, world)
    locTTM_names = [name for name, id in locTTM_table.items()]
    regTTM.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regTTM)
        for loc_name in locTTM_names
    ]
    if (world.EnableCoinStars[player].value):
        regTTM.locations.append(
            SM64Location(player, "TTM: 100 Coins",
                         location_table["TTM: 100 Coins"], regTTM))
    world.regions.append(regTTM)

    regTHI = Region("Tiny-Huge Island", RegionType.Generic, "Tiny-Huge Island",
                    player, world)
    locTHI_names = [name for name, id in locTHI_table.items()]
    regTHI.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regTHI)
        for loc_name in locTHI_names
    ]
    if (world.EnableCoinStars[player].value):
        regTHI.locations.append(
            SM64Location(player, "THI: 100 Coins",
                         location_table["THI: 100 Coins"], regTHI))
    world.regions.append(regTHI)

    regFloor3 = Region("Third Floor", RegionType.Generic, "Third Floor",
                       player, world)
    world.regions.append(regFloor3)

    regTTC = Region("Tick Tock Clock", RegionType.Generic, "Tick Tock Clock",
                    player, world)
    locTTC_names = [name for name, id in locTTC_table.items()]
    regTTC.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regTTC)
        for loc_name in locTTC_names
    ]
    if (world.EnableCoinStars[player].value):
        regTTC.locations.append(
            SM64Location(player, "TTC: 100 Coins",
                         location_table["TTC: 100 Coins"], regTTC))
    world.regions.append(regTTC)

    regRR = Region("Rainbow Ride", RegionType.Generic, "Rainbow Ride", player,
                   world)
    locRR_names = [name for name, id in locRR_table.items()]
    regRR.locations += [
        SM64Location(player, loc_name, location_table[loc_name], regRR)
        for loc_name in locRR_names
    ]
    if (world.EnableCoinStars[player].value):
        regRR.locations.append(
            SM64Location(player, "RR: 100 Coins",
                         location_table["RR: 100 Coins"], regRR))
    world.regions.append(regRR)
Ejemplo n.º 28
0
 def create_region(self, name: str):
     return Region(name, RegionType.Generic, name, self.player, self.world)
Ejemplo n.º 29
0
def create_regions(world: MultiWorld, player: int):
    regions = ["First", "Second", "Third", "Last"]
    bosses = ["Meridian", "Ataraxia", "Merodach"]

    for x, name in enumerate(regions):
        fullname = f"{name} Quarter"
        insidename = fullname
        if x == 0:
            insidename = "Menu"

        region = Region(insidename, RegionType.Generic, fullname, player,
                        world)
        for store in [
                "Alpha Cache", "Beta Cache", "Gamma Cache", "Reward Chest"
        ]:
            for y in range(1, 7):
                loc_name = f"{store} {(x * 6) + y}"
                region.locations += [
                    MeritousLocation(player, loc_name,
                                     location_table[loc_name], region)
                ]

        if x < 3:
            storage_loc = f"PSI Key Storage {x + 1}"
            region.locations += [
                MeritousLocation(player, storage_loc,
                                 location_table[storage_loc], region)
            ]
            region.exits += _generate_entrances(player, [f"To {bosses[x]}"],
                                                region)
        else:
            locations_end_game = [
                "Place of Power", "The Last Place You'll Look"
            ]
            region.locations += [
                MeritousLocation(player, loc_name, location_table[loc_name],
                                 region) for loc_name in locations_end_game
            ]
            region.exits += _generate_entrances(player, [
                "Back to the entrance", "Back to the entrance with the Knife"
            ], region)

        world.regions += [region]

    for x, boss in enumerate(bosses):
        boss_region = Region(boss, RegionType.Generic, boss, player, world)
        boss_region.locations += [
            MeritousLocation(player, boss, location_table[boss], boss_region),
            MeritousLocation(player, f"{boss} Defeat", None, boss_region)
        ]
        boss_region.exits = _generate_entrances(
            player, [f"To {regions[x + 1]} Quarter"], boss_region)
        world.regions.append(boss_region)

    region_final_boss = Region("Final Boss", RegionType.Generic, "Final Boss",
                               player, world)
    region_final_boss.locations = [
        MeritousLocation(player, "Wervyn Anixil", None, region_final_boss)
    ]
    world.regions.append(region_final_boss)

    region_tfb = Region("True Final Boss", RegionType.Generic,
                        "True Final Boss", player, world)
    region_tfb.locations = [
        MeritousLocation(player, "Wervyn Anixil?", None, region_tfb)
    ]
    world.regions.append(region_tfb)

    entrance_map = {
        "To Meridian": {
            "to":
            "Meridian",
            "rule":
            lambda state: state.has_group("PSI Keys", player, 1) and state.
            has_group("Important Artifacts", player, 1)
        },
        "To Second Quarter": {
            "to": "Second Quarter",
            "rule": lambda state: state.has("Meridian Defeated", player)
        },
        "To Ataraxia": {
            "to":
            "Ataraxia",
            "rule":
            lambda state: state.has_group("PSI Keys", player, 2) and state.
            has_group("Important Artifacts", player, 2)
        },
        "To Third Quarter": {
            "to": "Third Quarter",
            "rule": lambda state: state.has("Ataraxia Defeated", player)
        },
        "To Merodach": {
            "to":
            "Merodach",
            "rule":
            lambda state: state.has_group("PSI Keys", player, 3) and state.
            has_group("Important Artifacts", player, 3)
        },
        "To Last Quarter": {
            "to": "Last Quarter",
            "rule": lambda state: state.has("Merodach Defeated", player)
        },
        "Back to the entrance": {
            "to": "Final Boss",
            "rule": lambda state: state.has("Cursed Seal", player)
        },
        "Back to the entrance with the Knife": {
            "to":
            "True Final Boss",
            "rule":
            lambda state: state.has_all(["Cursed Seal", "Agate Knife"], player)
        }
    }

    for entrance in entrance_map:
        connection_data = entrance_map[entrance]
        connection = world.get_entrance(entrance, player)
        connection.access_rule = connection_data["rule"]
        connection.connect(world.get_region(connection_data["to"], player))
Ejemplo n.º 30
0
def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = None):
    if not baked_server_options:
        baked_server_options = get_options()["server_options"]
    if args.outputpath:
        os.makedirs(args.outputpath, exist_ok=True)
        output_path.cached_path = args.outputpath

    start = time.perf_counter()
    # initialize the world
    world = MultiWorld(args.multi)

    logger = logging.getLogger()
    world.set_seed(seed, args.race, str(args.outputname if args.outputname else world.seed))

    world.shuffle = args.shuffle.copy()
    world.logic = args.logic.copy()
    world.mode = args.mode.copy()
    world.difficulty = args.difficulty.copy()
    world.item_functionality = args.item_functionality.copy()
    world.timer = args.timer.copy()
    world.goal = args.goal.copy()
    world.open_pyramid = args.open_pyramid.copy()
    world.boss_shuffle = args.shufflebosses.copy()
    world.enemy_health = args.enemy_health.copy()
    world.enemy_damage = args.enemy_damage.copy()
    world.beemizer_total_chance = args.beemizer_total_chance.copy()
    world.beemizer_trap_chance = args.beemizer_trap_chance.copy()
    world.timer = args.timer.copy()
    world.countdown_start_time = args.countdown_start_time.copy()
    world.red_clock_time = args.red_clock_time.copy()
    world.blue_clock_time = args.blue_clock_time.copy()
    world.green_clock_time = args.green_clock_time.copy()
    world.dungeon_counters = args.dungeon_counters.copy()
    world.triforce_pieces_available = args.triforce_pieces_available.copy()
    world.triforce_pieces_required = args.triforce_pieces_required.copy()
    world.shop_shuffle = args.shop_shuffle.copy()
    world.shuffle_prizes = args.shuffle_prizes.copy()
    world.sprite_pool = args.sprite_pool.copy()
    world.dark_room_logic = args.dark_room_logic.copy()
    world.plando_items = args.plando_items.copy()
    world.plando_texts = args.plando_texts.copy()
    world.plando_connections = args.plando_connections.copy()
    world.required_medallions = args.required_medallions.copy()
    world.game = args.game.copy()
    world.player_name = args.name.copy()
    world.enemizer = args.enemizercli
    world.sprite = args.sprite.copy()
    world.glitch_triforce = args.glitch_triforce  # This is enabled/disabled globally, no per player option.

    world.set_options(args)
    world.set_item_links()
    world.state = CollectionState(world)
    logger.info('Archipelago Version %s  -  Seed: %s\n', __version__, world.seed)

    logger.info("Found World Types:")
    longest_name = max(len(text) for text in AutoWorld.AutoWorldRegister.world_types)
    numlength = 8
    for name, cls in AutoWorld.AutoWorldRegister.world_types.items():
        if not cls.hidden:
            logger.info(f"  {name:{longest_name}}: {len(cls.item_names):3} "
                        f"Items (IDs: {min(cls.item_id_to_name):{numlength}} - "
                        f"{max(cls.item_id_to_name):{numlength}}) | "
                        f"{len(cls.location_names):3} "
                        f"Locations (IDs: {min(cls.location_id_to_name):{numlength}} - "
                        f"{max(cls.location_id_to_name):{numlength}})")

    AutoWorld.call_stage(world, "assert_generate")

    AutoWorld.call_all(world, "generate_early")

    logger.info('')

    for player in world.player_ids:
        for item_name, count in world.start_inventory[player].value.items():
            for _ in range(count):
                world.push_precollected(world.create_item(item_name, player))

    for player in world.player_ids:
        if player in world.get_game_players("A Link to the Past"):
            # enforce pre-defined local items.
            if world.goal[player] in ["localtriforcehunt", "localganontriforcehunt"]:
                world.local_items[player].value.add('Triforce Piece')

            # Not possible to place pendants/crystals out side of boss prizes yet.
            world.non_local_items[player].value -= item_name_groups['Pendants']
            world.non_local_items[player].value -= item_name_groups['Crystals']

        # items can't be both local and non-local, prefer local
        world.non_local_items[player].value -= world.local_items[player].value

    logger.info('Creating World.')
    AutoWorld.call_all(world, "create_regions")

    logger.info('Creating Items.')
    AutoWorld.call_all(world, "create_items")

    logger.info('Calculating Access Rules.')
    if world.players > 1:
        for player in world.player_ids:
            locality_rules(world, player)
        group_locality_rules(world)
    else:
        world.non_local_items[1].value = set()
        world.local_items[1].value = set()

    AutoWorld.call_all(world, "set_rules")

    for player in world.player_ids:
        exclusion_rules(world, player, world.exclude_locations[player].value)
        world.priority_locations[player].value -= world.exclude_locations[player].value
        for location_name in world.priority_locations[player].value:
            world.get_location(location_name, player).progress_type = LocationProgressType.PRIORITY

    AutoWorld.call_all(world, "generate_basic")

    # temporary home for item links, should be moved out of Main
    for group_id, group in world.groups.items():
        def find_common_pool(players: Set[int], shared_pool: Set[str]):
            classifications = collections.defaultdict(int)
            counters = {player: {name: 0 for name in shared_pool} for player in players}
            for item in world.itempool:
                if item.player in counters and item.name in shared_pool:
                    counters[item.player][item.name] += 1
                    classifications[item.name] |= item.classification

            for player in players.copy():
                if all([counters[player][item] == 0 for item in shared_pool]):
                    players.remove(player)
                    del(counters[player])

            if not players:
                return None, None

            for item in shared_pool:
                count = min(counters[player][item] for player in players)
                if count:
                    for player in players:
                        counters[player][item] = count
                else:
                    for player in players:
                        del(counters[player][item])
            return counters, classifications

        common_item_count, classifications = find_common_pool(group["players"], group["item_pool"])
        if not common_item_count:
            continue

        new_itempool = []
        for item_name, item_count in next(iter(common_item_count.values())).items():
            for _ in range(item_count):
                new_item = group["world"].create_item(item_name)
                # mangle together all original classification bits
                new_item.classification |= classifications[item_name]
                new_itempool.append(new_item)

        region = Region("Menu", RegionType.Generic, "ItemLink", group_id, world)
        world.regions.append(region)
        locations = region.locations = []
        for item in world.itempool:
            count = common_item_count.get(item.player, {}).get(item.name, 0)
            if count:
                loc = Location(group_id, f"Item Link: {item.name} -> {world.player_name[item.player]} {count}",
                               None, region)
                loc.access_rule = lambda state, item_name = item.name, group_id_ = group_id, count_ = count: \
                    state.has(item_name, group_id_, count_)

                locations.append(loc)
                loc.place_locked_item(item)
                common_item_count[item.player][item.name] -= 1
            else:
                new_itempool.append(item)

        itemcount = len(world.itempool)
        world.itempool = new_itempool

        while itemcount > len(world.itempool):
            items_to_add = []
            for player in group["players"]:
                if group["replacement_items"][player]:
                    items_to_add.append(AutoWorld.call_single(world, "create_item", player,
                                                                group["replacement_items"][player]))
                else:
                    items_to_add.append(AutoWorld.call_single(world, "create_filler", player))
            world.random.shuffle(items_to_add)
            world.itempool.extend(items_to_add[:itemcount - len(world.itempool)])

    if any(world.item_links.values()):
        world._recache()
        world._all_state = None

    logger.info("Running Item Plando")

    for item in world.itempool:
        item.world = world

    distribute_planned(world)

    logger.info('Running Pre Main Fill.')

    AutoWorld.call_all(world, "pre_fill")

    logger.info(f'Filling the world with {len(world.itempool)} items.')

    if world.algorithm == 'flood':
        flood_items(world)  # different algo, biased towards early game progress items
    elif world.algorithm == 'balanced':
        distribute_items_restrictive(world)

    AutoWorld.call_all(world, 'post_fill')

    if world.players > 1:
        balance_multiworld_progression(world)

    logger.info(f'Beginning output...')
    outfilebase = 'AP_' + world.seed_name

    output = tempfile.TemporaryDirectory()
    with output as temp_dir:
        with concurrent.futures.ThreadPoolExecutor(world.players + 2) as pool:
            check_accessibility_task = pool.submit(world.fulfills_accessibility)

            output_file_futures = [pool.submit(AutoWorld.call_stage, world, "generate_output", temp_dir)]
            for player in world.player_ids:
                # skip starting a thread for methods that say "pass".
                if AutoWorld.World.generate_output.__code__ is not world.worlds[player].generate_output.__code__:
                    output_file_futures.append(
                        pool.submit(AutoWorld.call_single, world, "generate_output", player, temp_dir))

            def get_entrance_to_region(region: Region):
                for entrance in region.entrances:
                    if entrance.parent_region.type in (RegionType.DarkWorld, RegionType.LightWorld, RegionType.Generic):
                        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 world.get_game_players("A Link to the Past") if
                            world.shuffle[player] != "vanilla" or world.retro_caves[player]}

            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

            checks_in_area = {player: {area: list() for area in ordered_areas}
                              for player in range(1, world.players + 1)}

            for player in range(1, world.players + 1):
                checks_in_area[player]["Total"] = 0

            for location in world.get_filled_locations():
                if type(location.address) is int:
                    main_entrance = get_entrance_to_region(location.parent_region)
                    if location.game != "A Link to the Past":
                        checks_in_area[location.player]["Light World"].append(location.address)
                    elif location.parent_region.dungeon:
                        dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
                                       'Inverted Ganons Tower': 'Ganons Tower'} \
                            .get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
                        checks_in_area[location.player][dungeonname].append(location.address)
                    elif location.parent_region.type == RegionType.LightWorld:
                        checks_in_area[location.player]["Light World"].append(location.address)
                    elif location.parent_region.type == RegionType.DarkWorld:
                        checks_in_area[location.player]["Dark World"].append(location.address)
                    elif main_entrance.parent_region.type == RegionType.LightWorld:
                        checks_in_area[location.player]["Light World"].append(location.address)
                    elif main_entrance.parent_region.type == RegionType.DarkWorld:
                        checks_in_area[location.player]["Dark World"].append(location.address)
                    checks_in_area[location.player]["Total"] += 1

            oldmancaves = []
            takeanyregions = ["Old Man Sword Cave", "Take-Any #1", "Take-Any #2", "Take-Any #3", "Take-Any #4"]
            for index, take_any in enumerate(takeanyregions):
                for region in [world.get_region(take_any, player) for player in
                               world.get_game_players("A Link to the Past") if world.retro_caves[player]]:
                    item = world.create_item(
                        region.shop.inventory[(0 if take_any == "Old Man Sword Cave" else 1)]['item'],
                        region.player)
                    player = region.player
                    location_id = SHOP_ID_START + total_shop_slots + index

                    main_entrance = get_entrance_to_region(region)
                    if main_entrance.parent_region.type == RegionType.LightWorld:
                        checks_in_area[player]["Light World"].append(location_id)
                    else:
                        checks_in_area[player]["Dark World"].append(location_id)
                    checks_in_area[player]["Total"] += 1

                    er_hint_data[player][location_id] = main_entrance.name
                    oldmancaves.append(((location_id, player), (item.code, player)))

            FillDisabledShopSlots(world)

            def write_multidata():
                import NetUtils
                slot_data = {}
                client_versions = {}
                games = {}
                minimum_versions = {"server": AutoWorld.World.required_server_version, "clients": client_versions}
                slot_info = {}
                names = [[name for player, name in sorted(world.player_name.items())]]
                for slot in world.player_ids:
                    player_world: AutoWorld.World = world.worlds[slot]
                    minimum_versions["server"] = max(minimum_versions["server"], player_world.required_server_version)
                    client_versions[slot] = player_world.required_client_version
                    games[slot] = world.game[slot]
                    slot_info[slot] = NetUtils.NetworkSlot(names[0][slot - 1], world.game[slot],
                                                           world.player_types[slot])
                for slot, group in world.groups.items():
                    games[slot] = world.game[slot]
                    slot_info[slot] = NetUtils.NetworkSlot(group["name"], world.game[slot], world.player_types[slot],
                                                           group_members=sorted(group["players"]))
                precollected_items = {player: [item.code for item in world_precollected if type(item.code) == int]
                                      for player, world_precollected in world.precollected_items.items()}
                precollected_hints = {player: set() for player in range(1, world.players + 1 + len(world.groups))}


                for slot in world.player_ids:
                    slot_data[slot] = world.worlds[slot].fill_slot_data()

                def precollect_hint(location):
                    entrance = er_hint_data.get(location.player, {}).get(location.address, "")
                    hint = NetUtils.Hint(location.item.player, location.player, location.address,
                                         location.item.code, False, entrance, location.item.flags)
                    precollected_hints[location.player].add(hint)
                    if location.item.player not in world.groups:
                        precollected_hints[location.item.player].add(hint)
                    else:
                        for player in world.groups[location.item.player]["players"]:
                            precollected_hints[player].add(hint)

                locations_data: Dict[int, Dict[int, Tuple[int, int, int]]] = {player: {} for player in world.player_ids}
                for location in world.get_filled_locations():
                    if type(location.address) == int:
                        assert location.item.code is not None, "item code None should be event, " \
                                                               "location.address should then also be None"
                        locations_data[location.player][location.address] = \
                            location.item.code, location.item.player, location.item.flags
                        if location.name in world.start_location_hints[location.player]:
                            precollect_hint(location)
                        elif location.item.name in world.start_hints[location.item.player]:
                            precollect_hint(location)
                        elif any([location.item.name in world.start_hints[player]
                                  for player in world.groups.get(location.item.player, {}).get("players", [])]):
                            precollect_hint(location)

                multidata = {
                    "slot_data": slot_data,
                    "slot_info": slot_info,
                    "names": names,  # TODO: remove around 0.2.5 in favor of slot_info
                    "games": games,  # TODO: remove around 0.2.5 in favor of slot_info
                    "connect_names": {name: (0, player) for player, name in world.player_name.items()},
                    "remote_items": {player for player in world.player_ids if
                                     world.worlds[player].remote_items},
                    "remote_start_inventory": {player for player in world.player_ids if
                                               world.worlds[player].remote_start_inventory},
                    "locations": locations_data,
                    "checks_in_area": checks_in_area,
                    "server_options": baked_server_options,
                    "er_hint_data": er_hint_data,
                    "precollected_items": precollected_items,
                    "precollected_hints": precollected_hints,
                    "version": tuple(version_tuple),
                    "tags": ["AP"],
                    "minimum_versions": minimum_versions,
                    "seed_name": world.seed_name
                }
                AutoWorld.call_all(world, "modify_multidata", multidata)

                multidata = zlib.compress(pickle.dumps(multidata), 9)

                with open(os.path.join(temp_dir, f'{outfilebase}.archipelago'), 'wb') as f:
                    f.write(bytes([3]))  # version of format
                    f.write(multidata)

            multidata_task = pool.submit(write_multidata)
            if not check_accessibility_task.result():
                if not world.can_beat_game():
                    raise Exception("Game appears as unbeatable. Aborting.")
                else:
                    logger.warning("Location Accessibility requirements not fulfilled.")

            # retrieve exceptions via .result() if they occurred.
            multidata_task.result()
            for i, future in enumerate(concurrent.futures.as_completed(output_file_futures), start=1):
                if i % 10 == 0 or i == len(output_file_futures):
                    logger.info(f'Generating output files ({i}/{len(output_file_futures)}).')
                future.result()

        if args.spoiler > 1:
            logger.info('Calculating playthrough.')
            create_playthrough(world)

        if args.spoiler:
            world.spoiler.to_file(os.path.join(temp_dir, '%s_Spoiler.txt' % outfilebase))

        zipfilename = output_path(f"AP_{world.seed_name}.zip")
        logger.info(f'Creating final archive at {zipfilename}.')
        with zipfile.ZipFile(zipfilename, mode="w", compression=zipfile.ZIP_DEFLATED,
                             compresslevel=9) as zf:
            for file in os.scandir(temp_dir):
                zf.write(file.path, arcname=file.name)

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