예제 #1
0
def test_create_translator_gates_field():
    # Setup
    gate_assignment = {
        TranslatorGate(1): SimpleResourceInfo(10, "LongA", "A",
                                              ResourceType.ITEM),
        TranslatorGate(3): SimpleResourceInfo(50, "LongB", "B",
                                              ResourceType.ITEM),
        TranslatorGate(4): SimpleResourceInfo(10, "LongA", "A",
                                              ResourceType.ITEM),
    }

    # Run
    result = claris_patcher_file._create_translator_gates_field(
        gate_assignment)

    # Assert
    assert result == [
        {
            "gate_index": 1,
            "translator_index": 10
        },
        {
            "gate_index": 3,
            "translator_index": 50
        },
        {
            "gate_index": 4,
            "translator_index": 10
        },
    ]
def test_gate_assignment_for_configuration_all_random(
        echoes_resource_database):
    # Setup
    violet = find_resource_info_with_long_name(echoes_resource_database.item,
                                               "Violet Translator")
    emerald = find_resource_info_with_long_name(echoes_resource_database.item,
                                                "Emerald Translator")

    configuration = MagicMock()
    configuration.translator_configuration.translator_requirement = {
        TranslatorGate(index): LayoutTranslatorRequirement.RANDOM
        for index in [1, 15, 23]
    }

    rng = MagicMock()
    rng.choice.side_effect = [
        LayoutTranslatorRequirement.EMERALD,
        LayoutTranslatorRequirement.VIOLET,
        LayoutTranslatorRequirement.EMERALD,
    ]

    # Run
    results = base_patches_factory.gate_assignment_for_configuration(
        configuration, echoes_resource_database, rng)

    # Assert
    assert results == {
        TranslatorGate(1): emerald,
        TranslatorGate(15): violet,
        TranslatorGate(23): emerald,
    }
예제 #3
0
def test_basic_search_with_translator_gate(has_translator: bool,
                                           echoes_resource_database):
    # Setup
    scan_visor = echoes_resource_database.get_item(10)

    node_a = GenericNode("Node A", True, None, 0)
    node_b = GenericNode("Node B", True, None, 1)
    node_c = GenericNode("Node C", True, None, 2)
    translator_node = TranslatorGateNode("Translator Gate", True, None, 3,
                                         TranslatorGate(1), scan_visor)

    world_list = WorldList([
        World("Test World", "Test Dark World", 1, [
            Area(
                "Test Area A", False, 10, 0, True,
                [node_a, node_b, node_c, translator_node], {
                    node_a: {
                        node_b: Requirement.trivial(),
                        translator_node: Requirement.trivial(),
                    },
                    node_b: {
                        node_a: Requirement.trivial(),
                    },
                    node_c: {
                        translator_node: Requirement.trivial(),
                    },
                    translator_node: {
                        node_a: Requirement.trivial(),
                        node_c: Requirement.trivial(),
                    },
                })
        ])
    ])
    game_specific = EchoesGameSpecific(energy_per_tank=100,
                                       safe_zone_heal_per_second=1,
                                       beam_configurations=(),
                                       dangerous_energy_tank=False)
    game = GameDescription(RandovaniaGame.PRIME2,
                           DockWeaknessDatabase([], [], [], []),
                           echoes_resource_database, game_specific,
                           Requirement.impossible(), None, {}, world_list)

    patches = game.create_game_patches()
    patches = patches.assign_gate_assignment({TranslatorGate(1): scan_visor})
    initial_state = State({scan_visor: 1 if has_translator else 0}, (), 99,
                          node_a, patches, None, echoes_resource_database,
                          game.world_list)

    # Run
    reach = reach_with_all_safe_resources(game, initial_state)

    # Assert
    if has_translator:
        assert set(
            reach.safe_nodes) == {node_a, node_b, translator_node, node_c}
    else:
        assert set(reach.safe_nodes) == {node_a, node_b}
