Esempio n. 1
0
def test_items_for_ammo_two_item_diverging_values():
    # Setup
    item_a = 1
    item_b = 2

    total_pickup = 10
    maximum = 200

    included_ammo_for_item = {item_a: 0, item_b: 100}
    previous_pickup_for_item = {}

    ammo = Ammo("My Ammo", maximum=maximum, items=(item_a, item_b), broad_category=ItemCategory.BEAM_RELATED)
    state = AmmoState(0, total_pickup)
    maximum_ammo = {item_a: maximum, item_b: maximum}

    # Run
    ammo_per_pickup = randovania.generator.item_pool.ammo.items_for_ammo(ammo, state, included_ammo_for_item,
                                                                         previous_pickup_for_item, maximum_ammo)

    # Assert
    assert previous_pickup_for_item == {
        item_a: ammo,
        item_b: ammo,
    }
    assert ammo_per_pickup == [[20, 10]] * total_pickup
    def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata):
        from randovania.game_description import default_database
        item_database = default_database.default_prime2_item_database()

        default = cls.default()
        has_value = {
            item_key: bool(decoder.decode_single(2))
            for item_key in default.maximum_ammo.keys()
        }

        maximum_ammo = {
            item_key: decoder.decode_single(256)
            if has_value[item_key] else default.maximum_ammo[item_key]
            for item_key, default_value in default.maximum_ammo.items()
        }

        num_items = decoder.decode_single(len(default.items_state))
        indices_with_custom = {
            decoder.decode_single(len(default.items_state))
            for _ in range(num_items)
        }

        items_state = {}
        for index, item in enumerate(item_database.ammo.values()):
            if index in indices_with_custom:
                items_state[item] = AmmoState.bit_pack_unpack(decoder, {})
            else:
                items_state[item] = default.items_state[item]

        return cls(maximum_ammo, items_state)
Esempio n. 3
0
def test_items_for_ammo_two_item(per_pickup: int, total_pickup: int,
                                 included: int):
    # Setup
    item_a = 1
    item_b = 2

    included_ammo_for_item = {item_a: included, item_b: included}
    previous_pickup_for_item = {}

    maximum = per_pickup * total_pickup + included
    ammo = Ammo("My Ammo",
                model_name="Model",
                maximum=maximum,
                items=(item_a, item_b),
                broad_category=ItemCategory.BEAM_RELATED)
    state = AmmoState(0, total_pickup)
    maximum_ammo = {item_a: maximum, item_b: maximum}

    # Run
    ammo_per_pickup = randovania.generator.item_pool.ammo.items_for_ammo(
        ammo, state, included_ammo_for_item, previous_pickup_for_item,
        maximum_ammo)

    # Assert
    assert previous_pickup_for_item == {
        item_a: ammo,
        item_b: ammo,
    }
    assert ammo_per_pickup == [[per_pickup, per_pickup]] * total_pickup
Esempio n. 4
0
def test_items_for_ammo_one_item_non_divisible():
    # Setup
    item_a = 1

    maximum = 11
    total_pickup = 5

    included_ammo_for_item = {item_a: 0}
    previous_pickup_for_item = {}

    ammo = Ammo("My Ammo",
                model_name="Model",
                maximum=maximum,
                items=(item_a, ),
                broad_category=ItemCategory.BEAM_RELATED)
    state = AmmoState(0, total_pickup)
    maximum_ammo = {item_a: maximum}

    # Run
    ammo_per_pickup = randovania.generator.item_pool.ammo.items_for_ammo(
        ammo, state, included_ammo_for_item, previous_pickup_for_item,
        maximum_ammo)

    # Assert
    assert previous_pickup_for_item == {item_a: ammo}
    assert ammo_per_pickup == [[3]] + [[2]] * (total_pickup - 1)
