Ejemplo n.º 1
0
def dungeon_reentry_rules(world, player, clip: Entrance, dungeon_region: str,
                          dungeon_exit: str):
    fix_dungeon_exits = world.fix_palaceofdarkness_exit[player]
    fix_fake_worlds = world.fix_fake_world[player]

    dungeon_entrance = [
        r for r in world.get_region(dungeon_region, player).entrances
        if r.name != clip.name
    ][0]
    if not fix_dungeon_exits:  # vanilla, simple, restricted, dungeonssimple; should never have fake worlds fix
        # Dungeons are only shuffled among themselves. We need to check SW, MM, and AT because they can't be reentered trivially.
        if dungeon_entrance.name == 'Skull Woods Final Section':
            set_rule(
                clip, lambda state: False
            )  # entrance doesn't exist until you fire rod it from the other side
        elif dungeon_entrance.name == 'Misery Mire':
            add_rule(clip, lambda state: state.has_sword(player) and state.
                     has_misery_mire_medallion(player))  # open the dungeon
        elif dungeon_entrance.name == 'Agahnims Tower':
            add_rule(clip, lambda state: state.has('Cape', player) or state.
                     has_beam_sword(player) or state.has(
                         'Beat Agahnim 1', player))  # kill/bypass barrier
        # Then we set a restriction on exiting the dungeon, so you can't leave unless you got in normally.
        add_rule(world.get_entrance(dungeon_exit, player),
                 lambda state: dungeon_entrance.can_reach(state))
    elif not fix_fake_worlds:  # full, dungeonsfull; fixed dungeon exits, but no fake worlds fix
        # Entry requires the entrance's requirements plus a fake pearl, but you don't gain logical access to the surrounding region.
        add_rule(
            clip, lambda state: dungeon_entrance.access_rule(
                fake_pearl_state(state, player)))
        # exiting restriction
        add_rule(world.get_entrance(dungeon_exit, player),
                 lambda state: dungeon_entrance.can_reach(state))
Ejemplo n.º 2
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])
Ejemplo n.º 3
0
    def test_impossible_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[1].name, player1.id))
        set_rule(locations[0],
                 lambda state: state.has(items[0].name, player1.id))

        self.assertRaises(FillError, fill_restrictive, multi_world,
                          multi_world.state, player1.locations.copy(),
                          player1.prog_items.copy())
Ejemplo n.º 4
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)
Ejemplo n.º 5
0
    def set_rules(self):
        # SM G4 is logically required to access Ganon's Tower in SMZ3
        self.world.completion_condition[self.player] = lambda state: \
            self.smz3World.GetRegion("Ganon's Tower").CanEnter(state.smz3state[self.player]) and \
            self.smz3World.GetRegion("Ganon's Tower").TowerAscend(state.smz3state[self.player])

        for region in self.smz3World.Regions:
            entrance = self.world.get_entrance('Menu' + "->" + region.Name, self.player)
            set_rule(entrance, lambda state, region=region: region.CanEnter(state.smz3state[self.player]))
            for loc in region.Locations:
                l = self.locations[loc.Name]
                if self.world.accessibility[self.player] != 'locations':
                    l.always_allow = lambda state, item, loc=loc: \
                        item.game == "SMZ3" and \
                        loc.alwaysAllow(TotalSMZ3Item.Item(TotalSMZ3Item.ItemType[item.name], self.smz3World), state.smz3state[self.player])
                old_rule = l.item_rule
                l.item_rule = lambda item, loc=loc, region=region: (\
                    item.game != "SMZ3" or \
                    loc.allow(TotalSMZ3Item.Item(TotalSMZ3Item.ItemType[item.name], self.smz3World), None) and \
                        region.CanFill(TotalSMZ3Item.Item(TotalSMZ3Item.ItemType[item.name], self.smz3World))) and old_rule(item)
                set_rule(l, lambda state, loc=loc: loc.Available(state.smz3state[self.player]))
Ejemplo n.º 6
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])
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
    def test_multiplayer_rules_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)

        set_rule(
            player2.locations[1],
            lambda state: state.has(player2.prog_items[0].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, player2.prog_items[0])
        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, player1.prog_items[1])
Ejemplo n.º 9
0
    def test_circular_fill(self):
        multi_world = generate_multi_world()
        player1 = generate_player_data(multi_world, 1, 3, 3)

        item0 = player1.prog_items[0]
        item1 = player1.prog_items[1]
        item2 = player1.prog_items[2]
        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) and state.has(item2.name, player1.id)
        set_rule(loc1, lambda state: state.has(item0.name, player1.id))
        set_rule(loc2, lambda state: state.has(item1.name, player1.id))
        set_rule(loc0, lambda state: state.has(item2.name, player1.id))

        self.assertRaises(FillError, fill_restrictive, multi_world,
                          multi_world.state, player1.locations.copy(),
                          player1.prog_items.copy())