def test_basic_search_with_translator_gate(has_translator: bool,
                                           echoes_resource_database):
    # Setup
    scan_visor = echoes_resource_database.get_by_type_and_index(
        ResourceType.ITEM, 10)

    node_a = GenericNode("Node A", True, 0)
    node_b = GenericNode("Node B", True, 1)
    node_c = GenericNode("Node C", True, 2)
    translator_node = TranslatorGateNode("Translator Gate", True, 3,
                                         TranslatorGate(1), scan_visor)

    world_list = WorldList([
        World("Test World", 1, [
            Area(
                "Test Area A", False, 10, 0,
                [node_a, node_b, node_c, translator_node], {
                    node_a: {
                        node_b: RequirementSet.trivial(),
                        translator_node: RequirementSet.trivial(),
                    },
                    node_b: {
                        node_a: RequirementSet.trivial(),
                    },
                    node_c: {
                        translator_node: RequirementSet.trivial(),
                    },
                    translator_node: {
                        node_a: RequirementSet.trivial(),
                        node_c: RequirementSet.trivial(),
                    },
                })
        ])
    ])
    game = GameDescription(0, "",
                           DockWeaknessDatabase([], [], [],
                                                []), echoes_resource_database,
                           RequirementSet.impossible(), None, {}, world_list)

    patches = GamePatches.with_game(game)
    patches = patches.assign_gate_assignment({TranslatorGate(1): scan_visor})
    initial_state = State({scan_visor: 1 if has_translator else 0}, (), 99,
                          node_a, patches, None, echoes_resource_database)

    # Run
    reach = reach_with_all_safe_resources(game, initial_state)

    # Assert
    if has_translator:
        assert set(
            reach.safe_nodes) == {node_a, node_b, translator_node, node_c}
    else:
        assert set(reach.safe_nodes) == {node_a, node_b}
예제 #5
0
    def __init__(self, editor: PresetEditor):
        super().__init__()
        self.setupUi(self)
        self._editor = editor

        randomizer_data = default_data.decode_randomizer_data()

        self.translators_layout.setAlignment(QtCore.Qt.AlignTop)
        self.translator_randomize_all_button.clicked.connect(
            self._on_randomize_all_gates_pressed)
        self.translator_vanilla_actual_button.clicked.connect(
            self._on_vanilla_actual_gates_pressed)
        self.translator_vanilla_colors_button.clicked.connect(
            self._on_vanilla_colors_gates_pressed)

        self._combo_for_gate = {}

        for i, gate in enumerate(randomizer_data["TranslatorLocationData"]):
            label = QtWidgets.QLabel(self.translators_scroll_contents)
            label.setText(gate["Name"])
            self.translators_layout.addWidget(label, 3 + i, 0, 1, 1)

            combo = QComboBox(self.translators_scroll_contents)
            combo.gate = TranslatorGate(gate["Index"])
            for item in iterate_enum(LayoutTranslatorRequirement):
                combo.addItem(item.long_name, item)
            combo.currentIndexChanged.connect(
                functools.partial(self._on_gate_combo_box_changed, combo))

            self.translators_layout.addWidget(combo, 3 + i, 1, 1, 2)
            self._combo_for_gate[combo.gate] = combo
    def setup_translators_elements(self):
        randomizer_data = default_data.decode_randomizer_data()

        self.always_up_gfmc_compound_check.stateChanged.connect(
            functools.partial(self._on_always_up_check_changed, "fixed_gfmc_compound"))
        self.always_up_torvus_temple_check.stateChanged.connect(
            functools.partial(self._on_always_up_check_changed, "fixed_torvus_temple"))
        self.always_up_great_temple_check.stateChanged.connect(
            functools.partial(self._on_always_up_check_changed, "fixed_great_temple"))

        self.translator_randomize_all_button.clicked.connect(self._on_randomize_all_gates_pressed)
        self.translator_vanilla_actual_button.clicked.connect(self._on_vanilla_actual_gates_pressed)
        self.translator_vanilla_colors_button.clicked.connect(self._on_vanilla_colors_gates_pressed)

        self._combo_for_gate = {}

        for i, gate in enumerate(randomizer_data["TranslatorLocationData"]):
            label = QLabel(self.translators_scroll_contents)
            label.setText(gate["Name"])
            self.translators_layout.addWidget(label, 3 + i, 0, 1, 1)

            combo = QComboBox(self.translators_scroll_contents)
            combo.gate = TranslatorGate(gate["Index"])
            for item in LayoutTranslatorRequirement:
                combo.addItem(item.long_name, item)
            combo.currentIndexChanged.connect(functools.partial(self._on_gate_combo_box_changed, combo))

            self.translators_layout.addWidget(combo, 3 + i, 1, 1, 2)
            self._combo_for_gate[combo.gate] = combo
