def gate_assignment_for_configuration(configuration: EchoesConfiguration, resource_database: ResourceDatabase, rng: Random, ) -> GateAssignment: """ :param configuration: :param resource_database: :param rng: :return: """ all_choices = list(LayoutTranslatorRequirement) all_choices.remove(LayoutTranslatorRequirement.RANDOM) all_choices.remove(LayoutTranslatorRequirement.RANDOM_WITH_REMOVED) without_removed = copy.copy(all_choices) without_removed.remove(LayoutTranslatorRequirement.REMOVED) random_requirements = {LayoutTranslatorRequirement.RANDOM, LayoutTranslatorRequirement.RANDOM_WITH_REMOVED} result = {} for gate, requirement in configuration.translator_configuration.translator_requirement.items(): if requirement in random_requirements: if rng is None: raise MissingRng("Translator") requirement = rng.choice(all_choices if requirement == LayoutTranslatorRequirement.RANDOM_WITH_REMOVED else without_removed) result[gate] = resource_database.get_by_type_and_index(ResourceType.ITEM, requirement.item_index) return result
def gate_assignment_for_configuration( configuration: LayoutConfiguration, resource_database: ResourceDatabase, rng: Random, ) -> GateAssignment: """ :param configuration: :param resource_database: :param rng: :return: """ choices = list(LayoutTranslatorRequirement) choices.remove(LayoutTranslatorRequirement.RANDOM) result = {} for gate, requirement in configuration.translator_configuration.translator_requirement.items( ): if requirement == LayoutTranslatorRequirement.RANDOM: if rng is None: raise MissingRng("Translator") requirement = rng.choice(choices) result[gate] = resource_database.get_by_type_and_index( ResourceType.ITEM, requirement.item_index) return result
def patch_resource_database( self, db: ResourceDatabase, configuration: BaseConfiguration) -> ResourceDatabase: base_damage_reduction = db.base_damage_reduction damage_reductions = copy.copy(db.damage_reductions) requirement_template = copy.copy(db.requirement_template) suits = [db.get_item_by_name("Varia Suit")] if configuration.heat_protection_only_varia: requirement_template["Heat-Resisting Suit"] = ResourceRequirement( db.get_item_by_name("Varia Suit"), 1, False) else: suits.extend([ db.get_item_by_name("Gravity Suit"), db.get_item_by_name("Phazon Suit") ]) reductions = [DamageReduction(None, configuration.heat_damage / 10.0)] reductions.extend([DamageReduction(suit, 0) for suit in suits]) damage_reductions[db.get_by_type_and_index(ResourceType.DAMAGE, "HeatDamage1")] = reductions if configuration.progressive_damage_reduction: base_damage_reduction = self.prime1_progressive_damage_reduction else: base_damage_reduction = self.prime1_absolute_damage_reduction return dataclasses.replace(db, damage_reductions=damage_reductions, base_damage_reduction=base_damage_reduction, requirement_template=requirement_template)
def with_data(cls, database: ResourceDatabase, resource_type: ResourceType, requirement_name: str, amount: int, negate: bool) -> ResourceRequirement: return cls.create( database.get_by_type_and_index(resource_type, requirement_name), amount, negate, )
def read_resource_reductions_dict( data: List[Dict], db: ResourceDatabase, ) -> Dict[SimpleResourceInfo, List[DamageReduction]]: return { db.get_by_type_and_index(ResourceType.DAMAGE, item["name"]): read_damage_reductions(item["reductions"], db.item) for item in data }
def with_data(cls, database: ResourceDatabase, resource_type: ResourceType, requirement_index: int, amount: int, negate: bool) -> "IndividualRequirement": return cls( database.get_by_type_and_index(resource_type, requirement_index), amount, negate)
def patch_resource_database( self, db: ResourceDatabase, configuration: BaseConfiguration) -> ResourceDatabase: damage_reductions = copy.copy(db.damage_reductions) damage_reductions[db.get_by_type_and_index( ResourceType.DAMAGE, "DarkWorld1")] = [ DamageReduction(None, configuration.varia_suit_damage / 6.0), DamageReduction(db.get_item_by_name("Dark Suit"), configuration.dark_suit_damage / 6.0), DamageReduction(db.get_item_by_name("Light Suit"), 0.0), ] return dataclasses.replace(db, damage_reductions=damage_reductions)
def static_resources_for_layout_logic( configuration: TrickLevelConfiguration, resource_database: ResourceDatabase, ) -> Tuple[int, CurrentResources]: """ :param configuration: :param resource_database: :return: """ all_used_tricks = TrickLevelConfiguration.all_possible_tricks() static_resources = {} for trick in resource_database.trick: if trick.index in all_used_tricks: static_resources[trick] = configuration.level_for_trick( trick).as_number # Exclude from Room Rando static_resources[resource_database.get_by_type_and_index( ResourceType.TRICK, 18)] = 5 return configuration.global_level.as_number, static_resources
def test_minimum_satisfied_difficulty(database: ResourceDatabase, resources, expected_level): res_a, id_req_a = make_req_a() res_b, id_req_b = make_req_b() res_c, id_req_c = make_req_c() the_set = RequirementSet([ RequirementList(0, [id_req_a]), RequirementList(1, [ id_req_b, IndividualRequirement(database.difficulty_resource, 1, False) ]), RequirementList(2, [ id_req_c, IndividualRequirement(database.difficulty_resource, 2, False) ]), ]) res = { database.get_by_type_and_index(ResourceType.ITEM, x): 1 for x in resources } res[database.difficulty_resource] = 10 diff = the_set.minimum_satisfied_difficulty(res, 99) assert diff == expected_level
def _get_item( resource_database: ResourceDatabase, index: int, ) -> SimpleResourceInfo: return resource_database.get_by_type_and_index(ResourceType.ITEM, index)
def pool_creator(results: PoolResults, configuration: BaseConfiguration, db: ResourceDatabase, base_patches: GamePatches, rng: Random) -> None: assert isinstance(configuration, CSConfiguration) if rng is None: raise MissingRng("Pool Creator") if base_patches is None: return def get_valid_indices(indices): return [p for p in indices if p not in results.assignment.keys()] def get_valid_pickups(pickups): pickup_iter = lambda w: (p for p in results.pickups if p.name == w) return [ next(pickup_iter(w)) for w in pickups if next(pickup_iter(w), None) is not None ] # puppies if not configuration.puppies_anywhere: puppy_indices = get_valid_indices(PUPPY_INDICES) rng.shuffle(puppy_indices) puppies: list[PickupEntry] = list( filter(lambda p: p.item_category.name == "puppies", results.pickups)) for p in puppies: results.pickups.remove(p) results.assignment[puppy_indices.pop()] = p # weapon to break blocks in first cave (do it this way to ensure a particular distribution chance) if base_patches.starting_location.area_name in { "Start Point", "First Cave", "Hermit Gunsmith" }: sn_weapons = list(SN_WEAPONS) bubble_sn = db.get_by_type_and_index(ResourceType.TRICK, "SNBubbler") missile_sn = db.get_by_type_and_index(ResourceType.TRICK, "SNMissiles") if configuration.trick_level.level_for_trick(bubble_sn).is_enabled: sn_weapons.append("Bubbler") if configuration.trick_level.level_for_trick(missile_sn).is_enabled: sn_weapons.extend({ "Missile Launcher", "Super Missile Launcher", "Progressive Missile Launcher" }) sn_weapons = get_valid_pickups(sn_weapons) first_cave_indices = get_valid_indices(FIRST_CAVE_INDICES) if first_cave_indices and sn_weapons: index = rng.choice(first_cave_indices) weapon = rng.choice(sn_weapons) results.pickups.remove(weapon) results.assignment[index] = weapon # strong weapon and life capsule in camp if base_patches.starting_location.area_name == "Camp": strong_weapons = get_valid_pickups(STRONG_WEAPONS) life_capsules = get_valid_pickups(["5HP Life Capsule"]) camp_indices = get_valid_indices(CAMP_INDICES) rng.shuffle(camp_indices) if camp_indices and strong_weapons: results.assignment[camp_indices.pop()] = rng.choice(strong_weapons) if camp_indices and life_capsules: results.assignment[camp_indices.pop()] = rng.choice(life_capsules)