def from_json(cls, value: dict,
                  game: RandovaniaGame) -> "MajorItemsConfiguration":
        item_database = default_database.item_database_for_game(game)

        items_state = {}
        for name, item in item_database.major_items.items():
            if name in value["items_state"]:
                state = MajorItemState.from_json(value["items_state"][name])
            else:
                state = MajorItemState()
            items_state[item] = state

        default_items = {
            category:
            item_database.major_items[value["default_items"][category.name]]
            for category, _ in item_database.default_items.items()
        }

        return cls(
            game=game,
            items_state=items_state,
            default_items=default_items,
            minimum_random_starting_items=value[
                "minimum_random_starting_items"],
            maximum_random_starting_items=value[
                "maximum_random_starting_items"],
        )
def test_state_change_to_starting(skip_qtbot, echoes_item_database,
                                  echoes_resource_database):
    item = [
        item for item in echoes_item_database.major_items.values()
        if not item.must_be_starting
    ][0]
    state = MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=1,
        num_included_in_starting_items=0,
        included_ammo=(),
    )

    # Run
    popup = ItemConfigurationWidget(None, item, state,
                                    echoes_resource_database)
    skip_qtbot.addWidget(popup)
    popup.state_case_combo.setCurrentIndex(
        popup.state_case_combo.findData(MajorItemStateCase.STARTING_ITEM))

    # Assert
    assert popup.state == MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=0,
        num_included_in_starting_items=1,
        priority=1.0,
        included_ammo=(),
    )
def test_state_must_be_starting(skip_qtbot, echoes_item_database,
                                echoes_resource_database):
    item = [
        item for item in echoes_item_database.major_items.values()
        if item.must_be_starting
    ][0]
    state = MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=1,
        num_included_in_starting_items=0,
        included_ammo=(),
    )

    # Run
    popup = ItemConfigurationWidget(None, item, state,
                                    echoes_resource_database)
    skip_qtbot.addWidget(popup)

    # Assert
    assert popup.state == MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=0,
        num_included_in_starting_items=1,
        included_ammo=(),
    )
Beispiel #4
0
    def _update_explosive(self, bad_ending: bool):
        items = self._boxes_for_category["items"][2]
        explosive = next(item for item in items.keys() if item.name == "Explosive")
        explosive_box = items[explosive]

        if bad_ending:
            explosive_box.setVisible(False)
            explosive_box._update_for_state(MajorItemState(True, 0, 0))
        else:
            explosive_box.setVisible(True)
            explosive_box._update_for_state(MajorItemState(False, 1, 0))
    def change_progressive(self, is_progressive: bool):
        with self._editor as editor:
            if is_progressive:
                non_progressive_state = MajorItemState()
                progressive_state = MajorItemState(
                    num_shuffled_pickups=len(self.non_progressive_items))
            else:
                non_progressive_state = MajorItemState(num_shuffled_pickups=1)
                progressive_state = MajorItemState()

            new_states = {self.progressive_item: progressive_state}
            for item in self.non_progressive_items:
                new_states[item] = non_progressive_state

            editor.major_items_configuration = editor.major_items_configuration.replace_states(
                new_states)
async def test_receive_required_missile_launcher(
        connector: EchoesRemoteConnector, echoes_item_database,
        echoes_resource_database):
    pickup = pickup_creator.create_major_item(
        echoes_item_database.major_items["Missile Launcher"],
        MajorItemState(included_ammo=(5, )),
        True,
        echoes_resource_database,
        echoes_item_database.ammo["Missile Expansion"],
        True,
    )

    executor = AsyncMock()
    permanent_pickups = (("Received Missile Launcher from Someone Else",
                          pickup), )

    inventory = {
        echoes_resource_database.multiworld_magic_item: InventoryItem(0, 0),
    }

    # Run
    patches, has_message = await connector.find_missing_remote_pickups(
        executor,
        inventory,
        permanent_pickups,
        False,
    )
    assert has_message
    assert len(patches) == 5
    await connector.execute_remote_patches(executor, patches)
Beispiel #7
0
def test_decode(major_item_state):
    # Setup
    item, data, _, expected, reference = major_item_state

    # Run
    decoder = BitPackDecoder(data)
    result = MajorItemState.bit_pack_unpack(decoder, item, reference=reference)

    # Assert
    assert result == expected