예제 #7
0
def _find_gate_with_name(gate_name: str) -> TranslatorGate:
    from randovania.games.patchers import claris_patcher
    for items in claris_patcher.decode_randomizer_data(
    )["TranslatorLocationData"]:
        if items["Name"] == gate_name:
            return TranslatorGate(items["Index"])
    raise ValueError("Unknown gate name: {}".format(gate_name))
    def from_json(cls, value: dict) -> "TranslatorConfiguration":
        default = cls.default()

        params = copy.copy(value)

        translator_requirement = copy.copy(default.translator_requirement)
        for key, item in params.pop("translator_requirement").items():
            translator_requirement[TranslatorGate(
                int(key))] = LayoutTranslatorRequirement(item)

        return cls(translator_requirement, **params)
def test_gate_assignment_for_configuration_all_emerald(
        echoes_resource_database):
    # Setup
    emerald = find_resource_info_with_long_name(echoes_resource_database.item,
                                                "Emerald Translator")
    indices = [1, 15, 23]

    configuration = MagicMock()
    configuration.translator_configuration.translator_requirement = {
        TranslatorGate(index): LayoutTranslatorRequirement.EMERALD
        for index in indices
    }

    rng = MagicMock()

    # Run
    results = base_patches_factory.gate_assignment_for_configuration(
        configuration, echoes_resource_database, rng)

    # Assert
    assert results == {TranslatorGate(index): emerald for index in indices}
예제 #10
0
def _find_gate_with_name(gate_name: str) -> TranslatorGate:
    for items in default_data.decode_randomizer_data(
    )["TranslatorLocationData"]:
        if items["Name"] == gate_name:
            return TranslatorGate(items["Index"])
    raise ValueError("Unknown gate name: {}".format(gate_name))
예제 #11
0
    def create_new_node(self) -> Node:
        node_type = self.node_type_combo.currentData()
        name = self.name_edit.text()
        heal = self.heals_check.isChecked()
        location = None
        if self.location_group.isChecked():
            location = NodeLocation(self.location_x_spin.value(),
                                    self.location_y_spin.value(),
                                    self.location_z_spin.value())
        index = self.node.index

        if node_type == GenericNode:
            return GenericNode(name, heal, location, index)

        elif node_type == DockNode:
            return DockNode(
                name,
                heal,
                location,
                index,
                self.dock_index_spin.value(),
                DockConnection(
                    self.dock_connection_area_combo.currentData(
                    ).area_asset_id,
                    self.dock_connection_node_combo.currentData()),
                self.dock_weakness_combo.currentData(),
            )

        elif node_type == PickupNode:
            return PickupNode(
                name,
                heal,
                location,
                index,
                PickupIndex(self.pickup_index_spin.value()),
                self.major_location_check.isChecked(),
            )

        elif node_type == TeleporterNode:
            instance_id = self.teleporter_instance_id_edit.text()
            scan_asset_id = self.teleporter_scan_asset_id_edit.text()

            return TeleporterNode(
                name,
                heal,
                location,
                index,
                int(instance_id, 0) if instance_id != "" else None,
                AreaLocation(
                    self.teleporter_destination_world_combo.currentData(
                    ).world_asset_id,
                    self.teleporter_destination_area_combo.currentData().
                    area_asset_id),
                int(scan_asset_id, 0) if scan_asset_id != "" else None,
                self.teleporter_vanilla_name_edit.isChecked(),
                self.teleporter_editable_check.isChecked(),
            )

        elif node_type == EventNode:
            event = self.event_resource_combo.currentData()
            if event is None:
                raise ValueError(
                    "There are no events in the database, unable to create EventNode."
                )
            return EventNode(
                name,
                heal,
                location,
                index,
                event,
            )

        elif node_type == TranslatorGateNode:
            return TranslatorGateNode(
                name, heal, location, index,
                TranslatorGate(self.translator_gate_spin.value()),
                self._get_scan_visor())

        elif node_type == LogbookNode:
            lore_type: LoreType = self.lore_type_combo.currentData()
            if lore_type == LoreType.LUMINOTH_LORE:
                required_translator = self.logbook_extra_combo.currentData()
                if required_translator is None:
                    raise ValueError("Missing required translator.")
            else:
                required_translator = None

            if lore_type == LoreType.LUMINOTH_WARRIOR:
                hint_index = self.logbook_extra_combo.currentData()
            else:
                hint_index = None

            return LogbookNode(
                name, heal, location, index,
                int(self.logbook_string_asset_id_edit.text(), 0),
                self._get_scan_visor(), lore_type, required_translator,
                hint_index)

        elif node_type == PlayerShipNode:
            return PlayerShipNode(name, heal, location, index,
                                  self._unlocked_by_requirement,
                                  self._get_command_visor())

        else:
            raise RuntimeError(f"Unknown node type: {node_type}")
