Exemple #1
0
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    # with shuffled dungeon items they are distributed as part of the normal item pool
    for item in world.get_items():
        if (item.smallkey and world.keyshuffle[item.player]) or (
                item.bigkey and world.bigkeyshuffle[item.player]):
            all_state_base.collect(item, True)
            item.advancement = True
        elif (item.map and world.mapshuffle[item.player]) or (
                item.compass and world.compassshuffle[item.player]):
            item.priority = True

    dungeon_items = [
        item for item in get_dungeon_item_pool(world)
        if ((item.smallkey and not world.keyshuffle[item.player]) or (
            item.bigkey and not world.bigkeyshuffle[item.player]) or (
                item.map and not world.mapshuffle[item.player]) or (
                    item.compass and not world.compassshuffle[item.player]))
    ]

    # sort in the order Big Key, Small Key, Other before placing dungeon items
    sort_order = {"BigKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items,
                     True)
Exemple #2
0
    def test_restrictive_progress(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, prog_item_count=25)
        items = player1.prog_items.copy()
        multi_world.completion_condition[
            player1.id] = lambda state: state.has_all(
                names(player1.prog_items), player1.id)

        player1.generate_region(player1.menu, 5)
        player1.generate_region(
            player1.menu, 5,
            lambda state: state.has_all(names(items[2:7]), player1.id))
        player1.generate_region(
            player1.menu, 5,
            lambda state: state.has_all(names(items[7:12]), player1.id))
        player1.generate_region(
            player1.menu, 5,
            lambda state: state.has_all(names(items[12:17]), player1.id))
        player1.generate_region(
            player1.menu, 5,
            lambda state: state.has_all(names(items[17:22]), player1.id))

        locations = multi_world.get_unfilled_locations()

        fill_restrictive(multi_world, multi_world.state, locations,
                         player1.prog_items)
Exemple #3
0
    def pre_fill(self):
        from Fill import fill_restrictive
        self.InitialFillInOwnWorld()

        if (not self.smz3World.Config.Keysanity):
            locations = [loc for loc in self.locations.values() if loc.item is None]
            self.world.random.shuffle(locations)

            all_state = self.world.get_all_state(False)
            for item in self.smz3DungeonItems:
                all_state.remove(item)

            all_dungeonItems = self.smz3DungeonItems[:]
            fill_restrictive(self.world, all_state, locations, all_dungeonItems, True, True)
            # some small or big keys (those always_allow) can be unreachable in-game
            # while logic still collects some of them (probably to simulate the player collecting pot keys in the logic), some others don't
            # so we need to remove those exceptions as progression items
            if self.world.accessibility[self.player] != 'locations':
                exception_item = [TotalSMZ3Item.ItemType.BigKeySW, TotalSMZ3Item.ItemType.BigKeySP, TotalSMZ3Item.ItemType.KeyTH]
                for item in self.smz3DungeonItems:
                    if item.item.Type in exception_item and item.location.always_allow(all_state, item) and not all_state.can_reach(item.location):
                        item.classification = ItemClassification.filler
                        item.item.Progression = False
                        item.location.event = False
                        self.unreachable.append(item.location)
