Esempio n. 1
0
def ShopSlotFill(world):
    shop_slots: Set[Location] = {
        location
        for shop_locations in (shop.region.locations for shop in world.shops)
        for location in shop_locations if location.shop_slot
    }
    removed = set()
    for location in shop_slots:
        slot_num = int(location.name[-1]) - 1
        shop: Shop = location.parent_region.shop
        if not shop.can_push_inventory(
                slot_num) or location.shop_slot_disabled:
            location.shop_slot_disabled = True
            removed.add(location)

    if removed:
        shop_slots -= removed

    if shop_slots:
        del shop_slots

        from Fill import swap_location_item
        # TODO: allow each game to register a blacklist to be used here?
        blacklist_words = {"Rupee"}
        blacklist_words = {
            item_name
            for item_name in item_table
            if any(blacklist_word in item_name
                   for blacklist_word in blacklist_words)
        }
        blacklist_words.add("Bee")

        locations_per_sphere = list(
            list(sphere) for sphere in world.get_spheres())

        # currently special care needs to be taken so that Shop.region.locations.item is identical to Shop.inventory
        # Potentially create Locations as needed and make inventory the only source, to prevent divergence
        cumu_weights = []
        shops_per_sphere = []
        candidates_per_sphere = []

        # sort spheres into piles of valid candidates and shops
        for sphere in locations_per_sphere:
            current_shops_slots = []
            current_candidates = []
            shops_per_sphere.append(current_shops_slots)
            candidates_per_sphere.append(current_candidates)
            for location in sphere:
                if location.shop_slot:
                    if not location.shop_slot_disabled:
                        current_shops_slots.append(location)
                elif not location.locked and not location.item.name in blacklist_words:
                    current_candidates.append(location)
            if cumu_weights:
                x = cumu_weights[-1]
            else:
                x = 0
            cumu_weights.append(len(current_candidates) + x)

            world.random.shuffle(current_candidates)

        del locations_per_sphere

        total_spheres = len(candidates_per_sphere)

        for i, current_shop_slots in enumerate(shops_per_sphere):
            if current_shop_slots:
                candidate_sphere_ids = list(range(i, total_spheres))
                for location in current_shop_slots:
                    shop: Shop = location.parent_region.shop
                    swapping_sphere_id = world.random.choices(
                        candidate_sphere_ids, cum_weights=cumu_weights[i:])[0]
                    swapping_sphere: list = candidates_per_sphere[
                        swapping_sphere_id]
                    for c in swapping_sphere:  # chosen item locations
                        if c.item_rule(location.item) and location.item_rule(
                                c.item):
                            swap_location_item(c, location, check_locked=False)
                            logger.debug(
                                f'Swapping {c} into {location}:: {location.item}'
                            )
                            break

                    else:
                        # This *should* never happen. But let's fail safely just in case.
                        logger.warning(
                            "Ran out of ShopShuffle Item candidate locations.")
                        location.shop_slot_disabled = True
                        continue

                    # remove candidate
                    swapping_sphere.remove(c)
                    cumu_weights[swapping_sphere_id] -= 1

                    item_name = location.item.name
                    if any(x in item_name for x in [
                            'Compass', 'Map', 'Single Bomb', 'Single Arrow',
                            'Piece of Heart'
                    ]):
                        price = world.random.randrange(1, 7)
                    elif any(x in item_name
                             for x in ['Arrow', 'Bomb', 'Clock']):
                        price = world.random.randrange(2, 14)
                    elif any(x in item_name for x in ['Small Key', 'Heart']):
                        price = world.random.randrange(4, 28)
                    else:
                        price = world.random.randrange(8, 56)

                    shop.push_inventory(
                        int(location.name[-1]) - 1, item_name, price * 5, 1,
                        location.item.player
                        if location.item.player != location.player else 0)
Esempio n. 2
0
def ShopSlotFill(world):
    shop_slots: Set[Location] = {location for shop_locations in (shop.region.locations for shop in world.shops)
                                 for location in shop_locations if location.shop_slot}
    removed = set()
    for location in shop_slots:
        slot_num = int(location.name[-1]) - 1
        shop: Shop = location.parent_region.shop
        if not shop.can_push_inventory(slot_num) or location.shop_slot_disabled:
            location.shop_slot_disabled = True
            removed.add(location)

    if removed:
        shop_slots -= removed

    if shop_slots:
        from Fill import swap_location_item
        # TODO: allow each game to register a blacklist to be used here?
        blacklist_words = {"Rupee"}
        blacklist_words = {item_name for item_name in item_table if any(
            blacklist_word in item_name for blacklist_word in blacklist_words)}
        blacklist_words.add("Bee")
        candidates_per_sphere = list(list(sphere) for sphere in world.get_spheres())

        candidate_condition = lambda location: not location.locked and \
                                               not location.shop_slot and \
                                               not location.item.name in blacklist_words

        # currently special care needs to be taken so that Shop.region.locations.item is identical to Shop.inventory
        # Potentially create Locations as needed and make inventory the only source, to prevent divergence
        cumu_weights = []

        for sphere in candidates_per_sphere:
            if cumu_weights:
                x = cumu_weights[-1]
            else:
                x = 0
            cumu_weights.append(len(sphere) + x)
            world.random.shuffle(sphere)

        for i, sphere in enumerate(candidates_per_sphere):
            current_shop_slots = [location for location in sphere if location.shop_slot and not location.shop_slot_disabled]
            if current_shop_slots:

                for location in current_shop_slots:
                    shop: Shop = location.parent_region.shop
                    # TODO: might need to implement trying randomly across spheres until canditates are exhausted.
                    # As spheres may be as small as one item.
                    swapping_sphere = world.random.choices(candidates_per_sphere[i:], cum_weights=cumu_weights[i:])[0]
                    for c in swapping_sphere:  # chosen item locations
                        if candidate_condition(c) and c.item_rule(location.item) and location.item_rule(c.item):
                            swap_location_item(c, location, check_locked=False)
                            logger.debug(f'Swapping {c} into {location}:: {location.item}')
                            break

                    else:
                        # This *should* never happen. But let's fail safely just in case.
                        logger.warning("Ran out of ShopShuffle Item candidate locations.")
                        location.shop_slot_disabled = True
                        continue
                    item_name = location.item.name
                    if any(x in item_name for x in ['Single Bomb', 'Single Arrow', 'Piece of Heart']):
                        price = world.random.randrange(1, 7)
                    elif any(x in item_name for x in ['Arrow', 'Bomb', 'Clock']):
                        price = world.random.randrange(2, 14)
                    elif any(x in item_name for x in ['Compass', 'Map', 'Small Key', 'Clock', 'Heart']):
                        price = world.random.randrange(4, 28)
                    else:
                        price = world.random.randrange(8, 56)

                    price *= 5
                    shop.push_inventory(int(location.name[-1]) - 1, item_name, price, 1,
                                        location.item.player if location.item.player != location.player else 0)