def test_pickup_scan_for_progressive_suit(echoes_item_database, echoes_resource_database):
    # Setup
    progressive_suit = echoes_item_database.major_items["Progressive Suit"]
    pickup = pickup_creator.create_major_item(progressive_suit, MajorItemState(), False, echoes_resource_database,
                                              None, False)

    # Run
    result = pickup_exporter._pickup_scan(pickup)

    # Assert
    assert result == "Progressive Suit. Provides the following in order: Dark Suit, Light Suit"
Beispiel #9
0
def _major_item_state(request, echoes_item_database, generic_item_category):
    encoded: bytes = request.param["encoded"]

    item = MajorItem(
        game=RandovaniaGame.METROID_PRIME_ECHOES,
        name="Item Name",
        item_category=generic_item_category,
        broad_category=generic_item_category,
        model_name="Model Name",
        progression=(request.param.get("progression", "Power"),),
        default_starting_count=0,
        default_shuffled_count=1,
        ammo_index=request.param.get("ammo_index", ()),
        must_be_starting=True,
        original_index=None,
        probability_offset=0,
    )
    included_ammo = tuple(0 for _ in request.param["json"].get("included_ammo", []))
    reference = MajorItemState(included_ammo=included_ammo)
    return item, encoded, request.param["bit_count"], MajorItemState.from_json(request.param["json"]), reference
Beispiel #10
0
 def _on_default_item_updated(self, category: ItemCategory, combo: QtWidgets.QComboBox, _):
     item: MajorItem = combo.currentData()
     with self._editor as editor:
         new_config = editor.major_items_configuration
         new_config = new_config.replace_default_item(category, item)
         new_config = new_config.replace_state_for_item(
             item,
             MajorItemState(
                 num_included_in_starting_items=1,
                 included_ammo=new_config.items_state[item].included_ammo
             ),
         )
         editor.major_items_configuration = new_config
Beispiel #11
0
 def state(self) -> MajorItemState:
     if self.case == MajorItemStateCase.CUSTOM:
         return MajorItemState(
             include_copy_in_original_location=self.vanilla_check.isChecked(
             ),
             num_shuffled_pickups=self.shuffled_spinbox.value(),
             num_included_in_starting_items=1
             if self.starting_check.isChecked() else 0,
             priority=self.priority_combo.currentData(),
             included_ammo=self.included_ammo,
         )
     else:
         return MajorItemState.from_case(self.case, self.included_ammo)
def test_get_single_hud_text_all_major_items(echoes_item_database, echoes_resource_database):
    memo_data = default_database.default_prime2_memo_data()

    # Run
    for item in echoes_item_database.major_items.values():
        pickup = pickup_creator.create_major_item(item, MajorItemState(), False, echoes_resource_database, None, False)

        result = pickup_exporter._get_all_hud_text(pickup_exporter._conditional_resources_for_pickup(pickup),
                                                   memo_data)
        for i, progression in enumerate(pickup.progression):
            assert progression[0].long_name in result[i]
        assert result
        for line in result:
            assert len(line) > 10
            assert isinstance(line, str)
Beispiel #13
0
    def _create_major_item_boxes(self, item_database: ItemDatabase, resource_database: ResourceDatabase):
        for major_item in item_database.major_items.values():
            if major_item.hide_from_gui or major_item.item_category.name == "energy_tank":
                continue

            category_box, category_layout, elements = self._boxes_for_category[major_item.item_category.name]
            widget = ItemConfigurationWidget(None, major_item, MajorItemState(), resource_database)
            widget.Changed.connect(partial(self._on_major_item_updated, widget))

            row = category_layout.rowCount()
            if row > 1:
                # Show the transparent separator line if it's not the first element
                widget.separator_line.show()

            category_layout.addWidget(widget, row, 0, 1, 2)
            elements[major_item] = widget