Exemple #4
0
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    for player in range(1, world.players + 1):
        pinball_room = world.get_location('Skull Woods - Pinball Room', player)
        if world.retro:
            world.push_item(pinball_room,
                            ItemFactory('Small Key (Universal)', player),
                            False)
        else:
            world.push_item(pinball_room,
                            ItemFactory('Small Key (Skull Woods)', player),
                            False)
        pinball_room.event = True
        pinball_room.locked = True
        shuffled_locations.remove(pinball_room)

    if world.keysanity:
        #in keysanity dungeon items are distributed as part of the normal item pool
        for item in world.get_items():
            if item.key:
                item.advancement = True
            elif item.map or item.compass:
                item.priority = True
        return

    dungeon_items = get_dungeon_item_pool(world)

    # sort in the order Big Key, Small Key, Other before placing dungeon items
    sort_order = {"BigKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items)
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    skull_woods_big_chest = world.get_location('Skull Woods - Pinball Room')
    if world.retro:
        world.push_item(skull_woods_big_chest, ItemFactory('Small Key (Universal)'), False)
    else:
        world.push_item(skull_woods_big_chest, ItemFactory('Small Key (Skull Woods)'), False)
    skull_woods_big_chest.event = True
    shuffled_locations.remove(skull_woods_big_chest)

    if world.keysanity:
        #in keysanity dungeon items are distributed as part of the normal item pool
        for item in world.get_items():
            if item.key:
                item.advancement = True
            elif item.map or item.compass:
                item.priority = True
        return

    dungeon_items = get_dungeon_item_pool(world)

    # sort in the order Big Key, Small Key, Other before placing dungeon items
    sort_order = {"BigKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items)

    world.state.clear_cached_unreachable()
def fill_prizes(world, attempts=15):
    all_state = world.get_all_state(keys=True)
    for player in range(1, world.players + 1):
        crystals = ItemFactory(['Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7', 'Crystal 5', 'Crystal 6'], player)
        crystal_locations = [world.get_location('Turtle Rock - Prize', player), world.get_location('Eastern Palace - Prize', player), world.get_location('Desert Palace - Prize', player), world.get_location('Tower of Hera - Prize', player), world.get_location('Palace of Darkness - Prize', player),
                             world.get_location('Thieves\' Town - Prize', player), world.get_location('Skull Woods - Prize', player), world.get_location('Swamp Palace - Prize', player), world.get_location('Ice Palace - Prize', player),
                             world.get_location('Misery Mire - Prize', player)]
        placed_prizes = [loc.item.name for loc in crystal_locations if loc.item is not None]
        unplaced_prizes = [crystal for crystal in crystals if crystal.name not in placed_prizes]
        empty_crystal_locations = [loc for loc in crystal_locations if loc.item is None]
        for attempt in range(attempts):
            try:
                prizepool = list(unplaced_prizes)
                prize_locs = list(empty_crystal_locations)
                world.random.shuffle(prizepool)
                world.random.shuffle(prize_locs)
                fill_restrictive(world, all_state, prize_locs, prizepool, True)
            except FillError as e:
                logging.getLogger('').exception("Failed to place dungeon prizes (%s). Will retry %s more times", e,
                                                attempts - attempt)
                for location in empty_crystal_locations:
                    location.item = None
                continue
            break
        else:
            raise FillError('Unable to place dungeon prizes')
Exemple #7
0
 def pre_fill(self):
     from Fill import fill_restrictive, FillError
     attempts = 5
     world = self.world
     player = self.player
     all_state = world.get_all_state(use_cache=True)
     crystals = [
         self.create_item(name) for name in [
             'Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1',
             'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7',
             'Crystal 5', 'Crystal 6'
         ]
     ]
     crystal_locations = [
         world.get_location('Turtle Rock - Prize', player),
         world.get_location('Eastern Palace - Prize', player),
         world.get_location('Desert Palace - Prize', player),
         world.get_location('Tower of Hera - Prize', player),
         world.get_location('Palace of Darkness - Prize', player),
         world.get_location('Thieves\' Town - Prize', player),
         world.get_location('Skull Woods - Prize', player),
         world.get_location('Swamp Palace - Prize', player),
         world.get_location('Ice Palace - Prize', player),
         world.get_location('Misery Mire - Prize', player)
     ]
     placed_prizes = {
         loc.item.name
         for loc in crystal_locations if loc.item
     }
     unplaced_prizes = [
         crystal for crystal in crystals
         if crystal.name not in placed_prizes
     ]
     empty_crystal_locations = [
         loc for loc in crystal_locations if not loc.item
     ]
     for attempt in range(attempts):
         try:
             prizepool = unplaced_prizes.copy()
             prize_locs = empty_crystal_locations.copy()
             world.random.shuffle(prize_locs)
             fill_restrictive(world,
                              all_state,
                              prize_locs,
                              prizepool,
                              True,
                              lock=True)
         except FillError as e:
             lttp_logger.exception(
                 "Failed to place dungeon prizes (%s). Will retry %s more times",
                 e, attempts - attempt)
             for location in empty_crystal_locations:
                 location.item = None
             continue
         break
     else:
         raise FillError('Unable to place dungeon prizes')
Exemple #8
0
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    dungeon_items = get_dungeon_item_pool(world)

    # sort in the order Boss Key, Small Key, Other before placing dungeon items
    sort_order = {"BossKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items)

    world.state.clear_cached_unreachable()
Exemple #9
0
def fill_dungeons_restrictive(world):
    """Places dungeon-native items into their dungeons, places nothing if everything is shuffled outside."""
    localized: set = set()
    dungeon_specific: set = set()
    for subworld in world.get_game_worlds("A Link to the Past"):
        player = subworld.player
        localized |= {(player, item_name)
                      for item_name in subworld.dungeon_local_item_names}
        dungeon_specific |= {
            (player, item_name)
            for item_name in subworld.dungeon_specific_item_names
        }

    if localized:
        in_dungeon_items = [
            item for item in get_dungeon_item_pool(world)
            if (item.player, item.name) in localized
        ]
        if in_dungeon_items:
            restricted_players = {
                player
                for player, restricted in
                world.restrict_dungeon_item_on_boss.items() if restricted
            }
            locations = [
                location
                for location in world.get_unfilled_dungeon_locations()
                # filter boss
                if not (location.player in restricted_players
                        and location.name in lookup_boss_drops)
            ]
            if dungeon_specific:
                for location in locations:
                    dungeon = location.parent_region.dungeon
                    orig_rule = location.item_rule
                    location.item_rule = lambda item, dungeon=dungeon, orig_rule=orig_rule: \
                        (not (item.player, item.name) in dungeon_specific or item.dungeon is dungeon) and orig_rule(item)

            world.random.shuffle(locations)
            all_state_base = world.get_all_state(use_cache=True)
            # Dungeon-locked items have to be placed first, to not run out of spaces for dungeon-locked items
            # subsort in the order Big Key, Small Key, Other before placing dungeon items

            sort_order = {"BigKey": 3, "SmallKey": 2}
            in_dungeon_items.sort(
                key=lambda item: sort_order.get(item.type, 1) +
                (5 if (item.player, item.name) in dungeon_specific else 0))
            for item in in_dungeon_items:
                all_state_base.remove(item)
            fill_restrictive(world, all_state_base, locations,
                             in_dungeon_items, True, True)
Exemple #10
0
    def test_ordered_fill(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, 2, 2)
        items = player1.prog_items
        locations = player1.locations

        multi_world.completion_condition[player1.id] = lambda state: state.has(
            items[0].name, player1.id) and state.has(items[1].name, player1.id)
        set_rule(locations[1],
                 lambda state: state.has(items[0].name, player1.id))
        fill_restrictive(multi_world, multi_world.state,
                         player1.locations.copy(), player1.prog_items.copy())

        self.assertEqual(locations[0].item, items[0])
        self.assertEqual(locations[1].item, items[1])
Exemple #11
0
    def test_basic_fill(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, 2, 2)

        item0 = player1.prog_items[0]
        item1 = player1.prog_items[1]
        loc0 = player1.locations[0]
        loc1 = player1.locations[1]

        fill_restrictive(multi_world, multi_world.state, player1.locations,
                         player1.prog_items)

        self.assertEqual(loc0.item, item1)
        self.assertEqual(loc1.item, item0)
        self.assertEqual([], player1.locations)
        self.assertEqual([], player1.prog_items)
Exemple #12
0
    def test_reversed_fill(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, 2, 2)

        item0 = player1.prog_items[0]
        item1 = player1.prog_items[1]
        loc0 = player1.locations[0]
        loc1 = player1.locations[1]

        multi_world.completion_condition[player1.id] = lambda state: state.has(
            item0.name, player1.id) and state.has(item1.name, player1.id)
        set_rule(loc1, lambda state: state.has(item1.name, player1.id))
        fill_restrictive(multi_world, multi_world.state, player1.locations,
                         player1.prog_items)

        self.assertEqual(loc0.item, item1)
        self.assertEqual(loc1.item, item0)
Exemple #13
0
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    skull_woods_big_chest = world.get_location('Skull Woods - Pinball Room')
    world.push_item(skull_woods_big_chest, ItemFactory('Small Key (Skull Woods)'), False)
    skull_woods_big_chest.event = True
    shuffled_locations.remove(skull_woods_big_chest)

    dungeon_items = [item for dungeon in world.dungeons for item in dungeon.all_items if item.key or world.place_dungeon_items]

    # sort in the order Big Key, Small Key, Other before placing dungeon items
    sort_order = {"BigKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items)

    world.state._clear_cache()
Exemple #14
0
    def generate_basic(self):
        self.world.get_location("Place of Power",
                                self.player).place_locked_item(
                                    self.create_item("Cursed Seal"))
        self.world.get_location("The Last Place You'll Look",
                                self.player).place_locked_item(
                                    self.create_item("Agate Knife"))
        self.world.get_location("Wervyn Anixil",
                                self.player).place_locked_item(
                                    self.create_event("Victory"))
        self.world.get_location("Wervyn Anixil?",
                                self.player).place_locked_item(
                                    self.create_event("Full Victory"))
        for boss in ["Meridian", "Ataraxia", "Merodach"]:
            self.world.get_location(f"{boss} Defeat",
                                    self.player).place_locked_item(
                                        self.create_event(f"{boss} Defeated"))

        if not self.include_psi_keys:
            psi_keys = []
            psi_key_storage = []
            for i in range(0, 3):
                psi_keys += [self.create_item(f"PSI Key {i + 1}")]
                psi_key_storage += [
                    self.world.get_location(f"PSI Key Storage {i + 1}",
                                            self.player)
                ]

            fill_restrictive(self.world, self.world.get_all_state(False),
                             psi_key_storage, psi_keys)

        if not self.include_evolution_traps:
            for boss in ["Meridian", "Ataraxia", "Merodach"]:
                self.world.get_location(boss, self.player).place_locked_item(
                    self.create_item("Evolution Trap"))

        if self.goal == 0:
            self.world.completion_condition[
                self.player] = lambda state: state.has_any(
                    ["Victory", "Full Victory"], self.player)
        else:
            self.world.completion_condition[
                self.player] = lambda state: state.has("Full Victory", self.
                                                       player)
Exemple #15
0
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    # for player in range(1, world.players + 1):
    #     pinball_room = world.get_location('Skull Woods - Pinball Room', player)
    #     if world.retro[player]:
    #         world.push_item(pinball_room, ItemFactory('Small Key (Universal)', player), False)
    #     else:
    #         world.push_item(pinball_room, ItemFactory('Small Key (Skull Woods)', player), False)
    #     pinball_room.event = True
    #     pinball_room.locked = True
    #     shuffled_locations.remove(pinball_room)

    # with shuffled dungeon items they are distributed as part of the normal item pool
    for item in world.get_items():
        if (item.smallkey and world.keyshuffle[item.player]) or (
                item.bigkey and world.bigkeyshuffle[item.player]):
            item.advancement = True
        elif (item.map and world.mapshuffle[item.player]) or (
                item.compass and world.compassshuffle[item.player]):
            item.priority = True

    dungeon_items = [
        item for item in get_dungeon_item_pool(world)
        if ((item.smallkey and not world.keyshuffle[item.player]) or (
            item.bigkey and not world.bigkeyshuffle[item.player]) or (
                item.map and not world.mapshuffle[item.player]) or (
                    item.compass and not world.compassshuffle[item.player]))
    ]

    # sort in the order Big Key, Small Key, Other before placing dungeon items
    sort_order = {"BigKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world,
                     all_state_base,
                     shuffled_locations,
                     dungeon_items,
                     keys_in_itempool={
                         player: not world.keyshuffle[player]
                         for player in range(1, world.players + 1)
                     },
                     single_player_placement=True)
def fill_songs(world, attempts=15):
    songs = ItemFactory(songlist)
    song_locations = [
        world.get_location('Song from Composer Grave'),
        world.get_location('Impa at Castle'),
        world.get_location('Song from Malon'),
        world.get_location('Song from Saria'),
        world.get_location('Song from Ocarina of Time'),
        world.get_location('Song at Windmill'),
        world.get_location('Sheik Forest Song'),
        world.get_location('Sheik at Temple'),
        world.get_location('Sheik in Crater'),
        world.get_location('Sheik in Ice Cavern'),
        world.get_location('Sheik in Kakariko'),
        world.get_location('Sheik at Colossus')
    ]
    placed_prizes = [
        loc.item.name for loc in song_locations if loc.item is not None
    ]
    unplaced_prizes = [
        song for song in songs if song.name not in placed_prizes
    ]
    empty_song_locations = [loc for loc in song_locations if loc.item is None]

    while attempts:
        attempts -= 1
        try:
            prizepool = list(unplaced_prizes)
            prize_locs = list(empty_song_locations)
            random.shuffle(prizepool)
            random.shuffle(prize_locs)
            fill_restrictive(
                world, world.get_all_state(keys=True), prize_locs, prizepool
            )  #TODO: Set keys to true once keys are properly implemented
        except FillError:
            logging.getLogger('').info(
                "Failed to place songs. Will retry %s more times", attempts)
            for location in empty_song_locations:
                location.item = None
            continue
        break
    else:
        raise FillError('Unable to place songs')
Exemple #17
0
def fill_dungeons_restrictive(world, shuffled_locations):
    all_state_base = world.get_all_state()

    for player in range(1, world.players + 1):
        if not world.retro[
                player] and world.logic == "noglitches" and not world.keyshuffle[
                    player]:
            skull_woods = world.get_dungeon('Skull Woods', player)
            skull_woods.small_keys.pop()
            pinball_room = world.get_location('Skull Woods - Pinball Room',
                                              player)
            world.push_item(pinball_room,
                            ItemFactory('Small Key (Skull Woods)', player),
                            False)
            pinball_room.event = True
            pinball_room.locked = True
            shuffled_locations.remove(pinball_room)

    # with shuffled dungeon items they are distributed as part of the normal item pool
    for item in world.get_items():
        if (item.smallkey and world.keyshuffle[item.player]) or (
                item.bigkey and world.bigkeyshuffle[item.player]):
            all_state_base.collect(item, True)
            item.advancement = True
        elif (item.map and world.mapshuffle[item.player]) or (
                item.compass and world.compassshuffle[item.player]):
            item.priority = True

    dungeon_items = [
        item for item in get_dungeon_item_pool(world)
        if ((item.smallkey and not world.keyshuffle[item.player]) or (
            item.bigkey and not world.bigkeyshuffle[item.player]) or (
                item.map and not world.mapshuffle[item.player]) or (
                    item.compass and not world.compassshuffle[item.player]))
    ]

    # sort in the order Big Key, Small Key, Other before placing dungeon items
    sort_order = {"BigKey": 3, "SmallKey": 2}
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))

    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items,
                     True)
Exemple #18
0
def fill_songs(world, attempts=15):
    songs = ItemFactory(songlist)
    song_locations = [
        world.get_location('Song from Skull Kid'),
        world.get_location('Song from HMS'),
        world.get_location('Song from Owl Tablet'),
        world.get_location('Song from Romani'),
        world.get_location('Song at Grave'),
        world.get_location('Song from Monkey'),
        world.get_location('Song from Baby Goron'),
        world.get_location('Song from Goron Elder'),
        world.get_location('Song from Zora Eggs'),
        world.get_location('Song from Igos'),
        world.get_location('Song from the Giants')
    ]
    placed_prizes = [
        loc.item.name for loc in song_locations if loc.item is not None
    ]
    unplaced_prizes = [
        song for song in songs if song.name not in placed_prizes
    ]
    empty_song_locations = [loc for loc in song_locations if loc.item is None]

    while attempts:
        attempts -= 1
        try:
            prizepool = list(unplaced_prizes)
            prize_locs = list(empty_song_locations)
            random.shuffle(prizepool)
            random.shuffle(prize_locs)
            fill_restrictive(
                world, world.get_all_state(keys=True), prize_locs, prizepool
            )  #TODO: Set keys to true once keys are properly implemented
        except FillError:
            logging.getLogger('').info(
                "Failed to place songs. Will retry %s more times", attempts)
            for location in empty_song_locations:
                location.item = None
            continue
        break
    else:
        raise FillError('Unable to place songs')
Exemple #19
0
    def test_multiplayer_fill(self):
        multi_world = generate_multi_world(2)
        player1 = generate_player_data(multi_world, 1, 2, 2)
        player2 = generate_player_data(multi_world, 2, 2, 2)

        multi_world.completion_condition[player1.id] = lambda state: state.has(
            player1.prog_items[0].name, player1.id) and state.has(
                player1.prog_items[1].name, player1.id)
        multi_world.completion_condition[player2.id] = lambda state: state.has(
            player2.prog_items[0].name, player2.id) and state.has(
                player2.prog_items[1].name, player2.id)

        fill_restrictive(multi_world, multi_world.state,
                         player1.locations + player2.locations,
                         player1.prog_items + player2.prog_items)

        self.assertEqual(player1.locations[0].item, player1.prog_items[1])
        self.assertEqual(player1.locations[1].item, player2.prog_items[1])
        self.assertEqual(player2.locations[0].item, player1.prog_items[0])
        self.assertEqual(player2.locations[1].item, player2.prog_items[0])
Exemple #20
0
    def test_minimal_fill(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, 2, 2)

        items = player1.prog_items
        locations = player1.locations

        multi_world.accessibility[
            player1.id].value = multi_world.accessibility[
                player1.id].option_minimal
        multi_world.completion_condition[
            player1.id] = lambda state: state.has(items[1].name, player1.id)
        set_rule(locations[1],
                 lambda state: state.has(items[0].name, player1.id))

        fill_restrictive(multi_world, multi_world.state,
                         player1.locations.copy(), player1.prog_items.copy())

        self.assertEqual(locations[0].item, items[1])
        # Unnecessary unreachable Item
        self.assertEqual(locations[1].item, items[0])
Exemple #21
0
def fill_dungeons_restrictive(world):
    """Places dungeon-native items into their dungeons, places nothing if everything is shuffled outside."""
    restricted_players = {
        player
        for player, restricted in world.restrict_dungeon_item_on_boss.items()
        if restricted
    }

    locations = [
        location for location in world.get_unfilled_dungeon_locations()
        if not (location.player in restricted_players
                and location.name in lookup_boss_drops)
    ]  # filter boss

    world.random.shuffle(locations)
    all_state_base = world.get_all_state()

    # with shuffled dungeon items they are distributed as part of the normal item pool
    for item in world.get_items():
        if (item.smallkey and world.keyshuffle[item.player]) or (
                item.bigkey and world.bigkeyshuffle[item.player]):
            all_state_base.collect(item, True)
            item.advancement = True
        elif (item.map and world.mapshuffle[item.player]) or (
                item.compass and world.compassshuffle[item.player]):
            item.priority = True

    dungeon_items = [
        item for item in get_dungeon_item_pool(world)
        if ((item.smallkey and not world.keyshuffle[item.player]) or (
            item.bigkey and not world.bigkeyshuffle[item.player]) or (
                item.map and not world.mapshuffle[item.player]) or (
                    item.compass and not world.compassshuffle[item.player]))
    ]
    if dungeon_items:
        # sort in the order Big Key, Small Key, Other before placing dungeon items
        sort_order = {"BigKey": 3, "SmallKey": 2}
        dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))
        fill_restrictive(world, all_state_base, locations, dungeon_items, True)