예제 #12
0
    def apply_previous_state(self, previous_state: Optional[dict]) -> bool:
        if previous_state is None:
            return False

        starting_location = None
        needs_starting_location = len(
            self.layout_configuration.starting_location.locations) > 1
        resource_db = self.game_description.resource_database
        translator_gates = {}

        try:
            pickup_name_to_pickup = {
                pickup.name: pickup
                for pickup in self._collected_pickups.keys()
            }
            quantity_to_change = {
                pickup_name_to_pickup[pickup_name]: quantity
                for pickup_name, quantity in
                previous_state["collected_pickups"].items()
            }
            previous_actions = [
                self.game_description.world_list.all_nodes[index]
                for index in previous_state["actions"]
            ]
            if needs_starting_location:
                starting_location = AreaLocation.from_json(
                    previous_state["starting_location"])

            elevators: Dict[Teleporter, Optional[AreaLocation]] = {
                Teleporter.from_json(item["teleporter"]):
                AreaLocation.from_json(item["data"])
                if item["data"] is not None else None
                for item in previous_state["elevators"]
            }
            if self.layout_configuration.game == RandovaniaGame.PRIME2:
                translator_gates = {
                    TranslatorGate(int(gate)):
                    (resource_db.get_item(item)
                     if item is not None else self._undefined_item)
                    for gate, item in
                    previous_state["translator_gates"].items()
                }
        except KeyError:
            return False

        self.setup_starting_location(starting_location)

        for teleporter, area_location in elevators.items():
            combo = self._elevator_id_to_combo[teleporter]
            if area_location is None:
                combo.setCurrentIndex(0)
                continue
            for i in range(combo.count()):
                if area_location == combo.itemData(i):
                    combo.setCurrentIndex(i)
                    break

        for gate, item in translator_gates.items():
            combo = self._translator_gate_to_combo[gate]
            for i in range(combo.count()):
                if item == combo.itemData(i):
                    combo.setCurrentIndex(i)
                    break

        self.bulk_change_quantity(quantity_to_change)
        self._add_new_actions(previous_actions)
        return True
예제 #13
0
    def read_node(self, data: Dict) -> Node:
        name: str = data["name"]
        heal: bool = data["heal"]
        node_type: int = data["node_type"]
        self.generic_index += 1

        if node_type == 0:
            return GenericNode(name, heal, self.generic_index)

        elif node_type == 1:
            return DockNode(
                name, heal, self.generic_index, data["dock_index"],
                DockConnection(data["connected_area_asset_id"],
                               data["connected_dock_index"]),
                self.dock_weakness_database.get_by_type_and_index(
                    DockType(data["dock_type"]), data["dock_weakness_index"]))

        elif node_type == 2:
            return PickupNode(name, heal, self.generic_index,
                              PickupIndex(data["pickup_index"]),
                              data["major_location"])

        elif node_type == 3:
            instance_id = data["teleporter_instance_id"]

            destination_world_asset_id = data["destination_world_asset_id"]
            destination_area_asset_id = data["destination_area_asset_id"]

            return TeleporterNode(
                name,
                heal,
                self.generic_index,
                instance_id,
                AreaLocation(destination_world_asset_id,
                             destination_area_asset_id),
                data["keep_name_when_vanilla"],
                data["editable"],
            )

        elif node_type == 4:
            return EventNode(
                name, heal, self.generic_index,
                self.resource_database.get_by_type_and_index(
                    ResourceType.EVENT, data["event_index"]))

        elif node_type == 5:
            return TranslatorGateNode(
                name, heal, self.generic_index,
                TranslatorGate(data["gate_index"]),
                find_resource_info_with_long_name(self.resource_database.item,
                                                  "Scan Visor"))

        elif node_type == 6:
            lore_type = list(LoreType)[data["lore_type"]]

            if lore_type == LoreType.LUMINOTH_LORE:
                required_translator = self.resource_database.get_item(
                    data["extra"])
            else:
                required_translator = None

            if lore_type in {
                    LoreType.LUMINOTH_WARRIOR, LoreType.SKY_TEMPLE_KEY_HINT
            }:
                hint_index = data["extra"]
            else:
                hint_index = None

            return LogbookNode(
                name, heal, self.generic_index, data["string_asset_id"],
                find_resource_info_with_long_name(self.resource_database.item,
                                                  "Scan Visor"), lore_type,
                required_translator, hint_index)

        else:
            raise Exception("Unknown node type: {}".format(node_type))