Ejemplo n.º 10
0
def underworld_glitches_rules(world, player):
    fix_dungeon_exits = world.fix_palaceofdarkness_exit[player]
    fix_fake_worlds = world.fix_fake_world[player]

    # Ice Palace Entrance Clip
    # This is the easiest one since it's a simple internal clip. Just need to also add melting to freezor chest since it's otherwise assumed.
    add_rule(world.get_entrance('Ice Palace Entrance Room', player),
             lambda state: state.can_bomb_clip(
                 world.get_region('Ice Palace (Entrance)', player), player),
             combine='or')
    add_rule(world.get_location('Ice Palace - Freezor Chest', player),
             lambda state: state.can_melt_things(player))

    # Kiki Skip
    kikiskip = world.get_entrance('Kiki Skip', player)
    set_rule(kikiskip,
             lambda state: state.can_bomb_clip(kikiskip.parent_region, player))
    dungeon_reentry_rules(world, player, kikiskip,
                          'Palace of Darkness (Entrance)',
                          'Palace of Darkness Exit')

    # Mire -> Hera -> Swamp
    # Using mire keys on other dungeon doors
    mire = world.get_region('Misery Mire (West)', player)
    mire_clip = lambda state: state.can_reach(
        'Misery Mire (West)', 'Region', player) and state.can_bomb_clip(
            mire, player) and state.has_fire_source(player)
    hera_clip = lambda state: state.can_reach(
        'Tower of Hera (Top)', 'Region', player) and state.can_bomb_clip(
            world.get_region('Tower of Hera (Top)', player), player)
    add_rule(world.get_entrance('Tower of Hera Big Key Door', player),
             lambda state: mire_clip(state) and state.has(
                 'Big Key (Misery Mire)', player),
             combine='or')
    add_rule(world.get_entrance('Swamp Palace Small Key Door', player),
             lambda state: mire_clip(state),
             combine='or')
    add_rule(world.get_entrance('Swamp Palace (Center)', player),
             lambda state: mire_clip(state) or hera_clip(state),
             combine='or')

    # Build the rule for SP moat.
    # We need to be able to s+q to old man, then go to either Mire or Hera at either Hera or GT.
    # First we require a certain type of entrance shuffle, then build the rule from its pieces.
    if not world.swamp_patch_required[player]:
        if world.shuffle[player] in [
                'vanilla', 'dungeonssimple', 'dungeonsfull', 'dungeonscrossed'
        ]:
            rule_map = {
                'Misery Mire (Entrance)': (lambda state: True),
                'Tower of Hera (Bottom)': (lambda state: state.can_reach(
                    'Tower of Hera Big Key Door', 'Entrance', player))
            }
            inverted = world.mode[player] == 'inverted'
            hera_rule = lambda state: (state.has('Moon Pearl', player) or not inverted) and \
                                      rule_map.get(world.get_entrance('Tower of Hera', player).connected_region.name, lambda state: False)(state)
            gt_rule = lambda state: (state.has('Moon Pearl', player) or inverted) and \
                                    rule_map.get(world.get_entrance(('Ganons Tower' if not inverted else 'Inverted Ganons Tower'), player).connected_region.name, lambda state: False)(state)
            mirrorless_moat_rule = lambda state: state.can_reach(
                'Old Man S&Q', 'Entrance', player) and mire_clip(state) and (
                    hera_rule(state) or gt_rule(state))
            add_rule(
                world.get_entrance('Swamp Palace Moat', player),
                lambda state: state.has('Magic Mirror', player
                                        ) or mirrorless_moat_rule(state))
        else:
            add_rule(world.get_entrance('Swamp Palace Moat', player),
                     lambda state: state.has('Magic Mirror', player))

    # Using the entrances for various ER types. Hera -> Swamp never matters because you can only logically traverse with the mire keys
    mire_to_hera = world.get_entrance('Mire to Hera Clip', player)
    mire_to_swamp = world.get_entrance('Hera to Swamp Clip', player)
    set_rule(mire_to_hera, mire_clip)
    set_rule(mire_to_swamp,
             lambda state: mire_clip(state) and state.has('Flippers', player))
    dungeon_reentry_rules(world, player, mire_to_hera,
                          'Tower of Hera (Bottom)', 'Tower of Hera Exit')
    dungeon_reentry_rules(world, player, mire_to_swamp,
                          'Swamp Palace (Entrance)', 'Swamp Palace Exit')