Beispiel #14
0
def test_create_seeker_launcher(
    ammo_quantity: int,
    ammo_requires_major_item: bool,
    echoes_item_database,
    echoes_resource_database,
):
    # Setup
    missile = echoes_resource_database.get_item("Missile")
    missile_launcher = echoes_resource_database.get_item("MissileLauncher")
    seeker_launcher = echoes_resource_database.get_item("Seekers")
    temporary = echoes_resource_database.get_item("Temporary1")

    state = MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=0,
        num_included_in_starting_items=0,
        included_ammo=(ammo_quantity, ),
    )

    # Run
    result = pickup_creator.create_major_item(
        echoes_item_database.major_items["Seeker Launcher"], state, True,
        echoes_resource_database,
        echoes_item_database.ammo["Missile Expansion"],
        ammo_requires_major_item)

    # Assert

    assert result == PickupEntry(
        name="Seeker Launcher",
        progression=((seeker_launcher, 1), ),
        extra_resources=(
            (missile, ammo_quantity),
            (echoes_resource_database.item_percentage, 1),
        ),
        model=PickupModel(echoes_resource_database.game_enum,
                          "SeekerLauncher"),
        item_category=echoes_item_database.item_categories["missile"],
        broad_category=echoes_item_database.item_categories["missile_related"],
        respects_lock=ammo_requires_major_item,
        resource_lock=ResourceLock(
            locked_by=missile_launcher,
            temporary_item=temporary,
            item_to_lock=missile,
        ),
    )
Beispiel #15
0
def test_pickup_data_for_seeker_launcher(echoes_item_database, echoes_resource_database):
    # Setup
    state = MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=0,
        num_included_in_starting_items=0,
        included_ammo=(5,),
    )
    pickup = pickup_creator.create_major_item(
        echoes_item_database.major_items["Seeker Launcher"],
        state,
        True,
        echoes_resource_database,
        echoes_item_database.ammo["Missile Expansion"],
        True
    )
    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": "Seeker Launcher",
        "model": {"game": "prime2", "name": "SeekerLauncher"},
        "hud_text": ["Seeker Launcher acquired, but the Missile Launcher is required to use it.",
                     "Seeker Launcher acquired!"],
        'resources': [{'amount': 5, 'index': 71},
                      {'amount': 1, 'index': 47},
                      {'amount': 1, 'index': 26}],
        "conditional_resources": [
            {'item': 73,
             'resources': [{'amount': 5, 'index': 44},
                           {'amount': 1, 'index': 47},
                           {'amount': 1, 'index': 26}]}
        ],
        "convert": [],
    }
    def bit_pack_unpack(cls, decoder: BitPackDecoder,
                        metadata) -> "MajorItemsConfiguration":
        reference: MajorItemsConfiguration = metadata["reference"]

        name_to_item: Dict[str, MajorItem] = {
            item.name: item
            for item in reference.items_state.keys()
        }
        modified_items = bitpacking.decode_sorted_array_elements(
            decoder, sorted(name_to_item.keys()))

        items_state = copy.copy(reference.items_state)
        for item_name in modified_items:
            item = name_to_item[item_name]
            items_state[item] = MajorItemState.bit_pack_unpack(
                decoder, item, reference=reference.items_state[item])

        # default_items
        default_items = {}
        for category in reference.default_items.keys():
            all_major = [
                major for major in reference.items_state.keys()
                if major.item_category == category
            ]
            default_items[category] = decoder.decode_element(all_major)

        # random starting items
        minimum = bitpacking.decode_big_int(decoder)
        maximum = bitpacking.decode_big_int(decoder)

        return cls(
            game=reference.game,
            items_state=items_state,
            default_items=default_items,
            minimum_random_starting_items=minimum,
            maximum_random_starting_items=maximum,
        )
