def create_energy_cell( cell_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: ENERGY_CELL_CATEGORY = ItemCategory(name="energy_cell", long_name="", hint_details=("an ", "energy cell"), is_major=False, is_key=True) return PickupEntry( name=f"Energy Cell {cell_index + 1}", progression=((resource_database.get_item( corruption_items.ENERGY_CELL_ITEMS[cell_index]), 1), ), extra_resources=( (resource_database.get_item( corruption_items.ENERGY_CELL_TOTAL_ITEM), 1), (resource_database.item_percentage, 1), ), model=PickupModel( game=resource_database.game_enum, name=corruption_items.ENERGY_CELL_MODEL, ), item_category=ENERGY_CELL_CATEGORY, broad_category=GENERIC_KEY_CATEGORY, probability_offset=0.25, )
def create_stk_hints( all_patches: Dict[int, GamePatches], players_config: PlayersConfiguration, resource_database: ResourceDatabase, namer: HintNamer, hide_area: bool, ) -> list: """ Creates the string patches entries that changes the Sky Temple Gateway hint scans with hints for where the STK actually are. :param all_patches: :param players_config: :param resource_database: :param namer: :param hide_area: Should the hint include only the world? :return: """ resulting_hints = guaranteed_item_hint.create_guaranteed_hints_for_resources( all_patches, players_config, namer, hide_area, [ resource_database.get_item(index) for index in echoes_items.SKY_TEMPLE_KEY_ITEMS ], True, ) return [ create_simple_logbook_hint( _SKY_TEMPLE_KEY_SCAN_ASSETS[key_number], resulting_hints[resource_database.get_item(key_index)], ) for key_number, key_index in enumerate( echoes_items.SKY_TEMPLE_KEY_ITEMS) ]
def create_resource_lock(self, resource_database: ResourceDatabase) -> Optional[ResourceLock]: if self.unlocked_by is not None: return ResourceLock( locked_by=resource_database.get_item(self.unlocked_by), item_to_lock=resource_database.get_item(self.items[0]), temporary_item=resource_database.get_item(self.temporary), ) return None
def create_game_specific(self, resource_database: ResourceDatabase) -> EchoesBeamConfiguration: return EchoesBeamConfiguration( item=resource_database.get_item(self.item_index), ammo_a=resource_database.get_item(self.ammo_a) if self.ammo_a >= 0 else None, ammo_b=resource_database.get_item(self.ammo_b) if self.ammo_b >= 0 else None, uncharged_cost=self.uncharged_cost, charged_cost=self.charged_cost, combo_missile_cost=self.combo_missile_cost, combo_ammo_cost=self.combo_ammo_cost, )
def read_beam_configuration(data: Dict, resource_database: ResourceDatabase, ) -> EchoesBeamConfiguration: return EchoesBeamConfiguration( item=resource_database.get_item(data["item_index"]), ammo_a=resource_database.get_item(data["ammo_a"]) if data["ammo_a"] is not None else None, ammo_b=resource_database.get_item(data["ammo_b"]) if data["ammo_b"] is not None else None, uncharged_cost=data["uncharged_cost"], charged_cost=data["charged_cost"], combo_missile_cost=data["combo_missile_cost"], combo_ammo_cost=data["combo_ammo_cost"], )
def wrap(db: ResourceDatabase, data): if isinstance(data, dict): return { db.get_item(key): value for key, value in data.items() } else: return [ (db.get_item(key), value) for key, value in data ]
def create_artifact(artifact_index: int, minimum_progression: int, resource_database: ResourceDatabase, ) -> PickupEntry: ARTIFACT_CATEGORY = ItemCategory( name="artifact", long_name="", hint_details=("an ", "artifact"), is_major=False, is_key=True ) return PickupEntry( name=prime_items.ARTIFACT_NAMES[artifact_index], progression=( (resource_database.get_item(prime_items.ARTIFACT_ITEMS[artifact_index]), 1), ), model=PickupModel( game=resource_database.game_enum, name=prime_items.ARTIFACT_MODEL[artifact_index], ), item_category=ARTIFACT_CATEGORY, broad_category=GENERIC_KEY_CATEGORY, probability_offset=0.25, required_progression=minimum_progression, )
def create_dark_temple_key( key_number: int, temple_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: """ Creates a Dark Temple Key :param key_number: :param temple_index: The index of the temple: Dark Agon, Dark Torvus, Hive Temple :param resource_database: :return: """ TEMPLE_KEY_CATEGORY = ItemCategory(name="temple_key", long_name="", hint_details=("a ", "red Temple Key"), is_major=False, is_key=True) return PickupEntry( name=echoes_items.DARK_TEMPLE_KEY_NAMES[temple_index].format( key_number + 1), progression=((resource_database.get_item( echoes_items.DARK_TEMPLE_KEY_ITEMS[temple_index][key_number]), 1), ), model=PickupModel( game=resource_database.game_enum, name=echoes_items.DARK_TEMPLE_KEY_MODEL, ), item_category=TEMPLE_KEY_CATEGORY, broad_category=GENERIC_KEY_CATEGORY, probability_offset=3, )
def create_sky_temple_key( key_number: int, resource_database: ResourceDatabase, ) -> PickupEntry: """ :param key_number: :param resource_database: :return: """ SKY_TEMPLE_KEY_CATEGORY = ItemCategory(name="sky_temple_key", long_name="", hint_details=("a ", "Sky Temple Key"), is_major=False, is_key=True) return PickupEntry( name="Sky Temple Key {}".format(key_number + 1), progression=((resource_database.get_item( echoes_items.SKY_TEMPLE_KEY_ITEMS[key_number]), 1), ), model=PickupModel( game=resource_database.game_enum, name=echoes_items.SKY_TEMPLE_KEY_MODEL, ), item_category=SKY_TEMPLE_KEY_CATEGORY, broad_category=GENERIC_KEY_CATEGORY, probability_offset=3, )
def create_ammo_expansion( ammo: Ammo, ammo_count: Sequence[int], requires_major_item: bool, resource_database: ResourceDatabase, ) -> PickupEntry: """ Creates a Pickup for an expansion of the given ammo. :param ammo: :param ammo_count: :param requires_major_item: :param resource_database: :return: """ resources = [(resource_database.get_item(item), count) for item, count in zip(ammo.items, ammo_count)] if resource_database.item_percentage is not None: resources.append((resource_database.item_percentage, 1)) return PickupEntry( name=ammo.name, progression=(), extra_resources=tuple(resources), model=PickupModel( game=resource_database.game_enum, name=ammo.model_name, ), item_category=ammo.item_category, broad_category=ammo.broad_category, respects_lock=requires_major_item, resource_lock=ammo.create_resource_lock(resource_database), probability_multiplier=2, )
def _starting_items_value_for(resource_database: ResourceDatabase, starting_items: CurrentResources, index: str) -> Union[bool, int]: item = resource_database.get_item(index) value = starting_items.get(item, 0) if item.max_capacity > 1: return value else: return value > 0
def __init__(self, parent: QWidget, item: MajorItem, starting_state: MajorItemState, resources_database: ResourceDatabase): super().__init__(parent) self.setupUi(self) set_default_window_icon(self) self._item = item self.setWindowTitle(f"Item: {item.name}") self.item_name_label.setText(item.name) # connect self.excluded_radio.toggled.connect(self._on_select_excluded) self.vanilla_radio.toggled.connect(self._on_select_vanilla) self.starting_radio.toggled.connect(self._on_select_starting) self.shuffled_radio.toggled.connect(self._on_select_shuffled) self.shuffled_spinbox.valueChanged.connect(self._on_shuffled_value) self.provided_ammo_spinbox.valueChanged.connect(self._on_shuffled_value) # Update self.vanilla_radio.setEnabled(item.original_index is not None) self.shuffled_radio.setEnabled(item.model_index is not None) if not self.vanilla_radio.isEnabled(): self.vanilla_radio.setToolTip( "This item does not exist in the original game, so there's no vanilla location.") if not self.shuffled_radio.isEnabled(): self.shuffled_radio.setToolTip( "There's currently no available model and/or logic for this item to be shuffled.") # At least one radio should be selected for radio in (self.shuffled_radio, self.starting_radio, self.vanilla_radio): if radio.isEnabled(): radio.setChecked(True) break if item.ammo_index: self.provided_ammo_label.setText( "<html><head/><body><p>Provided Ammo ({})</p></body></html>".format( " and ".join( resources_database.get_item(ammo_index).long_name for ammo_index in item.ammo_index ) ) ) else: self.provided_ammo_label.hide() self.provided_ammo_spinbox.hide() if self._item.required: self.item_name_label.setToolTip( "This item is necessary for the game to function properly and can't be removed.") self.setEnabled(False) self.state = self._create_state(num_included_in_starting_items=1) else: if self._item.warning is not None: self.item_name_label.setToolTip(self._item.warning) self.state = starting_state
def _starting_items_value_for(resource_database: ResourceDatabase, starting_items: ResourceCollection, index: str) -> Union[bool, int]: item = resource_database.get_item(index) value = starting_items[item] if item.max_capacity > 1: return value else: return value > 0
def create_ammo_expansion( ammo: Ammo, ammo_count: List[int], requires_major_item: bool, resource_database: ResourceDatabase, ) -> PickupEntry: """ Creates a Pickup for an expansion of the given ammo. :param ammo: :param ammo_count: :param requires_major_item: :param resource_database: :return: """ resources = [(resource_database.get_item(item), count) for item, count in zip(ammo.items, ammo_count)] resources.append((resource_database.item_percentage, 1)) if ammo.unlocked_by is not None and requires_major_item: temporary_resources = [ (resource_database.get_item(item), count) for item, count in zip(ammo.temporaries, ammo_count) ] temporary_resources.append((resource_database.item_percentage, 1)) conditional_resources = ( ConditionalResources(temporary_resources[0][0].long_name, None, tuple(temporary_resources)), ConditionalResources(ammo.name, resource_database.get_item(ammo.unlocked_by), tuple(resources)), ) else: conditional_resources = (ConditionalResources(None, None, tuple(resources)), ) return PickupEntry( name=ammo.name, resources=conditional_resources, model_index=ammo.models[0], # TODO: use a random model item_category=ItemCategory.EXPANSION, broad_category=ammo.broad_category, )
def create_energy_cell(cell_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: return PickupEntry( name=f"Energy Cell {cell_index + 1}", progression=( (resource_database.get_item(corruption_items.ENERGY_CELL_ITEMS[cell_index]), 1), ), extra_resources=( (resource_database.get_item(corruption_items.ENERGY_CELL_TOTAL_ITEM), 1), (resource_database.item_percentage, 1), ), model=PickupModel( game=resource_database.game_enum, name=corruption_items.ENERGY_CELL_MODEL, ), item_category=ItemCategory.TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=0.25, )
def create_energy_cell( cell_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: return PickupEntry( name=f"Energy Cell {cell_index + 1}", resources=(ConditionalResources( None, None, tuple([ (resource_database.get_item( corruption_items.ENERGY_CELL_ITEMS[cell_index]), 1), (resource_database.get_item( corruption_items.ENERGY_CELL_TOTAL_ITEM), 1), (resource_database.item_percentage, 1), ])), ), model_index=corruption_items.ENERGY_CELL_MODEL, item_category=ItemCategory.TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=0.25, )
def create_major_item( item: MajorItem, state: MajorItemState, include_percentage: bool, resource_database: ResourceDatabase, ammo: Optional[Ammo], ammo_requires_major_item: bool, ) -> PickupEntry: """ Creates a Pickup for the given MajorItem :param include_percentage: :param state: :param item: :param resource_database: :param ammo: :param ammo_requires_major_item: :return: """ extra_resources = [ (resource_database.get_item(ammo_index), ammo_count) for ammo_index, ammo_count in zip(item.ammo_index, state.included_ammo) ] if include_percentage and resource_database.item_percentage is not None: extra_resources.append((resource_database.item_percentage, 1)) def _create_resources(base_resource: Optional[str]) -> ResourceQuantity: # FIXME: hacky quantity for Hazard Shield quantity = 5 if item.name == "Hazard Shield" else 1 return resource_database.get_item(base_resource), quantity return PickupEntry( name=item.name, progression=tuple( _create_resources(progression) for progression in item.progression), extra_resources=tuple(extra_resources), model=PickupModel( game=resource_database.game_enum, name=item.model_name, ), item_category=item.item_category, broad_category=item.broad_category, probability_offset=item.probability_offset, probability_multiplier=item.probability_multiplier * state.priority, unlocks_resource=item.unlocks_ammo, respects_lock=ammo_requires_major_item, resource_lock=ammo.create_resource_lock(resource_database) if ammo is not None else None, )
def create_useless_pickup(resource_database: ResourceDatabase) -> PickupEntry: """ Creates an Energy Transfer Module pickup. :param resource_database: :return: """ return PickupEntry( name="Energy Transfer Module", resources=(ConditionalResources( None, None, tuple([(resource_database.get_item(USELESS_PICKUP_ITEM), 1)])), ), model_index=USELESS_PICKUP_MODEL, item_category=ItemCategory.ETM, broad_category=ItemCategory.ETM, )
def create_artifact( artifact_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: return PickupEntry( name=prime_items.ARTIFACT_NAMES[artifact_index], resources=(ConditionalResources( None, None, tuple([(resource_database.get_item( prime_items.ARTIFACT_ITEMS[artifact_index]), 1), (resource_database.item_percentage, 1)])), ), model_index=prime_items.ARTIFACT_MODEL[artifact_index], item_category=ItemCategory.TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=0.25, )
def create_artifact(artifact_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: return PickupEntry( name=prime_items.ARTIFACT_NAMES[artifact_index], progression=( (resource_database.get_item(prime_items.ARTIFACT_ITEMS[artifact_index]), 1), ), model=PickupModel( game=resource_database.game_enum, name=prime_items.ARTIFACT_MODEL[artifact_index], ), item_category=ItemCategory.TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=0.25, )
def create_echoes_useless_pickup( resource_database: ResourceDatabase) -> PickupEntry: """ Creates an Energy Transfer Module pickup. :param resource_database: :return: """ return PickupEntry( name="Energy Transfer Module", progression=((resource_database.get_item( echoes_items.USELESS_PICKUP_ITEM), 1), ), model=PickupModel( game=resource_database.game_enum, name=echoes_items.USELESS_PICKUP_MODEL, ), item_category=USELESS_ITEM_CATEGORY, broad_category=USELESS_ITEM_CATEGORY, )
def create_sky_temple_key(key_number: int, resource_database: ResourceDatabase, ) -> PickupEntry: """ :param key_number: :param resource_database: :return: """ return PickupEntry( name="Sky Temple Key {}".format(key_number + 1), progression=((resource_database.get_item(echoes_items.SKY_TEMPLE_KEY_ITEMS[key_number]), 1),), model=PickupModel( game=resource_database.game_enum, name=echoes_items.SKY_TEMPLE_KEY_MODEL, ), item_category=ItemCategory.SKY_TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=3, )
def create_dark_temple_key(key_number: int, temple_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: """ Creates a Dark Temple Key :param key_number: :param temple_index: The index of the temple: Dark Agon, Dark Torvus, Hive Temple :param resource_database: :return: """ return PickupEntry( name=echoes_items.DARK_TEMPLE_KEY_NAMES[temple_index].format(key_number + 1), progression=((resource_database.get_item(echoes_items.DARK_TEMPLE_KEY_ITEMS[temple_index][key_number]), 1),), model=PickupModel( game=resource_database.game_enum, name=echoes_items.DARK_TEMPLE_KEY_MODEL, ), item_category=ItemCategory.TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=3, )
def create_dark_temple_key( key_number: int, temple_index: int, resource_database: ResourceDatabase, ) -> PickupEntry: """ Creates a Dark Temple Key :param key_number: :param temple_index: The index of the temple: Dark Agon, Dark Torvus, Hive Temple :param resource_database: :return: """ return PickupEntry( name=DARK_TEMPLE_KEY_NAMES[temple_index].format(key_number + 1), resources=(ConditionalResources( None, None, tuple([(resource_database.get_item( DARK_TEMPLE_KEY_ITEMS[temple_index][key_number]), 1)])), ), model_index=DARK_TEMPLE_KEY_MODEL, item_category=ItemCategory.TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=3, )
def create_sky_temple_key( key_number: int, resource_database: ResourceDatabase, ) -> PickupEntry: """ :param key_number: :param resource_database: :return: """ return PickupEntry( name="Sky Temple Key {}".format(key_number + 1), resources=(ConditionalResources( None, None, tuple([ (resource_database.get_item(SKY_TEMPLE_KEY_ITEMS[key_number]), 1) ])), ), model_index=SKY_TEMPLE_KEY_MODEL, item_category=ItemCategory.SKY_TEMPLE_KEY, broad_category=ItemCategory.KEY, probability_offset=3, )
def create_major_item( item: MajorItem, state: MajorItemState, include_percentage: bool, resource_database: ResourceDatabase, ammo: Optional[Ammo], ammo_requires_major_item: bool, ) -> PickupEntry: """ Creates a Pickup for the given MajorItem :param include_percentage: :param state: :param item: :param resource_database: :param ammo: :param ammo_requires_major_item: :return: """ def _create_resources( base_resource: Optional[int], temporary_ammo: bool = False) -> Tuple[ResourceQuantity, ...]: resources = [] if base_resource is not None: resources.append((resource_database.get_item(base_resource), 1)) for ammo_index, ammo_count in zip( ammo.temporaries if temporary_ammo else item.ammo_index, state.included_ammo): resources.append( (resource_database.get_item(ammo_index), ammo_count)) if include_percentage: resources.append((resource_database.item_percentage, 1)) return tuple(resources) if item.progression: if ammo_requires_major_item and ammo.unlocked_by != item.progression[ 0] and ammo.unlocked_by is not None: if len(item.progression) != 1: raise InvalidConfiguration(( "Item {item.name} uses ammo {ammo.name} that is locked behind {ammo.unlocked_by}," "but it also has progression. This is unsupported." ).format( ammo=ammo, item=item, )) name = resource_database.get_item(item.progression[0]).long_name conditional_resources = (ConditionalResources( name=name, item=None, resources=_create_resources(item.progression[0], True)), ConditionalResources( name=name, item=resource_database.get_item( ammo.unlocked_by), resources=_create_resources( item.progression[0]))) else: conditional_resources = tuple( ConditionalResources( name=resource_database.get_item( item.progression[i]).long_name, item=resource_database.get_item(item.progression[i - 1] ) if i > 0 else None, resources=_create_resources(progression)) for i, progression in enumerate(item.progression)) else: conditional_resources = (ConditionalResources( name=item.name, item=None, resources=_create_resources(None)), ) if item.converts_indices: assert len(item.converts_indices) == len(item.ammo_index) convert_resources = tuple( ResourceConversion( source=resource_database.get_item(source), target=resource_database.get_item(target), ) for source, target in zip(item.converts_indices, item.ammo_index)) else: convert_resources = tuple() return PickupEntry( name=item.name, resources=conditional_resources, model_index=item.model_index, item_category=item.item_category, broad_category=item.broad_category, probability_offset=item.probability_offset, probability_multiplier=item.probability_multiplier, convert_resources=convert_resources, )