Esempio n. 5
0
def test_decode(state_with_data):
    # Setup
    data, expected = state_with_data

    # Run
    decoder = BitPackDecoder(data)
    result = AmmoState.bit_pack_unpack(decoder, {})

    # Assert
    assert result == expected
Esempio n. 6
0
    def change_split(self, has_split: bool):
        with self._editor as editor:
            ammo_configuration = editor.ammo_configuration

            current_total = sum(
                ammo_configuration.items_state[ammo].pickup_count
                for ammo in (self.unified_ammo, *self.split_ammo)
            )
            if has_split:
                split_state = AmmoState(pickup_count=current_total // len(self.split_ammo))
                unified_state = AmmoState()
            else:
                split_state = AmmoState()
                unified_state = AmmoState(pickup_count=current_total)

            new_states = {self.unified_ammo: unified_state}
            for ammo in self.split_ammo:
                new_states[ammo] = split_state

            editor.ammo_configuration = ammo_configuration.replace_states(new_states)
 def from_json(cls, value: dict,
               item_database: ItemDatabase) -> "AmmoConfiguration":
     return cls(
         maximum_ammo={
             int(ammo_item): maximum
             for ammo_item, maximum in value["maximum_ammo"].items()
         },
         items_state={
             item_database.ammo[name]: AmmoState.from_json(state)
             for name, state in value["items_state"].items()
         },
     )
Esempio n. 8
0
    def _change_split_ammo(self, has_split: bool):
        with self._editor as options:
            ammo_configuration = options.ammo_configuration

            current_total = sum(
                ammo_configuration.items_state[ammo].pickup_count
                for ammo in (self._dark_ammo_item, self._light_ammo_item,
                             self._beam_ammo_item))
            if has_split:
                dark_ammo_state = AmmoState(pickup_count=current_total // 2)
                light_ammo_state = AmmoState(pickup_count=current_total // 2)
                beam_ammo_state = AmmoState()
            else:
                dark_ammo_state = AmmoState()
                light_ammo_state = AmmoState()
                beam_ammo_state = AmmoState(pickup_count=current_total)

            ammo_configuration = ammo_configuration.replace_states({
                self._dark_ammo_item:
                dark_ammo_state,
                self._light_ammo_item:
                light_ammo_state,
                self._beam_ammo_item:
                beam_ammo_state,
            })

            options.ammo_configuration = ammo_configuration
Esempio n. 9
0
 def from_json(cls, value: dict,
               game: RandovaniaGame) -> "AmmoConfiguration":
     item_database = default_database.item_database_for_game(game)
     return cls(
         maximum_ammo={
             int(ammo_item): maximum
             for ammo_item, maximum in value["maximum_ammo"].items()
         },
         items_state={
             item_database.ammo[name]: AmmoState.from_json(state)
             for name, state in value["items_state"].items()
         },
     )
Esempio n. 10
0
    def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata):
        default: AmmoConfiguration = metadata["reference"]

        # Maximum Ammo
        maximum_ammo = {}
        for item_key, default_value in default.maximum_ammo.items():
            is_different = bitpacking.decode_bool(decoder)
            if is_different:
                maximum_ammo[item_key] = decoder.decode_single(256)
            else:
                maximum_ammo[item_key] = default_value

        items_state = {}
        for item, default_state in default.items_state.items():
            is_different = bitpacking.decode_bool(decoder)
            if is_different:
                items_state[item] = AmmoState.bit_pack_unpack(decoder, {})
            else:
                items_state[item] = default_state

        return cls(maximum_ammo, items_state)
Esempio n. 11
0
def test_items_for_ammo_one_item(per_pickup: int, total_pickup: int,
                                 included: int):
    # Setup
    item_a = 1

    included_ammo_for_item = {item_a: included}
    previous_pickup_for_item = {}

    maximum = per_pickup * total_pickup + included
    ammo = Ammo("My Ammo", maximum=maximum, items=(item_a, ))
    state = AmmoState(0, total_pickup)
    maximum_ammo = {item_a: maximum}

    # Run
    ammo_per_pickup = randovania.generator.item_pool.ammo.items_for_ammo(
        ammo, state, included_ammo_for_item, previous_pickup_for_item,
        maximum_ammo)

    # Assert
    assert previous_pickup_for_item == {item_a: ammo}
    assert ammo_per_pickup == [[per_pickup]] * total_pickup
Esempio n. 12
0
    def _create_ammo_pickup_boxes(self, size_policy,
                                  item_database: ItemDatabase):
        """
        Creates the GroupBox with SpinBoxes for selecting the pickup count of all the ammo
        :param item_database:
        :return:
        """

        self._ammo_maximum_spinboxes = collections.defaultdict(list)
        self._ammo_pickup_widgets = {}

        resource_database = default_database.resource_database_for(self.game)
        broad_to_category = {
            ItemCategory.BEAM_RELATED: ItemCategory.BEAM,
            ItemCategory.MORPH_BALL_RELATED: ItemCategory.MORPH_BALL,
            ItemCategory.MISSILE_RELATED: ItemCategory.MISSILE,
        }

        for ammo in item_database.ammo.values():
            category_box, category_layout, _ = self._boxes_for_category[
                broad_to_category[ammo.broad_category]]

            pickup_box = QGroupBox(category_box)
            pickup_box.setSizePolicy(size_policy)
            pickup_box.setTitle(ammo.name + "s")
            layout = QGridLayout(pickup_box)
            layout.setObjectName(f"{ammo.name} Box Layout")
            current_row = 0

            for ammo_item in ammo.items:
                item = resource_database.get_by_type_and_index(
                    ResourceType.ITEM, ammo_item)

                target_count_label = QLabel(pickup_box)
                target_count_label.setText(f"{item.long_name} Target" if len(
                    ammo.items) > 1 else "Target count")

                maximum_spinbox = QSpinBox(pickup_box)
                maximum_spinbox.setMaximum(ammo.maximum)
                maximum_spinbox.valueChanged.connect(
                    partial(self._on_update_ammo_maximum_spinbox, ammo_item))
                self._ammo_maximum_spinboxes[ammo_item].append(maximum_spinbox)

                layout.addWidget(target_count_label, current_row, 0)
                layout.addWidget(maximum_spinbox, current_row, 1)
                current_row += 1

            count_label = QLabel(pickup_box)
            count_label.setText("Pickup Count")
            count_label.setToolTip(
                "How many instances of this expansion should be placed.")

            pickup_spinbox = QSpinBox(pickup_box)
            pickup_spinbox.setMaximum(AmmoState.maximum_pickup_count())
            pickup_spinbox.valueChanged.connect(
                partial(self._on_update_ammo_pickup_spinbox, ammo))

            layout.addWidget(count_label, current_row, 0)
            layout.addWidget(pickup_spinbox, current_row, 1)
            current_row += 1

            if ammo.temporaries:
                require_major_item_check = QCheckBox(pickup_box)
                require_major_item_check.setText(
                    "Requires the major item to work?")
                require_major_item_check.stateChanged.connect(
                    partial(self._on_update_ammo_require_major_item, ammo))
                layout.addWidget(require_major_item_check, current_row, 0, 1,
                                 2)
                current_row += 1
            else:
                require_major_item_check = None

            expected_count = QLabel(pickup_box)
            expected_count.setWordWrap(True)
            expected_count.setText(_EXPECTED_COUNT_TEXT_TEMPLATE)
            expected_count.setToolTip(
                "Some expansions may provide 1 extra, even with no variance, if the total count "
                "is not divisible by the pickup count.")
            layout.addWidget(expected_count, current_row, 0, 1, 2)
            current_row += 1

            self._ammo_pickup_widgets[ammo] = AmmoPickupWidgets(
                pickup_spinbox, expected_count, pickup_box,
                require_major_item_check)
            category_layout.addWidget(pickup_box)
Esempio n. 13
0
def _state_with_data(request):
    return request.param["encoded"], AmmoState.from_json(request.param["json"])
Esempio n. 14
0
    def _create_ammo_pickup_boxes(self, size_policy, item_database: ItemDatabase):
        """
        Creates the GroupBox with SpinBoxes for selecting the pickup count of all the ammo
        :param item_database:
        :return:
        """

        self._ammo_maximum_spinboxes = collections.defaultdict(list)
        self._ammo_pickup_widgets = {}

        resource_database = default_prime2_resource_database()

        for ammo in item_database.ammo.values():
            title_layout = QHBoxLayout()
            title_layout.setObjectName(f"{ammo.name} Title Horizontal Layout")

            expand_ammo_button = QToolButton(self.ammo_box)
            expand_ammo_button.setGeometry(QRect(20, 30, 24, 21))
            expand_ammo_button.setText("+")
            title_layout.addWidget(expand_ammo_button)

            category_label = QLabel(self.ammo_box)
            category_label.setSizePolicy(size_policy)
            category_label.setText(ammo.name + "s")
            title_layout.addWidget(category_label)

            pickup_box = QGroupBox(self.ammo_box)
            pickup_box.setSizePolicy(size_policy)
            layout = QGridLayout(pickup_box)
            layout.setObjectName(f"{ammo.name} Box Layout")
            current_row = 0

            for ammo_item in ammo.items:
                item = resource_database.get_by_type_and_index(ResourceType.ITEM, ammo_item)

                target_count_label = QLabel(pickup_box)
                target_count_label.setText(f"{item.long_name} Target" if len(ammo.items) > 1 else "Target count")

                maximum_spinbox = QSpinBox(pickup_box)
                maximum_spinbox.setMaximum(ammo.maximum)
                maximum_spinbox.valueChanged.connect(partial(self._on_update_ammo_maximum_spinbox, ammo_item))
                self._ammo_maximum_spinboxes[ammo_item].append(maximum_spinbox)

                layout.addWidget(target_count_label, current_row, 0)
                layout.addWidget(maximum_spinbox, current_row, 1)
                current_row += 1

            count_label = QLabel(pickup_box)
            count_label.setText("Pickup Count")
            count_label.setToolTip("How many instances of this expansion should be placed.")

            pickup_spinbox = QSpinBox(pickup_box)
            pickup_spinbox.setMaximum(AmmoState.maximum_pickup_count())
            pickup_spinbox.valueChanged.connect(partial(self._on_update_ammo_pickup_spinbox, ammo))

            layout.addWidget(count_label, current_row, 0)
            layout.addWidget(pickup_spinbox, current_row, 1)
            current_row += 1

            if ammo.temporaries:
                require_major_item_check = QCheckBox(pickup_box)
                require_major_item_check.setText("Requires the major item to work?")
                require_major_item_check.stateChanged.connect(partial(self._on_update_ammo_require_major_item, ammo))
                layout.addWidget(require_major_item_check, current_row, 0, 1, 2)
                current_row += 1
            else:
                require_major_item_check = None

            expected_count = QLabel(pickup_box)
            expected_count.setWordWrap(True)
            expected_count.setText(_EXPECTED_COUNT_TEXT_TEMPLATE)
            expected_count.setToolTip("Some expansions may provide 1 extra, even with no variance, if the total count "
                                      "is not divisible by the pickup count.")
            layout.addWidget(expected_count, current_row, 0, 1, 2)
            current_row += 1

            self._ammo_pickup_widgets[ammo] = (pickup_spinbox, expected_count, expand_ammo_button,
                                               category_label, pickup_box, require_major_item_check)

            expand_ammo_button.clicked.connect(partial(_toggle_box_visibility, expand_ammo_button, pickup_box))
            pickup_box.setVisible(False)

            self.ammo_layout.addLayout(title_layout)
            self.ammo_layout.addWidget(pickup_box)