Esempio n. 3
0
def ShopSlotFill(world):
    shop_slots: Set[ALttPLocation] = {
        location
        for shop_locations in (shop.region.locations for shop in world.shops)
        for location in shop_locations if location.shop_slot is not None
    }
    removed = set()
    for location in shop_slots:
        shop: Shop = location.parent_region.shop
        if not shop.can_push_inventory(
                location.shop_slot) or location.shop_slot_disabled:
            location.shop_slot_disabled = True
            removed.add(location)

    if removed:
        shop_slots -= removed

    if shop_slots:
        logger.info("Filling LttP Shop Slots")
        del shop_slots

        from Fill import swap_location_item
        # TODO: allow each game to register a blacklist to be used here?
        blacklist_words = {"Rupee"}
        blacklist_words = {
            item_name
            for item_name in item_table
            if any(blacklist_word in item_name
                   for blacklist_word in blacklist_words)
        }
        blacklist_words.add("Bee")

        locations_per_sphere = list(
            sorted(sphere, key=lambda location: location.name)
            for sphere in world.get_spheres())

        # currently special care needs to be taken so that Shop.region.locations.item is identical to Shop.inventory
        # Potentially create Locations as needed and make inventory the only source, to prevent divergence
        cumu_weights = []
        shops_per_sphere = []
        candidates_per_sphere = []

        # sort spheres into piles of valid candidates and shops
        for sphere in locations_per_sphere:
            current_shops_slots = []
            current_candidates = []
            shops_per_sphere.append(current_shops_slots)
            candidates_per_sphere.append(current_candidates)
            for location in sphere:
                if location.shop_slot is not None:
                    if not location.shop_slot_disabled:
                        current_shops_slots.append(location)
                elif not location.locked and not location.item.name in blacklist_words:
                    current_candidates.append(location)
            if cumu_weights:
                x = cumu_weights[-1]
            else:
                x = 0
            cumu_weights.append(len(current_candidates) + x)

            world.random.shuffle(current_candidates)

        del locations_per_sphere

        for i, current_shop_slots in enumerate(shops_per_sphere):
            if current_shop_slots:
                # getting all candidates and shuffling them feels cpu expensive, there may be a better method
                candidates = [(location, i) for i, candidates in enumerate(
                    candidates_per_sphere[i:], start=i)
                              for location in candidates]
                world.random.shuffle(candidates)
                for location in current_shop_slots:
                    shop: Shop = location.parent_region.shop
                    for index, (c, swapping_sphere_id) in enumerate(
                            candidates):  # chosen item locations
                        if c.item_rule(location.item) and location.item_rule(
                                c.item):
                            swap_location_item(c, location, check_locked=False)
                            logger.debug(
                                f'Swapping {c} into {location}:: {location.item}'
                            )
                            # remove candidate
                            candidates_per_sphere[swapping_sphere_id].remove(c)
                            candidates.pop(index)
                            break

                    else:
                        # This *should* never happen. But let's fail safely just in case.
                        logger.warning(
                            "Ran out of ShopShuffle Item candidate locations.")
                        location.shop_slot_disabled = True
                        continue

                    item_name = location.item.name
                    if location.item.game != "A Link to the Past":
                        if location.item.advancement:
                            price = world.random.randrange(8, 56)
                        elif location.item.useful:
                            price = world.random.randrange(4, 28)
                        else:
                            price = world.random.randrange(2, 14)
                    elif any(x in item_name for x in [
                            'Compass', 'Map', 'Single Bomb', 'Single Arrow',
                            'Piece of Heart'
                    ]):
                        price = world.random.randrange(1, 7)
                    elif any(x in item_name
                             for x in ['Arrow', 'Bomb', 'Clock']):
                        price = world.random.randrange(2, 14)
                    elif any(x in item_name for x in ['Small Key', 'Heart']):
                        price = world.random.randrange(4, 28)
                    else:
                        price = world.random.randrange(8, 56)

                    shop.push_inventory(
                        location.shop_slot, item_name,
                        min(
                            int(price *
                                world.shop_price_modifier[location.player] /
                                100) * 5, 9999), 1, location.item.player
                        if location.item.player != location.player else 0)
                    if 'P' in world.shop_shuffle[location.player]:
                        price_to_funny_price(
                            world, shop.inventory[location.shop_slot],
                            location.player)