Beispiel #17
0
def _patches_with_data(request, echoes_game_description, echoes_game_patches,
                       echoes_item_database):
    game = echoes_game_description
    db = game.resource_database

    data = {
        "game": echoes_game_description.game.value,
        "starting_location": "Temple Grounds/Landing Site",
        "starting_items": {},
        "teleporters": {
            "Temple Grounds/Temple Transport C/Elevator to Great Temple - Temple Transport C":
            "Great Temple/Temple Transport C",
            "Temple Grounds/Transport to Agon Wastes/Elevator to Agon Wastes - Transport to Temple Grounds":
            "Agon Wastes/Transport to Temple Grounds",
            "Temple Grounds/Transport to Torvus Bog/Elevator to Torvus Bog - Transport to Temple Grounds":
            "Torvus Bog/Transport to Temple Grounds",
            "Temple Grounds/Temple Transport B/Elevator to Great Temple - Temple Transport B":
            "Great Temple/Temple Transport B",
            "Temple Grounds/Transport to Sanctuary Fortress/Elevator to Sanctuary Fortress - Transport to Temple Grounds":
            "Sanctuary Fortress/Transport to Temple Grounds",
            "Temple Grounds/Temple Transport A/Elevator to Great Temple - Temple Transport A":
            "Great Temple/Temple Transport A",
            "Great Temple/Temple Transport A/Elevator to Temple Grounds - Temple Transport A":
            "Temple Grounds/Temple Transport A",
            "Great Temple/Temple Transport C/Elevator to Temple Grounds - Temple Transport C":
            "Temple Grounds/Temple Transport C",
            "Great Temple/Temple Transport B/Elevator to Temple Grounds - Temple Transport B":
            "Temple Grounds/Temple Transport B",
            "Temple Grounds/Sky Temple Gateway/Teleport to Great Temple - Sky Temple Energy Controller":
            "Great Temple/Sky Temple Energy Controller",
            "Great Temple/Sky Temple Energy Controller/Teleport to Temple Grounds - Sky Temple Gateway":
            "Temple Grounds/Sky Temple Gateway",
            "Agon Wastes/Transport to Temple Grounds/Elevator to Temple Grounds - Transport to Agon Wastes":
            "Temple Grounds/Transport to Agon Wastes",
            "Agon Wastes/Transport to Torvus Bog/Elevator to Torvus Bog - Transport to Agon Wastes":
            "Torvus Bog/Transport to Agon Wastes",
            "Agon Wastes/Transport to Sanctuary Fortress/Elevator to Sanctuary Fortress - Transport to Agon Wastes":
            "Sanctuary Fortress/Transport to Agon Wastes",
            "Torvus Bog/Transport to Temple Grounds/Elevator to Temple Grounds - Transport to Torvus Bog":
            "Temple Grounds/Transport to Torvus Bog",
            "Torvus Bog/Transport to Agon Wastes/Elevator to Agon Wastes - Transport to Torvus Bog":
            "Agon Wastes/Transport to Torvus Bog",
            "Torvus Bog/Transport to Sanctuary Fortress/Elevator to Sanctuary Fortress - Transport to Torvus Bog":
            "Sanctuary Fortress/Transport to Torvus Bog",
            "Sanctuary Fortress/Transport to Temple Grounds/Elevator to Temple Grounds - Transport to Sanctuary Fortress":
            "Temple Grounds/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Transport to Agon Wastes/Elevator to Agon Wastes - Transport to Sanctuary Fortress":
            "Agon Wastes/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Transport to Torvus Bog/Elevator to Torvus Bog - Transport to Sanctuary Fortress":
            "Torvus Bog/Transport to Sanctuary Fortress",
            "Sanctuary Fortress/Aerie/Elevator to Sanctuary Fortress - Aerie Transport Station":
            "Sanctuary Fortress/Aerie Transport Station",
            "Sanctuary Fortress/Aerie Transport Station/Elevator to Sanctuary Fortress - Aerie":
            "Sanctuary Fortress/Aerie",
        },
        "dock_weakness": {},
        "configurable_nodes": {},
        "locations": {},
        "hints": {}
    }
    patches = dataclasses.replace(echoes_game_patches, player_index=0)

    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([
            (db.get_item_by_name(item_name), 1),
        ])
        data["starting_items"][item_name] = 1

    if request.param.get("elevator"):
        teleporter: NodeIdentifier = request.param.get("elevator")
        patches = patches.assign_elevators([
            (game.world_list.get_teleporter_node(teleporter),
             game.starting_location),
        ])
        data["teleporters"][
            teleporter.as_string] = "Temple Grounds/Landing Site"

    if request.param.get("configurable_nodes"):
        gates = []
        for identifier, translator in request.param.get("configurable_nodes"):
            requirement = ResourceRequirement.simple(db.get_item(translator))
            gates.append((NodeIdentifier.from_string(identifier), requirement))
            data["configurable_nodes"][
                identifier] = data_writer.write_requirement(requirement)

        patches = patches.assign_node_configuration(gates)

    if request.param.get("pickup"):
        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),
                                               PickupTarget(pickup, 0))])
        data["locations"]["Temple Grounds"][
            'Transport to Agon Wastes/Pickup (Missile)'] = pickup_name

    if request.param.get("hint"):
        identifier, hint = request.param.get("hint")
        patches = patches.assign_hint(NodeIdentifier.from_string(identifier),
                                      Hint.from_json(hint))
        data["hints"][identifier] = hint

    return data, patches