예제 #14
0
def _patches_with_data(request, echoes_game_data, echoes_item_database):
    game = data_reader.decode_data(echoes_game_data)

    data = {
        "starting_location": "Temple Grounds/Landing Site",
        "starting_items": {},
        "elevators": {
            "Temple Grounds/Temple Transport C": "Great Temple/Temple Transport C",
            "Temple Grounds/Transport to Agon Wastes": "Agon Wastes/Transport to Temple Grounds",
            "Temple Grounds/Transport to Torvus Bog": "Torvus Bog/Transport to Temple Grounds",
            "Temple Grounds/Temple Transport B": "Great Temple/Temple Transport B",
            "Temple Grounds/Transport to Sanctuary Fortress": "Sanctuary Fortress/Transport to Temple Grounds",
            "Temple Grounds/Temple Transport A": "Great Temple/Temple Transport A",
            "Great Temple/Temple Transport A": "Temple Grounds/Temple Transport A",
            "Great Temple/Temple Transport C": "Temple Grounds/Temple Transport C",
            "Great Temple/Temple Transport B": "Temple Grounds/Temple Transport B",
            "Sky Temple Grounds/Sky Temple Gateway": "Sky Temple/Sky Temple Energy Controller",
            "Sky Temple/Sky Temple Energy Controller": "Sky Temple Grounds/Sky Temple Gateway",
            "Agon Wastes/Transport to Temple Grounds": "Temple Grounds/Transport to Agon Wastes",
            "Agon Wastes/Transport to Torvus Bog": "Torvus Bog/Transport to Agon Wastes",
            "Agon Wastes/Transport to Sanctuary Fortress": "Sanctuary Fortress/Transport to Agon Wastes",
            "Torvus Bog/Transport to Temple Grounds": "Temple Grounds/Transport to Torvus Bog",
            "Torvus Bog/Transport to Agon Wastes": "Agon Wastes/Transport to Torvus Bog",
            "Torvus Bog/Transport to Sanctuary Fortress": "Sanctuary Fortress/Transport to Torvus Bog",
            "Sanctuary Fortress/Transport to Temple Grounds": "Temple Grounds/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Transport to Agon Wastes": "Agon Wastes/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Transport to Torvus Bog": "Torvus Bog/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Aerie": "Sanctuary Fortress/Aerie Transport Station",
            "Sanctuary Fortress/Aerie Transport Station": "Sanctuary Fortress/Aerie",
        },
        "translators": {},
        "locations": {},
        "hints": {},
        "_locations_internal": "",
    }
    patches = game.create_game_patches()

    locations = collections.defaultdict(dict)
    for world, area, node in game.world_list.all_worlds_areas_nodes:
        if node.is_resource_node and isinstance(node, PickupNode):
            world_name = world.dark_name if area.in_dark_aether else world.name
            locations[world_name][game.world_list.node_name(node)] = game_patches_serializer._ETM_NAME

    data["locations"] = {
        world: {
            area: item
            for area, item in sorted(locations[world].items())
        }
        for world in sorted(locations.keys())
    }

    if request.param.get("starting_item"):
        item_name = request.param.get("starting_item")
        patches = patches.assign_extra_initial_items({
            find_resource_info_with_long_name(game.resource_database.item, item_name): 1,
        })
        data["starting_items"][item_name] = 1

    if request.param.get("elevator"):
        elevator_id, elevator_source = request.param.get("elevator")
        elevator_connection = copy.copy(patches.elevator_connection)
        elevator_connection[elevator_id] = game.starting_location

        patches = dataclasses.replace(patches, elevator_connection=elevator_connection)
        data["elevators"][elevator_source] = "Temple Grounds/Landing Site"

    if request.param.get("translator"):
        gates = {}
        for index, gate_name, translator in request.param.get("translator"):
            gates[TranslatorGate(index)] = find_resource_info_with_long_name(game.resource_database.item, translator)
            data["translators"][gate_name] = translator

        patches = patches.assign_gate_assignment(gates)

    if request.param.get("pickup"):
        data["_locations_internal"], pickup_name = request.param.get("pickup")
        pickup = pickup_creator.create_major_item(echoes_item_database.major_items[pickup_name],
                                                  MajorItemState(), True, game.resource_database,
                                                  None, False)

        patches = patches.assign_new_pickups([(PickupIndex(5), pickup)])
        data["locations"]["Temple Grounds"]['Transport to Agon Wastes/Pickup (Missile)'] = pickup_name

    if request.param.get("hint"):
        asset, hint = request.param.get("hint")
        patches = patches.assign_hint(LogbookAsset(asset), Hint.from_json(hint))
        data["hints"][str(asset)] = hint

    return data, patches