Exemple #22
0
    def test_partial_fill(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, 3, 2)

        item0 = player1.prog_items[0]
        item1 = player1.prog_items[1]
        loc0 = player1.locations[0]
        loc1 = player1.locations[1]
        loc2 = player1.locations[2]

        multi_world.completion_condition[player1.id] = lambda state: state.has(
            item0.name, player1.id) and state.has(item1.name, player1.id)
        set_rule(loc1, lambda state: state.has(item0.name, player1.id))
        # forces a swap
        set_rule(loc2, lambda state: state.has(item0.name, player1.id))
        fill_restrictive(multi_world, multi_world.state, player1.locations,
                         player1.prog_items)

        self.assertEqual(loc0.item, item0)
        self.assertEqual(loc1.item, item1)
        self.assertEqual(1, len(player1.locations))
        self.assertEqual(player1.locations[0], loc2)
def generate_itempool(world):
    if (world.difficulty not in ['easy', 'normal', 'hard', 'expert', 'insane']
            or world.goal not in [
                'ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'
            ] or world.mode not in ['open', 'standard', 'swordless']
            or world.timer not in [
                'none', 'display', 'timed', 'timed-ohko', 'timed-countdown'
            ] or world.progressive not in ['on', 'off', 'random']):
        raise NotImplementedError('Not supported yet')

    world.push_item('Ganon', ItemFactory('Triforce'), False)
    world.get_location('Ganon').event = True
    world.push_item('Agahnim 1', ItemFactory('Beat Agahnim 1'), False)
    world.get_location('Agahnim 1').event = True
    world.push_item('Agahnim 2', ItemFactory('Beat Agahnim 2'), False)
    world.get_location('Agahnim 2').event = True

    # set up item pool
    world.itempool = ItemFactory(alwaysitems)
    if world.progressive == 'on':
        world.itempool.extend(ItemFactory(progressivegloves))
    elif world.progressive == 'off':
        world.itempool.extend(ItemFactory(basicgloves))
    else:
        randvalue = random.randint(0, 1)
        if (randvalue == 0):
            world.itempool.extend(ItemFactory(progressivegloves))
        else:
            world.itempool.extend(ItemFactory(basicgloves))

    # insanity shuffle doesn't have fake LW/DW logic so for now guaranteed Mirror and Moon Pearl at the start
    if world.shuffle == 'insanity':
        world.push_item('Link\'s House', ItemFactory('Magic Mirror'), False)
        world.get_location('Link\'s House').event = True
        world.push_item('Sanctuary', ItemFactory('Moon Pearl'), False)
        world.get_location('Sanctuary').event = True
    else:
        world.itempool.extend(ItemFactory(['Magic Mirror', 'Moon Pearl']))

    if world.timer == 'display':
        world.clock_mode = 'stopwatch'

    if world.difficulty == 'normal':
        world.itempool.extend(ItemFactory(normalbaseitems))
        for i in range(0, 4):
            thisbottle = normalbottles[random.randint(0, 6)]
            world.itempool.append(ItemFactory(thisbottle))
        extraitems = 70
        if world.timer in ['timed', 'timed-countdown']:
            world.itempool.extend(ItemFactory(normaltimedother))
            extraitems = extraitems - 40
            world.clock_mode = 'stopwatch' if world.timer == 'timed' else 'countdown'
        elif world.timer == 'timed-ohko':
            world.itempool.extend(ItemFactory(normaltimedohko))
            extraitems = extraitems - 25
            world.clock_mode = 'ohko'
        if world.goal == 'triforcehunt':
            world.itempool.extend(ItemFactory(normaltriforcehunt))
            extraitems = extraitems - 30
            world.treasure_hunt_count = 20
            world.treasure_hunt_icon = 'Triforce Piece'
        if extraitems > 0:
            world.itempool.extend(ItemFactory(normalfirst15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(normalsecond15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(normalthird10extra))
            extraitems = extraitems - 10
        if extraitems > 0:
            world.itempool.extend(ItemFactory(normalfourth5extra))
            extraitems = extraitems - 5
        if extraitems > 0:
            world.itempool.extend(ItemFactory(normalfinal25extra))
            extraitems = extraitems - 25
        if world.progressive == 'on':
            world.itempool.extend(ItemFactory(normalprogressiveshield))
            world.itempool.extend(ItemFactory(normalprogressivearmor))
        elif world.progressive == 'off':
            world.itempool.extend(ItemFactory(normalbasicshield))
            world.itempool.extend(ItemFactory(normalbasicarmor))
        else:
            randvalue = random.randint(0, 1)
            if (randvalue == 0):
                world.itempool.extend(ItemFactory(normalprogressiveshield))
            else:
                world.itempool.extend(ItemFactory(normalbasicshield))
            randvalue = random.randint(0, 1)
            if (randvalue == 0):
                world.itempool.extend(ItemFactory(normalprogressivearmor))
            else:
                world.itempool.extend(ItemFactory(normalbasicarmor))
        if world.mode == 'swordless':
            world.itempool.extend(ItemFactory(normalswordless))
        elif world.mode == 'standard':
            if world.progressive == 'on':
                world.push_item('Link\'s Uncle',
                                ItemFactory('Progressive Sword'), False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(normalprogressivesword))
            elif world.progressive == 'off':
                world.push_item('Link\'s Uncle', ItemFactory('Fighter Sword'),
                                False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(normalbasicsword))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Progressive Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(normalprogressivesword))
                else:
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Fighter Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(normalbasicsword))
        else:
            if world.progressive == 'on':
                world.itempool.extend(ItemFactory(normalprogressivesword))
                world.itempool.extend(ItemFactory(['Progressive Sword']))
            elif world.progressive == 'off':
                world.itempool.extend(ItemFactory(normalbasicsword))
                world.itempool.extend(ItemFactory(['Fighter Sword']))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.itempool.extend(ItemFactory(normalprogressivesword))
                    world.itempool.extend(ItemFactory(['Progressive Sword']))
                else:
                    world.itempool.extend(ItemFactory(normalbasicsword))
                    world.itempool.extend(ItemFactory(['Fighter Sword']))

    elif world.difficulty == 'easy':
        world.itempool.extend(ItemFactory(easybaseitems))
        for i in range(0, 8):
            thisbottle = normalbottles[random.randint(0, 6)]
            world.itempool.append(ItemFactory(thisbottle))
        extraitems = 70
        if world.timer in ['timed', 'timed-countdown']:
            world.itempool.extend(ItemFactory(easytimedother))
            extraitems = extraitems - 40
            world.clock_mode = 'stopwatch' if world.timer == 'timed' else 'countdown'
        elif world.timer == 'timed-ohko':
            world.itempool.extend(ItemFactory(easytimedohko))
            extraitems = extraitems - 25
            world.clock_mode = 'ohko'
        if world.goal == 'triforcehunt':
            world.itempool.extend(ItemFactory(easytriforcehunt))
            extraitems = extraitems - 30
            world.treasure_hunt_count = 10
            world.treasure_hunt_icon = 'Triforce Piece'
        if extraitems == 0:
            world.itempool.extend(ItemFactory(easylimitedextra))
        else:
            world.itempool.extend(ItemFactory(easyextra))
            if world.timer in ['timed', 'timed-countdown']:
                world.itempool.extend(ItemFactory(easytimedotherextra))
        extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(easyfirst15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(easysecond10extra))
            extraitems = extraitems - 10
        if extraitems > 0:
            world.itempool.extend(ItemFactory(easythird5extra))
            extraitems = extraitems - 5
        if extraitems > 0:
            world.itempool.extend(ItemFactory(easyfinal25extra))
            extraitems = extraitems - 25
        if world.progressive == 'on':
            world.itempool.extend(ItemFactory(easyprogressiveshield))
            world.itempool.extend(ItemFactory(easyprogressivearmor))
        elif world.progressive == 'off':
            world.itempool.extend(ItemFactory(easybasicshield))
            world.itempool.extend(ItemFactory(easybasicarmor))
        else:
            randvalue = random.randint(0, 1)
            if (randvalue == 0):
                world.itempool.extend(ItemFactory(easyprogressiveshield))
            else:
                world.itempool.extend(ItemFactory(easybasicshield))
            randvalue = random.randint(0, 1)
            if (randvalue == 0):
                world.itempool.extend(ItemFactory(easyprogressivearmor))
            else:
                world.itempool.extend(ItemFactory(easybasicarmor))
        if world.mode == 'swordless':
            world.itempool.extend(ItemFactory(easyswordless))
        elif world.mode == 'standard':
            if world.progressive == 'on':
                world.push_item('Link\'s Uncle',
                                ItemFactory('Progressive Sword'), False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(easyprogressivesword))
            elif world.progressive == 'off':
                world.push_item('Link\'s Uncle', ItemFactory('Fighter Sword'),
                                False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(easybasicsword))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Progressive Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(easyprogressivesword))
                else:
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Fighter Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(easybasicsword))
        else:
            if world.progressive == 'on':
                world.itempool.extend(ItemFactory(easyprogressivesword))
                world.itempool.extend(ItemFactory(['Progressive Sword']))
            elif world.progressive == 'off':
                world.itempool.extend(ItemFactory(easybasicsword))
                world.itempool.extend(ItemFactory(['Fighter Sword']))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.itempool.extend(ItemFactory(easyprogressivesword))
                    world.itempool.extend(ItemFactory(['Progressive Sword']))
                else:
                    world.itempool.extend(ItemFactory(easybasicsword))
                    world.itempool.extend(ItemFactory(['Fighter Sword']))

    elif world.difficulty == 'hard':
        world.itempool.extend(ItemFactory(hardbaseitems))
        for i in range(0, 4):
            thisbottle = hardbottles[random.randint(0, 5)]
            world.itempool.append(ItemFactory(thisbottle))
        extraitems = 80
        if world.timer in ['timed', 'timed-countdown']:
            world.itempool.extend(ItemFactory(hardtimedother))
            extraitems = extraitems - 40
            world.clock_mode = 'stopwatch' if world.timer == 'timed' else 'countdown'
        elif world.timer == 'timed-ohko':
            world.itempool.extend(ItemFactory(hardtimedohko))
            extraitems = extraitems - 25
            world.clock_mode = 'ohko'
        if world.goal == 'triforcehunt':
            world.itempool.extend(ItemFactory(hardtriforcehunt))
            extraitems = extraitems - 40
            world.treasure_hunt_count = 30
            world.treasure_hunt_icon = 'Triforce Piece'
        if extraitems > 0:
            world.itempool.extend(ItemFactory(hardfirst20extra))
            extraitems = extraitems - 20
        if extraitems > 0:
            world.itempool.extend(ItemFactory(hardsecond20extra))
            extraitems = extraitems - 20
        if extraitems > 0:
            world.itempool.extend(ItemFactory(hardthird20extra))
            extraitems = extraitems - 20
        if extraitems > 0:
            world.itempool.extend(ItemFactory(hardfinal20extra))
            extraitems = extraitems - 20
        world.itempool.extend(ItemFactory(hardarmor))
        if world.progressive == 'on':
            world.itempool.extend(ItemFactory(hardprogressiveshield))
        elif world.progressive == 'off':
            world.itempool.extend(ItemFactory(hardbasicshield))
        else:
            randvalue = random.randint(0, 1)
            if (randvalue == 0):
                world.itempool.extend(ItemFactory(hardprogressiveshield))
            else:
                world.itempool.extend(ItemFactory(hardbasicshield))
        if world.mode == 'swordless':
            world.itempool.extend(ItemFactory(hardswordless))
        elif world.mode == 'standard':
            if world.progressive == 'on':
                world.push_item('Link\'s Uncle',
                                ItemFactory('Progressive Sword'), False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(hardprogressivesword))
            elif world.progressive == 'off':
                world.push_item('Link\'s Uncle', ItemFactory('Fighter Sword'),
                                False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(hardbasicsword))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Progressive Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(hardprogressivesword))
                else:
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Fighter Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(hardbasicsword))
        else:
            if world.progressive == 'on':
                world.itempool.extend(ItemFactory(hardprogressivesword))
                world.itempool.extend(ItemFactory(['Progressive Sword']))
            elif world.progressive == 'off':
                world.itempool.extend(ItemFactory(hardbasicsword))
                world.itempool.extend(ItemFactory(['Fighter Sword']))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.itempool.extend(ItemFactory(hardprogressivesword))
                    world.itempool.extend(ItemFactory(['Progressive Sword']))
                else:
                    world.itempool.extend(ItemFactory(hardbasicsword))
                    world.itempool.extend(ItemFactory(['Fighter Sword']))

    elif world.difficulty == 'expert':
        world.itempool.extend(ItemFactory(expertbaseitems))
        thisbottle = hardbottles[random.randint(0, 5)]
        for i in range(0, 4):
            world.itempool.append(ItemFactory(thisbottle))
        extraitems = 80
        if world.timer in ['timed', 'timed-countdown']:
            world.itempool.extend(ItemFactory(experttimedother))
            extraitems = extraitems - 40
            world.clock_mode = 'stopwatch' if world.timer == 'timed' else 'countdown'
        elif world.timer == 'timed-ohko':
            world.itempool.extend(ItemFactory(experttimedohko))
            extraitems = extraitems - 25
            world.clock_mode = 'ohko'
        if world.goal == 'triforcehunt':
            world.itempool.extend(ItemFactory(experttriforcehunt))
            extraitems = extraitems - 40
            world.treasure_hunt_count = 40
            world.treasure_hunt_icon = 'Triforce Piece'
        if extraitems > 0:
            world.itempool.extend(ItemFactory(expertfirst15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(expertsecond25extra))
            extraitems = extraitems - 25
        if extraitems > 0:
            world.itempool.extend(ItemFactory(expertthird15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(expertfinal25extra))
            extraitems = extraitems - 25
        if world.mode == 'swordless':
            world.itempool.extend(ItemFactory(expertswordless))
        elif world.mode == 'standard':
            if world.progressive == 'on':
                world.push_item('Link\'s Uncle',
                                ItemFactory('Progressive Sword'), False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(expertprogressivesword))
            elif world.progressive == 'off':
                world.push_item('Link\'s Uncle', ItemFactory('Fighter Sword'),
                                False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(expertbasicsword))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Progressive Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(expertprogressivesword))
                else:
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Fighter Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(expertbasicsword))
        else:
            if world.progressive == 'on':
                world.itempool.extend(ItemFactory(expertprogressivesword))
                world.itempool.extend(ItemFactory(['Progressive Sword']))
            elif world.progressive == 'off':
                world.itempool.extend(ItemFactory(expertbasicsword))
                world.itempool.extend(ItemFactory(['Fighter Sword']))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.itempool.extend(ItemFactory(expertprogressivesword))
                    world.itempool.extend(ItemFactory(['Progressive Sword']))
                else:
                    world.itempool.extend(ItemFactory(expertbasicsword))
                    world.itempool.extend(ItemFactory(['Fighter Sword']))

    elif world.difficulty == 'insane':
        world.itempool.extend(ItemFactory(insanebaseitems))
        thisbottle = hardbottles[random.randint(0, 5)]
        for i in range(0, 4):
            world.itempool.append(ItemFactory(thisbottle))
        extraitems = 90
        if world.timer in ['timed', 'timed-countdown']:
            world.itempool.extend(ItemFactory(insanetimedother))
            extraitems = extraitems - 40
            world.clock_mode = 'stopwatch' if world.timer == 'timed' else 'countdown'
        elif world.timer == 'timed-ohko':
            world.itempool.extend(ItemFactory(insanetimedohko))
            extraitems = extraitems - 25
            world.clock_mode = 'ohko'
        if world.goal == 'triforcehunt':
            world.itempool.extend(ItemFactory(insanetriforcehunt))
            extraitems = extraitems - 50
            world.treasure_hunt_count = 50
            world.treasure_hunt_icon = 'Triforce Piece'
        if extraitems > 0:
            world.itempool.extend(ItemFactory(insanefirst15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(insanesecond25extra))
            extraitems = extraitems - 25
        if extraitems > 0:
            world.itempool.extend(ItemFactory(insanethird10extra))
            extraitems = extraitems - 10
        if extraitems > 0:
            world.itempool.extend(ItemFactory(insanefourth15extra))
            extraitems = extraitems - 15
        if extraitems > 0:
            world.itempool.extend(ItemFactory(insanefinal25extra))
            extraitems = extraitems - 25
        if world.mode == 'swordless':
            world.itempool.extend(ItemFactory(insaneswordless))
        elif world.mode == 'standard':
            if world.progressive == 'on':
                world.push_item('Link\'s Uncle',
                                ItemFactory('Progressive Sword'), False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(insaneprogressivesword))
            elif world.progressive == 'off':
                world.push_item('Link\'s Uncle', ItemFactory('Fighter Sword'),
                                False)
                world.get_location('Link\'s Uncle').event = True
                world.itempool.extend(ItemFactory(insanebasicsword))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Progressive Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(insaneprogressivesword))
                else:
                    world.push_item('Link\'s Uncle',
                                    ItemFactory('Fighter Sword'), False)
                    world.get_location('Link\'s Uncle').event = True
                    world.itempool.extend(ItemFactory(insanebasicsword))
        else:
            if world.progressive == 'on':
                world.itempool.extend(ItemFactory(insaneprogressivesword))
                world.itempool.extend(ItemFactory(['Progressive Sword']))
            elif world.progressive == 'off':
                world.itempool.extend(ItemFactory(insanebasicsword))
                world.itempool.extend(ItemFactory(['Fighter Sword']))
            else:
                randvalue = random.randint(0, 1)
                if (randvalue == 0):
                    world.itempool.extend(ItemFactory(insaneprogressivesword))
                    world.itempool.extend(ItemFactory(['Progressive Sword']))
                else:
                    world.itempool.extend(ItemFactory(insanebasicsword))
                    world.itempool.extend(ItemFactory(['Fighter Sword']))

    if world.goal == 'pedestal':
        world.push_item('Master Sword Pedestal', ItemFactory('Triforce'),
                        False)
        world.get_location('Master Sword Pedestal').event = True

    # shuffle medallions
    mm_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)]
    tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)]
    world.required_medallions = (mm_medallion, tr_medallion)

    # distribute crystals
    crystals = ItemFactory([
        'Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1',
        'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7', 'Crystal 5',
        'Crystal 6'
    ])
    crystal_locations = [
        world.get_location('Turtle Rock - Prize'),
        world.get_location('Eastern Palace - Prize'),
        world.get_location('Desert Palace - Prize'),
        world.get_location('Tower of Hera - Prize'),
        world.get_location('Palace of Darkness - Prize'),
        world.get_location('Thieves Town - Prize'),
        world.get_location('Skull Woods - Prize'),
        world.get_location('Swamp Palace - Prize'),
        world.get_location('Ice Palace - Prize'),
        world.get_location('Misery Mire - Prize')
    ]

    random.shuffle(crystal_locations)

    fill_restrictive(world, world.get_all_state(keys=True), crystal_locations,
                     crystals)