def test_create_message_for_hint_relative_item(echoes_game_patches, blank_pickup, players_config, distance_precise, distance_text, reference_precision, reference_name): patches = echoes_game_patches.assign_new_pickups([ (PickupIndex(5), PickupTarget(blank_pickup, 0)), (PickupIndex(15), PickupTarget( dataclasses.replace(blank_pickup, name="Reference Pickup"), 0)), ]) hint = Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.RELATIVE_TO_INDEX, HintItemPrecision.DETAILED, include_owner=False, relative=RelativeDataItem(distance_precise, PickupIndex(15), reference_precision)), PickupIndex(5)) namer = EchoesHintNamer({0: patches}, PlayersConfiguration(0, {0: "You"})) exporter = HintExporter(namer, random.Random(0), ["A Joke"]) # Run result = exporter.create_message_for_hint(hint, {0: patches}, players_config, True) # Assert assert result == ( f'The &push;&main-color=#FF6705B3;Blank Pickup&pop; can be found ' f'&push;&main-color=#FF3333;{distance_text} {7 + (distance_precise or 0)} ' f'rooms&pop; away from {reference_name}.')
def test_create_hints_item_dark_temple_keys_cross_game( blank_pickup, echoes_resource_database, echoes_game_patches, default_echoes_configuration, prime_game_patches, default_prime_configuration, ): # Setup players_config = PlayersConfiguration( player_index=0, player_names={ 0: "Player 1", 1: "Player 2", }, ) keys = [ dataclasses.replace( blank_pickup, progression=((echoes_resource_database.get_item(item), 1), )) for item in echoes_items.DARK_TEMPLE_KEY_ITEMS[1] ] echoes_patches = dataclasses.replace( echoes_game_patches, configuration=default_echoes_configuration, pickup_assignment={ PickupIndex(14): PickupTarget(keys[0], 0), PickupIndex(80): PickupTarget(keys[2], 0), }) prime_patches = dataclasses.replace( prime_game_patches, configuration=default_prime_configuration, pickup_assignment={ PickupIndex(23): PickupTarget(keys[1], 0), }) hint = Hint(HintType.RED_TEMPLE_KEY_SET, None, dark_temple=HintDarkTemple.TORVUS_BOG) namer = EchoesHintNamer({ 0: echoes_patches, 1: prime_patches }, players_config) exporter = HintExporter(namer, random.Random(0), ["A Joke"]) # Run result = exporter.create_message_for_hint(hint, { 0: echoes_patches, 1: prime_patches }, players_config, True) # Assert assert result == ( 'The keys to &push;&main-color=#FF6705B3;Dark Torvus Temple&pop; can be found ' 'in &push;&main-color=#FF3333;Chozo Ruins&pop;, ' '&push;&main-color=#FF3333;Dark Torvus Bog&pop; and ' '&push;&main-color=#FF3333;Temple Grounds&pop;.')
def test_create_hints_light_suit_location(empty_patches, 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.LIGHT_SUIT_LOCATION, PrecisionPair(location, item[0]), pickup_index) }) rng = MagicMock() # Run result = item_hints.create_hints(patches, world_list, rng) # Assert if location is HintLocationPrecision.WRONG_GAME and item[ 0] is HintItemPrecision.WRONG_GAME: message = "&push;&main-color=#45F731;Warning! Dark Aether's atmosphere is dangerous!" \ " Energized Safe Zones don't last forever!&pop;" else: message = f"U-Mos's reward for returning the Sanctuary energy is {item[1]}." assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
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 test_game_session_request_pickups_one_action( mock_session_description: PropertyMock, mock_get_resource_database: MagicMock, mock_get_pickup_target: MagicMock, flask_app, two_player_session, echoes_resource_database): # Setup sio = MagicMock() sio.get_current_user.return_value = database.User.get_by_id(1234) pickup = PickupEntry("A", PickupModel(echoes_resource_database.game_enum, "AmmoModel"), ItemCategory.TEMPLE_KEY, ItemCategory.KEY, progression=((echoes_resource_database.item[0], 1), )) mock_get_pickup_target.return_value = PickupTarget(pickup=pickup, player=0) mock_get_resource_database.return_value = echoes_resource_database # Run result = game_session.game_session_request_pickups(sio, 1) # Assert mock_get_resource_database.assert_called_once_with( mock_session_description.return_value, 0) mock_get_pickup_target.assert_called_once_with( mock_session_description.return_value, 1, 0) assert result == { "game": "prime2", "pickups": [{ 'provider_name': 'Other Name', 'pickup': 'C@fSK*4Fga_C{94xPb=' }] }
def test_multi_create_pickup_data_for_self(pickup_for_create_pickup_data): # Setup solo = pickup_exporter.PickupExporterSolo( pickup_exporter.GenericAcquiredMemo()) creator = pickup_exporter.PickupExporterMulti( solo, MagicMock(), PlayersConfiguration(0, { 0: "You", 1: "Someone" })) model = MagicMock() resource_a = ItemResourceInfo(1, "A", "A", 10, None) resource_b = ItemResourceInfo(2, "B", "B", 10, None) # Run data = creator.create_details( PickupIndex(10), PickupTarget(pickup_for_create_pickup_data, 0), pickup_for_create_pickup_data, PickupModelStyle.ALL_VISIBLE, "Scan Text", model) # Assert assert data == pickup_exporter.ExportedPickupDetails( index=PickupIndex(10), scan_text="Your Scan Text", hud_text=['A acquired!', 'B acquired!'], conditional_resources=[ ConditionalResources("A", None, ((resource_a, 1), )), ConditionalResources("B", resource_a, ((resource_b, 1), )), ], conversion=[], model=model, )
def test_game_session_collect_pickup_for_self( mock_session_description: PropertyMock, mock_get_resource_database: MagicMock, mock_get_pickup_target: MagicMock, mock_emit: MagicMock, flask_app, two_player_session, echoes_resource_database): sio = MagicMock() sio.get_current_user.return_value = database.User.get_by_id(1234) pickup = PickupEntry( "A", 1, ItemCategory.TEMPLE_KEY, ItemCategory.KEY, (ConditionalResources(None, None, ((echoes_resource_database.item[0], 1), )), )) mock_get_resource_database.return_value = echoes_resource_database mock_get_pickup_target.return_value = PickupTarget(pickup, 0) # Run with flask_app.test_request_context(): result = game_session.game_session_collect_locations(sio, 1, (0, )) # Assert assert result is None mock_emit.assert_not_called() mock_get_pickup_target.assert_called_once_with( mock_session_description.return_value, 0, 0) with pytest.raises(peewee.DoesNotExist): database.GameSessionTeamAction.get(session=two_player_session, provider_row=0, provider_location_index=0)
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
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 _create_pickup_list(cosmetic_patches: EchoesCosmeticPatches, configuration: BaseConfiguration, game: GameDescription, patches: GamePatches, players_config: PlayersConfiguration, rng: Random): useless_target = PickupTarget( pickup_creator.create_echoes_useless_pickup(game.resource_database), players_config.player_index) if cosmetic_patches.disable_hud_popup: memo_data = _simplified_memo_data() else: memo_data = default_prime2_memo_data() pickup_list = pickup_exporter.export_all_indices( patches, useless_target, game.world_list, rng, configuration.pickup_model_style, configuration.pickup_model_data_source, exporter=pickup_exporter.create_pickup_exporter( game, memo_data, players_config), visual_etm=pickup_creator.create_visual_etm(), ) return [ echoes_pickup_details_to_patcher(details, rng) for details in pickup_list ]
def test_multi_create_pickup_data_for_other(pickup_for_create_pickup_data): # Setup multi = ItemResourceInfo(10, "Multiworld", "Multiworld", 30, None) solo = pickup_exporter.PickupExporterSolo( pickup_exporter.GenericAcquiredMemo()) creator = pickup_exporter.PickupExporterMulti( solo, multi, PlayersConfiguration(0, { 0: "You", 1: "Someone" })) model = MagicMock() resource_a = ItemResourceInfo(1, "A", "A", 10, None) resource_b = ItemResourceInfo(2, "B", "B", 10, None) # Run data = creator.create_details( PickupIndex(10), PickupTarget(pickup_for_create_pickup_data, 1), pickup_for_create_pickup_data, PickupModelStyle.ALL_VISIBLE, "Scan Text", model) # Assert assert data == pickup_exporter.ExportedPickupDetails( index=PickupIndex(10), scan_text="Someone's Scan Text", hud_text=['Sent Cake to Someone!'], conditional_resources=[ ConditionalResources(None, None, ((multi, 11), )), ], conversion=[], model=model, )
def _distribute_remaining_items(rng: Random, filler_results: Dict[int, FillerPlayerResult], ) -> Dict[int, GamePatches]: unassigned_pickup_nodes = [] all_remaining_pickups = [] assignments: Dict[int, PickupAssignment] = {} for player, filler_result in filler_results.items(): for pickup_node in filter_unassigned_pickup_nodes(filler_result.game.world_list.all_nodes, filler_result.patches.pickup_assignment): unassigned_pickup_nodes.append((player, pickup_node)) all_remaining_pickups.extend(zip([player] * len(filler_result.unassigned_pickups), filler_result.unassigned_pickups)) assignments[player] = {} rng.shuffle(unassigned_pickup_nodes) rng.shuffle(all_remaining_pickups) if len(all_remaining_pickups) > len(unassigned_pickup_nodes): raise InvalidConfiguration( "Received {} remaining pickups, but there's only {} unassigned locations.".format( len(all_remaining_pickups), len(unassigned_pickup_nodes) )) for (node_player, node), (pickup_player, pickup) in zip(unassigned_pickup_nodes, all_remaining_pickups): assignments[node_player][node.pickup_index] = PickupTarget(pickup, pickup_player) return { index: filler_results[index].patches.assign_pickup_assignment(assignment) for index, assignment in assignments.items() }
def test_multi_create_pickup_data_for_other(pickup_for_create_pickup_data): # Setup creator = patcher_file.PickupCreatorMulti( MagicMock(), patcher_file._SimplifiedMemo(), PlayersConfiguration(0, { 0: "You", 1: "Someone" })) # Run data = creator.create_pickup_data( PickupIndex(10), PickupTarget(pickup_for_create_pickup_data, 1), pickup_for_create_pickup_data, PickupModelStyle.ALL_VISIBLE, "Scan Text") # Assert assert data == { 'conditional_resources': [], 'convert': [], 'hud_text': ['Sent Cake to Someone!'], 'resources': [ { 'amount': 11, 'index': 74 }, ], 'scan': "Someone's Scan Text", }
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, 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 test_game_session_collect_pickup_other(flask_app, two_player_session, echoes_resource_database, locations_to_collect, exists, mock_emit_session_update, mocker): mock_emit: MagicMock = mocker.patch("flask_socketio.emit", autospec=True) mock_get_pickup_target: MagicMock = mocker.patch("randovania.server.game_session._get_pickup_target", autospec=True) mock_session_description: PropertyMock = mocker.patch("randovania.server.database.GameSession.layout_description", new_callable=PropertyMock) sio = MagicMock() sio.get_current_user.return_value = database.User.get_by_id(1234) mock_get_pickup_target.return_value = PickupTarget(MagicMock(), 1) for existing_id in exists: database.GameSessionTeamAction.create(session=two_player_session, provider_row=0, provider_location_index=existing_id, receiver_row=0) # Run with flask_app.test_request_context(): result = game_session.game_session_collect_locations(sio, 1, locations_to_collect) # Assert assert result is None mock_get_pickup_target.assert_has_calls([ call(mock_session_description.return_value, 0, location) for location in locations_to_collect ]) for location in locations_to_collect: database.GameSessionTeamAction.get(session=two_player_session, provider_row=0, provider_location_index=location) if exists == locations_to_collect: mock_emit.assert_not_called() mock_emit_session_update.assert_not_called() else: mock_emit.assert_called_once_with("game_has_update", {"session": 1, "row": 1, }, room=f"game-session-1-1235") mock_emit_session_update.assert_called_once_with(database.GameSession.get(id=1))
def test_solo_create_pickup_data(pickup_for_create_pickup_data): # Setup creator = patcher_file.PickupCreatorSolo(MagicMock(), patcher_file._SimplifiedMemo()) # Run data = creator.create_pickup_data( PickupIndex(10), PickupTarget(pickup_for_create_pickup_data, 0), pickup_for_create_pickup_data, PickupModelStyle.ALL_VISIBLE, "Scan Text") # Assert assert data == { 'conditional_resources': [{ 'item': 1, 'resources': [{ 'amount': 1, 'index': 2 }] }], 'convert': [], 'hud_text': ['Sugar acquired!', 'Salt acquired!'], 'resources': [{ 'amount': 1, 'index': 1 }], 'scan': 'Scan Text', }
def _distribute_remaining_items( rng: Random, filler_results: Dict[int, FillerPlayerResult], ) -> Dict[int, GamePatches]: unassigned_pickup_nodes = [] all_remaining_pickups = [] assignments: Dict[int, PickupAssignment] = {} for index, filler_result in filler_results.items(): for pickup_node in filter_unassigned_pickup_nodes( filler_result.game.world_list.all_nodes, filler_result.patches.pickup_assignment): unassigned_pickup_nodes.append((index, pickup_node)) all_remaining_pickups.extend( zip([index] * len(filler_result.unassigned_pickups), filler_result.unassigned_pickups)) assignments[index] = {} rng.shuffle(unassigned_pickup_nodes) rng.shuffle(all_remaining_pickups) for (node_player, node), (pickup_player, pickup) in zip(unassigned_pickup_nodes, all_remaining_pickups): assignments[node_player][node.pickup_index] = PickupTarget( pickup, pickup_player) return { index: filler_results[index].patches.assign_pickup_assignment(assignment) for index, assignment in assignments.items() }
def test_game_session_request_pickups_one_action( mock_session_description: PropertyMock, mock_get_resource_database: MagicMock, mock_get_pickup_target: MagicMock, flask_app, two_player_session, echoes_resource_database): # Setup sio = MagicMock() sio.get_current_user.return_value = database.User.get_by_id(1234) pickup = PickupEntry( "A", 1, ItemCategory.TEMPLE_KEY, ItemCategory.KEY, (ConditionalResources(None, None, ((echoes_resource_database.item[0], 1), )), )) mock_get_pickup_target.return_value = PickupTarget(pickup=pickup, player=0) mock_get_resource_database.return_value = echoes_resource_database # Run result = game_session.game_session_request_pickups(sio, 1) # Assert mock_get_resource_database.assert_called_once_with( mock_session_description.return_value, 0) mock_get_pickup_target.assert_called_once_with( mock_session_description.return_value, 1, 0) assert result == [{'provider_name': 'Other Name', 'pickup': '6c8P51ON~'}]
def test_create_message_for_hint_relative_area(echoes_game_patches, blank_pickup, players_config, echoes_hint_exporter, offset, distance_text): patches = echoes_game_patches.assign_new_pickups([ (PickupIndex(5), PickupTarget(blank_pickup, 0)), ]) hint = Hint( HintType.LOCATION, PrecisionPair(HintLocationPrecision.RELATIVE_TO_AREA, HintItemPrecision.DETAILED, include_owner=False, relative=RelativeDataArea( offset, AreaIdentifier("Torvus Bog", "Great Bridge"), HintRelativeAreaName.NAME)), PickupIndex(5)) namer = EchoesHintNamer({0: patches}, PlayersConfiguration(0, {0: "You"})) exporter = HintExporter(namer, random.Random(0), ["A Joke"]) # Run result = exporter.create_message_for_hint(hint, {0: patches}, players_config, True) # Assert assert result == ( f'The &push;&main-color=#FF6705B3;Blank Pickup&pop; can be found ' f'&push;&main-color=#FF3333;{distance_text} {10 + (offset or 0)} rooms&pop; away from ' f'Torvus Bog - Great Bridge.')
def test_create_hints_guardians(empty_patches, pickup_index_and_guardian, pickup, item, players_config): # Setup asset_id = 1000 pickup_index, guardian = pickup_index_and_guardian 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.GUARDIAN, item[0]), pickup_index) }) rng = MagicMock() # Run result = item_hints.create_hints({0: patches}, players_config, world_list, rng) # Assert message = f"{guardian} is guarding {item[1]}." assert result == [{ 'asset_id': asset_id, 'strings': [message, '', message] }]
def test_solo_create_pickup_data(pickup_for_create_pickup_data): # Setup creator = pickup_exporter.PickupExporterSolo(pickup_exporter.GenericAcquiredMemo()) model = MagicMock() resource_a = ItemResourceInfo(0, "A", "A", 10) resource_b = ItemResourceInfo(1, "B", "B", 10) # Run data = creator.create_details(PickupIndex(10), PickupTarget(pickup_for_create_pickup_data, 0), pickup_for_create_pickup_data, PickupModelStyle.ALL_VISIBLE, "Scan Text", model) # Assert assert data == pickup_exporter.ExportedPickupDetails( index=PickupIndex(10), scan_text="Scan Text", hud_text=['A acquired!', 'B acquired!'], conditional_resources=[ ConditionalResources("A", None, ((resource_a, 1),)), ConditionalResources("B", resource_a, ((resource_b, 1),)), ], conversion=[], model=model, other_player=False, original_pickup=pickup_for_create_pickup_data, )
def create_pickup_hint( pickup_assignment: PickupAssignment, world_list: WorldList, precision: HintItemPrecision, target: Optional[PickupTarget], players_config: PlayersConfiguration, include_owner: bool, ) -> PickupHint: """ :param pickup_assignment: :param world_list: :param precision: :param target: :param players_config: :param include_owner: :return: """ if target is None: target = PickupTarget( pickup=PickupEntry( name="Energy Transfer Module", progression=tuple(), model=PickupModel( game=RandovaniaGame.METROID_PRIME_ECHOES, name="EnergyTransferModule", ), item_category=USELESS_ITEM_CATEGORY, broad_category=USELESS_ITEM_CATEGORY, ), player=players_config.player_index, ) if precision is HintItemPrecision.GENERAL_CATEGORY: details = target.pickup.item_category.general_details elif precision is HintItemPrecision.PRECISE_CATEGORY: details = target.pickup.item_category.hint_details elif precision is HintItemPrecision.BROAD_CATEGORY: details = target.pickup.broad_category.hint_details elif precision is HintItemPrecision.DETAILED: details = _calculate_determiner(pickup_assignment, target.pickup, world_list), target.pickup.name elif precision is HintItemPrecision.NOTHING: details = "an ", "item" else: raise ValueError(f"Unknown precision: {precision}") determiner = Determiner(details[0]) player = None if include_owner and players_config.is_multiworld: player = players_config.player_names[target.player] return PickupHint(determiner, player, details[1])
def _assign_pickup_somewhere(action: PickupEntry, current_player: PlayerState, player_states: List[PlayerState], rng: Random, all_locations_weighted: WeightedLocations, ) -> str: """ Assigns a PickupEntry to a free, collected PickupIndex or as a starting item. :param action: :param current_player: :param player_states: :param rng: :return: """ assert action in current_player.pickups_left if all_locations_weighted and (current_player.num_random_starting_items_placed >= current_player.configuration.minimum_random_starting_items): index_owner_state, pickup_index = select_element_with_weight(all_locations_weighted, rng) index_owner_state.assign_pickup(pickup_index, PickupTarget(action, current_player.index)) # Place a hint for the new item hint_location = _calculate_hint_location_for_action( action, UncollectedState.from_reach(index_owner_state.reach), pickup_index, rng, index_owner_state.scan_asset_initial_pickups, ) if hint_location is not None: index_owner_state.reach.state.patches = index_owner_state.reach.state.patches.assign_hint( hint_location, Hint(HintType.LOCATION, None, pickup_index)) if pickup_index in index_owner_state.reach.state.collected_pickup_indices: current_player.reach.advance_to(current_player.reach.state.assign_pickup_resources(action)) else: # FIXME: isn't that condition always true? pass spoiler_entry = pickup_placement_spoiler_entry(current_player.index, action, index_owner_state.game, pickup_index, hint_location, index_owner_state.index, len(player_states) > 1) else: current_player.num_random_starting_items_placed += 1 if (current_player.num_random_starting_items_placed > current_player.configuration.maximum_random_starting_items): raise UnableToGenerate("Attempting to place more extra starting items than the number allowed.") spoiler_entry = f"{action.name} as starting item" if len(player_states) > 1: spoiler_entry += f" for Player {current_player.index + 1}" current_player.reach.advance_to(current_player.reach.state.assign_pickup_to_starting_items(action)) return spoiler_entry
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 create_data(self) -> dict: db = self.game useless_target = PickupTarget(pickup_creator.create_nothing_pickup(db.resource_database), self.players_config.player_index) pickup_list = pickup_exporter.export_all_indices( self.patches, useless_target, db.world_list, self.rng, self.configuration.pickup_model_style, self.configuration.pickup_model_data_source, exporter=pickup_exporter.create_pickup_exporter(db, pickup_exporter.GenericAcquiredMemo(), self.players_config), visual_etm=pickup_creator.create_visual_etm(), ) gameplay_patch_list = [field.name for field in dataclasses.fields(self.configuration.patches)] cosmetic_patch_list = [field.name for field in dataclasses.fields(self.cosmetic_patches)] cosmetic_patch_list.remove("music") specific_patches = {} for patch in gameplay_patch_list: specific_patches[patch] = getattr(self.configuration.patches, patch) for patch in cosmetic_patch_list: specific_patches[patch] = getattr(self.cosmetic_patches, patch) if self.cosmetic_patches.music != MusicMode.VANILLA: specific_patches[self.cosmetic_patches.music.value] = True starting_point = self.patches.starting_location starting_area = db.world_list.area_by_area_location(starting_point) starting_save_index = starting_area.extra["save_index"] starting_location_info = { "starting_region": starting_point.world_name, "starting_save_station_index": starting_save_index, } return { "pickups": [ sm_pickup_details_to_patcher(detail) for detail in pickup_list ], "starting_items": [ sm_starting_items_to_patcher(item, qty) for item, qty in self.patches.starting_items.as_resource_gain() ], "specific_patches": specific_patches, "starting_conditions": starting_location_info }
async def create_player_pool(rng: Random, configuration: BaseConfiguration, player_index: int, num_players: int, rng_required: bool = True) -> PlayerPool: game = filtered_database.game_description_for_layout( configuration).get_mutable() game_generator = game.game.generator game.resource_database = game_generator.bootstrap.patch_resource_database( game.resource_database, configuration) base_patches = game_generator.base_patches_factory.create_base_patches( configuration, rng, game, num_players > 1, player_index=player_index, rng_required=rng_required) base_patches = dock_weakness_distributor.distribute_pre_fill_weaknesses( base_patches) base_patches = await game_generator.hint_distributor.assign_pre_filler_hints( base_patches, PreFillParams( rng, configuration, game, num_players > 1, ), rng_required=rng_required) pool_results = pool_creator.calculate_pool_results( configuration, game.resource_database, base_patches, rng, rng_required=rng_required) target_assignment = [(index, PickupTarget(pickup, player_index)) for index, pickup in pool_results.assignment.items()] patches = base_patches.assign_new_pickups( target_assignment).assign_extra_initial_items( pool_results.initial_resources.as_resource_gain()) return PlayerPool( game=game, game_generator=game_generator, configuration=configuration, patches=patches, pickups=pool_results.pickups, )
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_add_relative_hint(echoes_game_description, echoes_game_patches, precise_distance, location_precision, echoes_item_database): # Setup rng = Random(5000) target_precision = MagicMock(spec=HintItemPrecision) precision = MagicMock(spec=HintItemPrecision) patches = echoes_game_patches.assign_new_pickups([ (PickupIndex(8), PickupTarget( _make_pickup(echoes_item_database.item_categories["movement"]), 0)), ]) hint_distributor = EchoesHintDistributor() if location_precision == HintLocationPrecision.RELATIVE_TO_AREA: max_distance = 8 data = RelativeDataArea( None if precise_distance else 3, # Was Industrial Site AreaIdentifier("Temple Grounds", "Hive Chamber A"), precision, ) else: max_distance = 20 data = RelativeDataItem( None if precise_distance else 11, PickupIndex(8), precision, ) # Run result = hint_distributor.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))