예제 #15
0
    def read_node(self, data: Dict) -> Node:
        name: str = data["name"]
        self.generic_index += 1
        try:
            heal: bool = data["heal"]
            node_type: int = data["node_type"]
            location = None
            if data["coordinates"] is not None:
                location = location_from_json(data["coordinates"])

            if node_type == "generic":
                return GenericNode(name, heal, location, self.generic_index)

            elif node_type == "dock":
                return DockNode(
                    name, heal, location, self.generic_index,
                    data["dock_index"],
                    DockConnection(data["connected_area_asset_id"],
                                   data["connected_dock_index"]),
                    self.dock_weakness_database.get_by_type_and_index(
                        DockType(data["dock_type"]),
                        data["dock_weakness_index"]))

            elif node_type == "pickup":
                return PickupNode(name, heal, location, self.generic_index,
                                  PickupIndex(data["pickup_index"]),
                                  data["major_location"])

            elif node_type == "teleporter":
                instance_id = data["teleporter_instance_id"]

                destination_world_asset_id = data["destination_world_asset_id"]
                destination_area_asset_id = data["destination_area_asset_id"]

                return TeleporterNode(
                    name,
                    heal,
                    location,
                    self.generic_index,
                    instance_id,
                    AreaLocation(destination_world_asset_id,
                                 destination_area_asset_id),
                    data["scan_asset_id"],
                    data["keep_name_when_vanilla"],
                    data["editable"],
                )

            elif node_type == "event":
                return EventNode(
                    name, heal, location, self.generic_index,
                    self.resource_database.get_by_type_and_index(
                        ResourceType.EVENT, data["event_index"]))

            elif node_type == "translator_gate":
                return TranslatorGateNode(name, heal, location,
                                          self.generic_index,
                                          TranslatorGate(data["gate_index"]),
                                          self._get_scan_visor())

            elif node_type == "logbook":
                lore_type = LoreType(data["lore_type"])

                if lore_type == LoreType.LUMINOTH_LORE:
                    required_translator = self.resource_database.get_item(
                        data["extra"])
                else:
                    required_translator = None

                if lore_type in {
                        LoreType.LUMINOTH_WARRIOR, LoreType.SKY_TEMPLE_KEY_HINT
                }:
                    hint_index = data["extra"]
                else:
                    hint_index = None

                return LogbookNode(name, heal, location, self.generic_index,
                                   data["string_asset_id"],
                                   self._get_scan_visor(), lore_type,
                                   required_translator, hint_index)
            else:
                raise Exception(f"Unknown type: {node_type}")

        except Exception as e:
            raise Exception(f"In node {name}, got error: {e}")
예제 #16
0
def _raw_translator_configurations(
        data: dict) -> Dict[TranslatorGate, LayoutTranslatorRequirement]:
    return {
        TranslatorGate(int(key)): LayoutTranslatorRequirement(item)
        for key, item in data["translator_requirement"].items()
    }