Beispiel #18
0
def test_blank_as_json():
    assert MajorItemState().as_json == {}
Beispiel #19
0
def test_blank_from_json():
    assert MajorItemState.from_json({}) == MajorItemState()
Beispiel #20
0
def test_missile_expansion_before_launcher(include_before,
                                           echoes_item_database,
                                           echoes_resource_database):
    # Setup
    ammo = echoes_item_database.ammo["Missile Expansion"]
    major_item = echoes_item_database.major_items["Missile Launcher"]

    missile = echoes_resource_database.get_item(ammo.items[0])
    missile_launcher = echoes_resource_database.get_item(
        major_item.progression[0])
    temporary = echoes_resource_database.get_item(ammo.temporary)
    percent = echoes_resource_database.item_percentage

    # Run
    expansion = pickup_creator.create_ammo_expansion(ammo, [5], True,
                                                     echoes_resource_database)
    launcher = pickup_creator.create_major_item(
        major_item, MajorItemState(included_ammo=(5, )), True,
        echoes_resource_database, ammo, True)

    resources = {}

    if include_before:
        # Ammo Expansion
        add_resource_gain_to_current_resources(
            expansion.resource_gain(resources, force_lock=True), resources)
        assert resources == {percent: 1, temporary: 5}

    # Add Launcher
    add_resource_gain_to_current_resources(
        launcher.resource_gain(resources, force_lock=True), resources)
    if include_before:
        assert resources == {
            percent: 2,
            temporary: 0,
            missile_launcher: 1,
            missile: 10
        }
    else:
        assert resources == {
            percent: 1,
            temporary: 0,
            missile_launcher: 1,
            missile: 5
        }

    # Ammo Expansion
    add_resource_gain_to_current_resources(
        expansion.resource_gain(resources, force_lock=True), resources)
    if include_before:
        assert resources == {
            percent: 3,
            temporary: 0,
            missile_launcher: 1,
            missile: 15
        }
    else:
        assert resources == {
            percent: 2,
            temporary: 0,
            missile_launcher: 1,
            missile: 10
        }
Beispiel #21
0
def test_create_pickup_for(percentage: bool, echoes_item_database,
                           echoes_resource_database, generic_item_category):
    # Setup
    item_a = echoes_resource_database.get_item("DarkVisor")
    item_b = echoes_resource_database.get_item("MorphBall")
    item_c = echoes_resource_database.get_item("Bombs")
    ammo_a = echoes_resource_database.get_item("EnergyTank")
    ammo_b = echoes_resource_database.get_item("DarkAmmo")

    less_generic_item_category = ItemCategory(name="the_category",
                                              long_name="The Category",
                                              hint_details=("a ",
                                                            " wonderful item"),
                                              is_major=True)

    major_item = MajorItem(
        game=echoes_resource_database.game_enum,
        name="The Item",
        item_category=less_generic_item_category,
        broad_category=generic_item_category,
        model_name="SuperModel",
        progression=("DarkVisor", "MorphBall", "Bombs"),
        default_starting_count=0,
        default_shuffled_count=1,
        ammo_index=("EnergyTank", "DarkAmmo"),
        must_be_starting=False,
        original_index=None,
        probability_offset=5,
    )
    state = MajorItemState(
        include_copy_in_original_location=False,
        num_shuffled_pickups=0,
        num_included_in_starting_items=0,
        included_ammo=(10, 20),
    )

    if percentage:
        extra_resources = (
            (ammo_a, 10),
            (ammo_b, 20),
            (echoes_resource_database.item_percentage, 1),
        )
    else:
        extra_resources = (
            (ammo_a, 10),
            (ammo_b, 20),
        )

    # Run
    result = pickup_creator.create_major_item(major_item, state, percentage,
                                              echoes_resource_database, None,
                                              False)

    # Assert
    assert result == PickupEntry(
        name="The Item",
        model=PickupModel(echoes_resource_database.game_enum, "SuperModel"),
        progression=(
            (item_a, 1),
            (item_b, 1),
            (item_c, 1),
        ),
        extra_resources=extra_resources,
        item_category=less_generic_item_category,
        broad_category=generic_item_category,
        probability_offset=5,
        respects_lock=False,
    )