def test_create_hints_item_joke(empty_patches, players_config): # Setup asset_id = 1000 logbook_node, _, world_list = _create_world_list(asset_id, PickupIndex(50)) patches = dataclasses.replace( empty_patches, hints={ world_list.identifier_for_node(logbook_node): Hint(HintType.JOKE, None) }) rng = MagicMock() namer = EchoesHintNamer({0: patches}, players_config) # Run result = hints.create_patches_hints({0: patches}, players_config, world_list, namer, rng) # Assert joke = "While walking, holding L makes you move faster." message = f"&push;&main-color=#45F731;{joke}&pop;" assert result[0]['strings'][0] == message assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
async def test_show_dialog_for_prime3_layout(skip_qtbot, mocker, corruption_game_description, empty_patches): mock_execute_dialog = mocker.patch("randovania.gui.lib.async_dialog.execute_dialog", new_callable=AsyncMock) mock_clipboard: MagicMock = mocker.patch("randovania.gui.lib.common_qt_lib.set_clipboard") options = MagicMock() options.options_for_game.return_value.cosmetic_patches = CorruptionCosmeticPatches() window = GameDetailsWindow(None, options) window.player_index_combo.addItem("Current", 0) skip_qtbot.addWidget(window) target = MagicMock() target.pickup.name = "Boost Ball" patches = dataclasses.replace(empty_patches, starting_location=corruption_game_description.starting_location) for i in range(100): patches.pickup_assignment[PickupIndex(i)] = target window.layout_description = MagicMock() window.layout_description.all_patches = {0: patches} # Run await window._show_dialog_for_prime3_layout() # Assert mock_execute_dialog.assert_awaited_once() mock_clipboard.assert_called_once()
def test_create_hints_nothing(empty_patches, players_config): # Setup asset_id = 1000 pickup_index = PickupIndex(0) logbook_node, _, world_list = _create_world_list(asset_id, pickup_index) patches = dataclasses.replace(empty_patches, hints={ logbook_node.resource(): Hint( HintType.LOCATION, PrecisionPair( HintLocationPrecision.DETAILED, HintItemPrecision.DETAILED), pickup_index) }) rng = MagicMock() # Run result = item_hints.create_hints({0: patches}, players_config, world_list, rng) # Assert message = ( "The &push;&main-color=#FF6705B3;Energy Transfer Module&pop; can be found in " "&push;&main-color=#FF3333;World - Area&pop;.") assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
def test_create_hints_item_location(empty_patches, players_config, pickup, item, location): # Setup asset_id = 1000 pickup_index = PickupIndex(50) logbook_node, _, world_list = _create_world_list(asset_id, pickup_index) patches = dataclasses.replace(empty_patches, pickup_assignment={ pickup_index: PickupTarget(pickup, 0), }, hints={ logbook_node.resource(): Hint(HintType.LOCATION, PrecisionPair(location[0], item[0]), pickup_index) }) rng = MagicMock() # Run result = item_hints.create_hints({0: patches}, players_config, world_list, rng) # Assert message = "{} can be found in {}.".format(item[1][0].upper() + item[1][1:], location[1]) # message = "The Flying Ing Cache in {} contains {}.".format(location[1], item[1]) assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
def test_create_hints_light_suit_location(empty_patches, players_config, pickup, item): # Setup asset_id = 1000 pickup_index = PickupIndex(50) logbook_node, _, world_list = _create_world_list(asset_id, pickup_index) patches = dataclasses.replace( empty_patches, pickup_assignment={ pickup_index: PickupTarget(pickup, 0), }, hints={ logbook_node.resource(): Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.LIGHT_SUIT_LOCATION, item[0]), pickup_index) }) rng = MagicMock() # Run result = item_hints.create_hints({0: patches}, players_config, world_list, rng) # Assert message = f"U-Mos's reward for returning the Sanctuary energy is {item[1]}." assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
def g(index, loc): return ( PickupIndex(index), PrecisionPair(loc, HintItemPrecision.DETAILED, include_owner=False), )
def test_create_hints_item_dark_temple_keys(empty_patches, players_config, echoes_game_description, pickup, indices, expected_message): # Setup db = echoes_game_description.resource_database keys = [ (PickupIndex(index), dataclasses.replace(pickup, resources=(ConditionalResources( None, None, ((db.get_item(item), 1), )), ))) for index, item in zip(indices, echoes_items.DARK_TEMPLE_KEY_ITEMS[1]) ] patches = dataclasses.replace(empty_patches, pickup_assignment={ pickup_index: PickupTarget(key, 0) for pickup_index, key in keys }) hint = Hint(HintType.RED_TEMPLE_KEY_SET, None, dark_temple=HintDarkTemple.TORVUS_BOG) # Run result = item_hints.create_message_for_hint( hint, {0: patches}, players_config, None, {}, echoes_game_description.world_list) # Assert assert result == expected_message
async def known_collected_locations( self, executor: MemoryOperationExecutor, ) -> Tuple[Set[PickupIndex], List[DolRemotePatch]]: """Fetches pickup indices that have been collected. The list may return less than all collected locations, depending on implementation details. This function also returns a list of remote patches that must be performed via `execute_remote_patches`. """ multiworld_magic_item = self.game.resource_database.multiworld_magic_item if multiworld_magic_item is None: return set(), [] memory_ops = await self._memory_op_for_items(executor, [multiworld_magic_item]) op_result = await executor.perform_single_memory_operation(*memory_ops) magic_inv = InventoryItem(*struct.unpack(">II", op_result)) if magic_inv.amount > 0: self.logger.info( f"magic item was at {magic_inv.amount}/{magic_inv.capacity}") locations = {PickupIndex(magic_inv.amount - 1)} patches = [ DolRemotePatch([], all_prime_dol_patches. adjust_item_amount_and_capacity_patch( self.version.powerup_functions, self.game.game, multiworld_magic_item.extra["item_id"], -magic_inv.amount, )) ] return locations, patches else: return set(), []
def test_run_validated_hud_text(): # Setup rng = MagicMock() rng.randint.return_value = 0 details = pickup_exporter.ExportedPickupDetails( index=PickupIndex(0), scan_text="scan", hud_text=["Energy Transfer Module acquired!"], conditional_resources=[ ConditionalResources(None, None, ()), ], conversion=[], model=PickupModel( game=RandovaniaGame.METROID_PRIME_ECHOES, name="EnergyTransferModule", ), other_player=False, original_pickup=None, ) # Run data = patch_data_factory.echoes_pickup_details_to_patcher(details, rng) # Assert assert data['hud_text'] == ['Run validated!']
async def test_show_dialog_for_prime3_layout(skip_qtbot, mocker, corruption_game_description): mock_execute_dialog = mocker.patch( "randovania.gui.lib.async_dialog.execute_dialog", new_callable=AsyncMock) mock_clipboard: MagicMock = mocker.patch( "PySide2.QtWidgets.QApplication.clipboard") window = SeedDetailsWindow(None, MagicMock()) window.player_index_combo.addItem("Current", 0) skip_qtbot.addWidget(window) collections.namedtuple("MockPickup", ["name"]) target = MagicMock() target.pickup.name = "Boost Ball" patches = corruption_game_description.create_game_patches() for i in range(100): patches.pickup_assignment[PickupIndex(i)] = target window.layout_description = MagicMock() window.layout_description.all_patches = {0: patches} # Run await window._show_dialog_for_prime3_layout() # Assert mock_execute_dialog.assert_awaited_once() mock_clipboard.return_value.setText.assert_called_once()
def test_pickup_data_for_pb_expansion_unlocked(echoes_item_database, echoes_resource_database): # Setup pickup = pickup_creator.create_ammo_expansion( echoes_item_database.ammo["Power Bomb Expansion"], [2], False, echoes_resource_database, ) creator = pickup_exporter.PickupExporterSolo(patch_data_factory._simplified_memo_data()) # Run details = creator.export(PickupIndex(0), PickupTarget(pickup, 0), pickup, PickupModelStyle.ALL_VISIBLE) result = patch_data_factory.echoes_pickup_details_to_patcher(details, MagicMock()) # Assert assert result == { "pickup_index": 0, "scan": "Power Bomb Expansion. Provides 2 Power Bombs and 1 Item Percentage", "model": {"game": "prime2", "name": "PowerBombExpansion"}, "hud_text": ["Power Bomb Expansion acquired!"], 'resources': [{'amount': 2, 'index': 43}, {'amount': 1, 'index': 47}], "conditional_resources": [], "convert": [], }
def from_json(cls, value: dict, game: RandovaniaGame) -> "AvailableLocationsConfiguration": return cls( randomization_mode=RandomizationMode(value["randomization_mode"]), excluded_indices=frozenset( PickupIndex(item) for item in value["excluded_indices"]), game=game, )
def from_json(cls, data) -> "GameSessionAction": return GameSessionAction( provider=data["provider"], provider_row=data["provider_row"], receiver=data["receiver"], pickup=data["pickup"], location=PickupIndex(data["location"]), time=datetime.datetime.fromisoformat(data["time"]), )
def from_json(cls, value) -> "Hint": return Hint( hint_type=HintType(value["hint_type"]), precision=PrecisionPair( location=HintLocationPrecision(value["location_precision"]), item=HintItemPrecision(value["item_precision"]), ), target=PickupIndex(value["target"]), )
def test_add_relative_hint(echoes_game_description, empty_patches, location_precision): # Setup rng = Random(5000) target_precision = MagicMock() precise_distance = MagicMock() precision = MagicMock() patches = empty_patches.assign_pickup_assignment({ PickupIndex(8): PickupTarget(_make_pickup(ItemCategory.MOVEMENT), 0), }) if location_precision == HintLocationPrecision.RELATIVE_TO_AREA: max_distance = 8 data = RelativeDataArea( precise_distance, AreaLocation(0x3BFA3EFF, 0x62AC8AC4), precision, ) else: max_distance = 20 data = RelativeDataItem( precise_distance, PickupIndex(8), precision, ) # Run result = runner.add_relative_hint(echoes_game_description.world_list, patches, rng, PickupIndex(1), target_precision, location_precision, precise_distance, precision, max_distance=max_distance) # Assert pair = PrecisionPair(location_precision, target_precision, include_owner=False, relative=data) assert result == Hint(HintType.LOCATION, pair, PickupIndex(1))
async def _show_dialog_for_prime3_layout(self): from randovania.games.prime3.patcher import gollop_corruption_patcher from randovania.games.prime3.layout.corruption_cosmetic_patches import CorruptionCosmeticPatches from randovania.games.prime3.layout.corruption_configuration import CorruptionConfiguration from randovania.game_description import default_database cosmetic = typing.cast( CorruptionCosmeticPatches, self._options.options_for_game(RandovaniaGame.METROID_PRIME_CORRUPTION).cosmetic_patches, ) configuration = typing.cast( CorruptionConfiguration, self.layout_description.get_preset(self.current_player_index).configuration, ) patches = self.layout_description.all_patches[self.current_player_index] game = default_database.game_description_for(RandovaniaGame.METROID_PRIME_CORRUPTION) pickup_names = [] for index in range(game.world_list.num_pickup_nodes): p_index = PickupIndex(index) if p_index in patches.pickup_assignment: name = patches.pickup_assignment[p_index].pickup.name else: name = "Missile Expansion" pickup_names.append(name) layout_string = gollop_corruption_patcher.layout_string_for_items(pickup_names) starting_location = patches.starting_location starting_items = patches.starting_items.duplicate() starting_items.add_resource_gain([ (game.resource_database.get_item_by_name("Suit Type"), cosmetic.player_suit.value), ]) if configuration.start_with_corrupted_hypermode: hypermode_original = 0 else: hypermode_original = 1 commands = "\n".join([ f'set seed="{layout_string}"', f'set "starting_items={gollop_corruption_patcher.starting_items_for(starting_items, hypermode_original)}"', f'set "starting_location={gollop_corruption_patcher.starting_location_for(game, starting_location)}"', f'set "random_door_colors={str(cosmetic.random_door_colors).lower()}"', f'set "random_welding_colors={str(cosmetic.random_welding_colors).lower()}"', ]) dialog_text = ( "There is no integrated patcher for Metroid Prime 3: Corruption games.\n" "Download the randomizer for it from #corruption-general in the Metroid Prime Randomizer Discord, " "and use the following commands as a seed.\n\n" "\n{}").format(commands) message_box = ScrollLabelDialog(dialog_text, "Commands for patcher", self) message_box.resize(750, 200) message_box.label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) common_qt_lib.set_clipboard(commands) await async_dialog.execute_dialog(message_box)
def test_filter_usable_locations(state_for_blank, must_be_local, num_assigned_pickups): state_for_blank.configuration = dataclasses.replace( state_for_blank.configuration, first_progression_must_be_local=must_be_local) state_for_blank.num_assigned_pickups = num_assigned_pickups locations_weighted = { (state_for_blank, PickupIndex(0)): 1, (MagicMock(), PickupIndex(0)): 1, } # Run filtered = state_for_blank.filter_usable_locations(locations_weighted) # Assert if must_be_local and num_assigned_pickups == 0: assert filtered == {(state_for_blank, PickupIndex(0)): 1} else: assert filtered == locations_weighted
async def test_run_filler( echoes_game_description, default_layout_configuration, mocker, ): # Setup rng = Random(5000) status_update = MagicMock() logbook_nodes = [ node for node in echoes_game_description.world_list.all_nodes if isinstance(node, LogbookNode) ] player_pools = { 0: create_player_pool(rng, default_layout_configuration, 0, 1), } initial_pickup_count = len(player_pools[0].pickups) patches = echoes_game_description.create_game_patches() patches = patches.assign_hint( logbook_nodes[0].resource(), Hint(HintType.LOCATION, None, PickupIndex(0))) action_log = (MagicMock(), MagicMock()) player_state = MagicMock() player_state.index = 0 player_state.game = player_pools[0].game player_state.pickups_left = runner._split_expansions( player_pools[0].pickups)[0] player_state.scan_asset_initial_pickups = {} mocker.patch( "randovania.generator.filler.runner.retcon_playthrough_filler", autospec=True, return_value=({ player_state: patches }, action_log)) # Run filler_result = await runner.run_filler(rng, player_pools, status_update) assert filler_result.action_log == action_log assert len(filler_result.player_results) == 1 result_patches = filler_result.player_results[0].patches remaining_items = filler_result.player_results[0].unassigned_pickups # Assert assert len(result_patches.hints) == len(logbook_nodes) assert [ hint for hint in result_patches.hints.values() if hint.precision is None ] == [] assert initial_pickup_count == len(remaining_items) + len( result_patches.pickup_assignment.values())
def _pickup_node(): return PickupNode( pickup_index=PickupIndex(1), major_location=True, identifier=NodeIdentifier.create("W", "A", "Pickup (Ultra Beam)"), heal=False, location=None, layers=("default", ), description="", extra={}, )
def test_create_message_for_hint_relative_item(echoes_game_description, pickup, players_config, distance_precise, distance_text, reference_precision, reference_name): world_list = echoes_game_description.world_list patches = echoes_game_description.create_game_patches( ).assign_pickup_assignment({ PickupIndex(5): PickupTarget(pickup, 0), PickupIndex(15): PickupTarget(dataclasses.replace(pickup, name="Reference Pickup"), 0), }) hint_name_creator = LocationHintCreator(world_list, None, None) location_formatters = { HintLocationPrecision.RELATIVE_TO_INDEX: RelativeItemFormatter(world_list, patches, players_config), } hint = Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.RELATIVE_TO_INDEX, HintItemPrecision.DETAILED, include_owner=False, relative=RelativeDataItem(distance_precise, PickupIndex(15), reference_precision)), PickupIndex(5)) # Run result = item_hints.create_message_for_hint(hint, {0: patches}, players_config, hint_name_creator, location_formatters, world_list) # Assert assert result == ( f'The &push;&main-color=#FF6705B3;Pickup&pop; can be found ' f'&push;&main-color=#FF3333;{distance_text} {7 + distance_precise} rooms&pop; away from {reference_name}.' )
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "BitPackPickupEntryList": result = [] index_mapping = metadata["index_mapping"] num_players = metadata["num_players"] for _ in range(len(index_mapping)): index = PickupIndex(decoder.decode_single(255)) target_player = bitpacking.decode_int_with_limits(decoder, (num_players,)) pickup = BitPackPickupEntry.bit_pack_unpack(decoder, index_mapping[index], metadata["database"]) result.append((index, PickupTarget(pickup, target_player))) return BitPackPickupEntryList(result, num_players, metadata["database"])
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "BitPackPickupEntryList": result = [] index_mapping = metadata["index_mapping"] for _ in range(len(index_mapping)): index = PickupIndex(decoder.decode_single(255)) pickup = BitPackPickupEntry.bit_pack_unpack( decoder, index_mapping[index], metadata["database"]) result.append((index, pickup)) return BitPackPickupEntryList(result, metadata["database"])
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata): randomization_mode = RandomizationMode.bit_pack_unpack(decoder, metadata) if bitpacking.decode_bool(decoder): indices = bitpacking.decode_sorted_array_elements(decoder, _ALL_INDICES) else: indices = [] return AvailableLocationsConfiguration( randomization_mode=randomization_mode, excluded_indices=frozenset(PickupIndex(item) for item in indices), )
def from_json(cls, name: str, value: dict) -> "MajorItem": return cls( name=name, item_category=ItemCategory(value["item_category"]), model_index=value["model_index"], progression=tuple(value["progression"]), ammo_index=tuple(value.get("ammo", [])), converts_indices=tuple(value.get("converts_indices", [])), required=value.get("required", False), original_index=PickupIndex(value["original_index"]) if "original_index" in value else None, probability_offset=value["probability_offset"], )
def test_create_hints_item_location(echoes_game_patches, blank_pickup, item, location, owner, is_multiworld, echoes_game_description, monkeypatch): # Setup asset_id = 1000 pickup_index = PickupIndex(50) logbook_node, _, world_list = _create_world_list(asset_id, pickup_index) monkeypatch.setattr(echoes_game_description, "world_list", world_list) players_config = PlayersConfiguration( player_index=0, player_names={ i: f"Player {i + 1}" for i in range(int(is_multiworld) + 1) }, ) location_precision, determiner, item_name = item if owner and is_multiworld: determiner = "&push;&main-color=#d4cc33;Player 1&pop;'s" patches = dataclasses.replace( echoes_game_patches, pickup_assignment={ pickup_index: PickupTarget(blank_pickup, 0), }, hints={ world_list.identifier_for_node(logbook_node): Hint( HintType.LOCATION, PrecisionPair(location[0], location_precision, include_owner=owner), pickup_index, ) }) rng = MagicMock() namer = EchoesHintNamer({0: patches}, players_config) # Run result = hints.create_patches_hints({0: patches}, players_config, world_list, namer, rng) # Assert message = "{} {} can be found in {}.".format(determiner, item_name, location[1]) # message = "The Flying Ing Cache in {} contains {}.".format(location[1], item[1]) assert result[0]['strings'][0] == message assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
def test_prime1_pickup_details_to_patcher_shiny_missile( prime1_resource_database, other_player: bool): # Setup rng = MagicMock() rng.randint.return_value = 0 detail = pickup_exporter.ExportedPickupDetails( index=PickupIndex(15), scan_text="Your Missile Expansion. Provides 5 Missiles", hud_text=["Missile Expansion acquired!"], conditional_resources=[ ConditionalResources( None, None, ((prime1_resource_database.get_item_by_name("Missile"), 6), ), ) ], conversion=[], model=PickupModel(RandovaniaGame.METROID_PRIME, "Missile"), other_player=other_player, original_pickup=None, ) if other_player: shiny_stuff = { 'model': { 'game': 'prime1', 'name': 'Missile' }, 'scanText': 'Your Missile Expansion. Provides 5 Missiles', 'hudmemoText': 'Missile Expansion acquired!', } else: shiny_stuff = { 'model': { 'game': 'prime1', 'name': 'Shiny Missile' }, 'scanText': 'Your Shiny Missile Expansion. Provides 5 Missiles', 'hudmemoText': 'Shiny Missile Expansion acquired!', } # Run result = prime1_pickup_details_to_patcher(detail, False, rng) # Assert assert result == { 'type': 'Missile', 'currIncrease': 6, 'maxIncrease': 6, 'respawn': False, **shiny_stuff, }
def test_create_message_for_hint_relative_area(echoes_game_description, pickup, players_config, distance_precise, distance_text): world_list = echoes_game_description.world_list patches = echoes_game_description.create_game_patches( ).assign_pickup_assignment({ PickupIndex(5): PickupTarget(pickup, 0), }) hint_name_creator = LocationHintCreator(world_list, None, None) location_formatters = { HintLocationPrecision.RELATIVE_TO_AREA: RelativeAreaFormatter(world_list, patches) } hint = Hint( HintType.LOCATION, PrecisionPair( HintLocationPrecision.RELATIVE_TO_AREA, HintItemPrecision.DETAILED, include_owner=False, relative=RelativeDataArea(distance_precise, AreaLocation(1039999561, 3822429534), HintRelativeAreaName.NAME)), PickupIndex(5)) # Run result = item_hints.create_message_for_hint(hint, {0: patches}, players_config, hint_name_creator, location_formatters, world_list) # Assert assert result == ( f'The &push;&main-color=#FF6705B3;Pickup&pop; can be found ' f'&push;&main-color=#FF3333;{distance_text} 10 rooms&pop; away from Torvus Bog - Great Bridge.' )
def _describe_action(action: GameSessionTeamAction) -> dict: provider: int = action.provider_row receiver: int = action.receiver_row time = datetime.datetime.fromisoformat(action.time) target = description.all_patches[provider].pickup_assignment[ PickupIndex(action.provider_location_index)] message = ( f"{location_to_name[provider]} found {target.pickup.name} " f"for {location_to_name[receiver]}.") return { "message": message, "time": time.astimezone(datetime.timezone.utc).isoformat(), }
def test_add_hints_precision(empty_patches): failed_relative_provider = MagicMock(return_value=None) relative_hint_provider = MagicMock() player_state = MagicMock() rng = MagicMock() hints = [ Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.DETAILED, HintItemPrecision.DETAILED, include_owner=False), PickupIndex(1)), Hint(HintType.LOCATION, None, PickupIndex(2)), Hint(HintType.LOCATION, None, PickupIndex(3)), ] nc = NodeIdentifier.create initial_patches = empty_patches for i, hint in enumerate(hints): initial_patches = initial_patches.assign_hint(nc("w", "a", f"{i}"), hint) hint_distributor = EchoesHintDistributor() hint_distributor._get_relative_hint_providers = MagicMock( return_value=[failed_relative_provider, relative_hint_provider]) # Run result = hint_distributor.add_hints_precision(player_state, initial_patches, rng) # Assert failed_relative_provider.assert_called_once_with(player_state, initial_patches, rng, PickupIndex(2)) relative_hint_provider.assert_called_once_with(player_state, initial_patches, rng, PickupIndex(3)) assert result.hints == { nc("w", "a", "0"): Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.DETAILED, HintItemPrecision.DETAILED, include_owner=False), PickupIndex(1)), nc("w", "a", "1"): Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.WORLD_ONLY, HintItemPrecision.PRECISE_CATEGORY, include_owner=True), PickupIndex(2)), nc("w", "a", "2"): relative_hint_provider.return_value, }
def export_all_indices( patches: GamePatches, useless_target: PickupTarget, pickup_count: int, rng: Random, model_style: PickupModelStyle, data_source: PickupModelDataSource, exporter: PickupExporter, visual_etm: PickupEntry, ) -> List[ExportedPickupDetails]: """ Creates the patcher data for all pickups in the game :param patches: :param useless_target: :param pickup_count: :param rng: :param model_style: :param data_source: :param exporter: :param visual_etm: :return: """ pickup_assignment = patches.pickup_assignment pickup_list = list(pickup_assignment.values()) rng.shuffle(pickup_list) pickups = [ exporter.export( PickupIndex(i), pickup_assignment.get(PickupIndex(i), useless_target), _get_visual_model(i, pickup_list, data_source, visual_etm), model_style, ) for i in range(pickup_count) ] return pickups