def _patches_with_data(request, echoes_game_data, echoes_item_database):
    game = data_reader.decode_data(echoes_game_data)

    data = {
        "starting_location": "Temple Grounds/Landing Site",
        "starting_items": {},
        "elevators": {
            "Temple Grounds/Temple Transport C":
            "Great Temple/Temple Transport C",
            "Temple Grounds/Transport to Agon Wastes":
            "Agon Wastes/Transport to Temple Grounds",
            "Temple Grounds/Transport to Torvus Bog":
            "Torvus Bog/Transport to Temple Grounds",
            "Temple Grounds/Temple Transport B":
            "Great Temple/Temple Transport B",
            "Temple Grounds/Sky Temple Gateway":
            "Great Temple/Sky Temple Energy Controller",
            "Temple Grounds/Transport to Sanctuary Fortress":
            "Sanctuary Fortress/Transport to Temple Grounds",
            "Temple Grounds/Temple Transport A":
            "Great Temple/Temple Transport A",
            "Great Temple/Temple Transport A":
            "Temple Grounds/Temple Transport A",
            "Great Temple/Temple Transport C":
            "Temple Grounds/Temple Transport C",
            "Great Temple/Temple Transport B":
            "Temple Grounds/Temple Transport B",
            "Great Temple/Sky Temple Energy Controller":
            "Temple Grounds/Sky Temple Gateway",
            "Agon Wastes/Transport to Temple Grounds":
            "Temple Grounds/Transport to Agon Wastes",
            "Agon Wastes/Transport to Torvus Bog":
            "Torvus Bog/Transport to Agon Wastes",
            "Agon Wastes/Transport to Sanctuary Fortress":
            "Sanctuary Fortress/Transport to Agon Wastes",
            "Torvus Bog/Transport to Temple Grounds":
            "Temple Grounds/Transport to Torvus Bog",
            "Torvus Bog/Transport to Agon Wastes":
            "Agon Wastes/Transport to Torvus Bog",
            "Torvus Bog/Transport to Sanctuary Fortress":
            "Sanctuary Fortress/Transport to Torvus Bog",
            "Sanctuary Fortress/Transport to Temple Grounds":
            "Temple Grounds/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Transport to Agon Wastes":
            "Agon Wastes/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Transport to Torvus Bog":
            "Torvus Bog/Transport to Sanctuary Fortress"
        },
        "translators": {},
        "locations": {
            world.name: {
                game.world_list.node_name(node): "Nothing"
                for node in world.all_nodes
                if node.is_resource_node and isinstance(node, PickupNode)
            }
            for world in sorted(game.world_list.worlds, key=lambda w: w.name)
        },
        "hints": {},
        "_locations_internal": "",
    }
    patches = GamePatches.with_game(game)

    if request.param.get("starting_item"):
        item_name = request.param.get("starting_item")
        patches = patches.assign_extra_initial_items({
            find_resource_info_with_long_name(game.resource_database.item, item_name):
            1,
        })
        data["starting_items"][item_name] = 1

    if request.param.get("elevator"):
        elevator_id, elevator_source = request.param.get("elevator")
        elevator_connection = copy.copy(patches.elevator_connection)
        elevator_connection[elevator_id] = game.starting_location

        patches = dataclasses.replace(patches,
                                      elevator_connection=elevator_connection)
        data["elevators"][elevator_source] = "Temple Grounds/Landing Site"

    if request.param.get("translator"):
        gates = {}
        for index, gate_name, translator in request.param.get("translator"):
            gates[TranslatorGate(index)] = find_resource_info_with_long_name(
                game.resource_database.item, translator)
            data["translators"][gate_name] = translator

        patches = patches.assign_gate_assignment(gates)

    if request.param.get("pickup"):
        data["_locations_internal"], pickup_name = request.param.get("pickup")
        pickup = pickup_creator.create_major_item(
            echoes_item_database.major_items[pickup_name], MajorItemState(),
            True, game.resource_database, None, False)

        patches = patches.assign_new_pickups([(PickupIndex(5), pickup)])
        data["locations"]["Temple Grounds"][
            'Transport to Agon Wastes/Pickup (Missile)'] = pickup_name

    if request.param.get("hint"):
        asset, hint = request.param.get("hint")
        patches = patches.assign_hint(LogbookAsset(asset),
                                      Hint.from_json(hint))
        data["hints"][str(asset)] = hint

    return data, patches