Noita: Implement Extra Orbs, Shop Price Reduction, and some slight region tweaks (#1972)
Co-authored-by: Adam Heinermann <aheinerm@gmail.com>
This commit is contained in:
		
							parent
							
								
									83387da6a4
								
							
						
					
					
						commit
						8360435607
					
				|  | @ -1,13 +1,13 @@ | |||
| import itertools | ||||
| from collections import Counter | ||||
| from typing import Dict, List, NamedTuple, Optional, Set | ||||
| from typing import Dict, List, NamedTuple, Set | ||||
| 
 | ||||
| from BaseClasses import Item, ItemClassification, MultiWorld | ||||
| from .Options import BossesAsChecks, VictoryCondition | ||||
| from .Options import BossesAsChecks, VictoryCondition, ExtraOrbs | ||||
| 
 | ||||
| 
 | ||||
| class ItemData(NamedTuple): | ||||
|     code: Optional[int] | ||||
|     code: int | ||||
|     group: str | ||||
|     classification: ItemClassification = ItemClassification.progression | ||||
|     required_num: int = 0 | ||||
|  | @ -27,12 +27,12 @@ def create_fixed_item_pool() -> List[str]: | |||
|     return list(Counter(required_items).elements()) | ||||
| 
 | ||||
| 
 | ||||
| def create_orb_items(victory_condition: VictoryCondition) -> List[str]: | ||||
|     orb_count = 0 | ||||
| def create_orb_items(victory_condition: VictoryCondition, extra_orbs: ExtraOrbs) -> List[str]: | ||||
|     orb_count = extra_orbs.value | ||||
|     if victory_condition == VictoryCondition.option_pure_ending: | ||||
|         orb_count = 11 | ||||
|         orb_count = orb_count + 11 | ||||
|     elif victory_condition == VictoryCondition.option_peaceful_ending: | ||||
|         orb_count = 33 | ||||
|         orb_count = orb_count + 33 | ||||
|     return ["Orb" for _ in range(orb_count)] | ||||
| 
 | ||||
| 
 | ||||
|  | @ -61,7 +61,7 @@ def create_all_items(multiworld: MultiWorld, player: int) -> None: | |||
| 
 | ||||
|     itempool = ( | ||||
|         create_fixed_item_pool() | ||||
|         + create_orb_items(multiworld.victory_condition[player]) | ||||
|         + create_orb_items(multiworld.victory_condition[player], multiworld.extra_orbs[player]) | ||||
|         + create_spatial_awareness_item(multiworld.bosses_as_checks[player]) | ||||
|         + create_kantele(multiworld.victory_condition[player]) | ||||
|     ) | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| # Locations are specific points that you would obtain an item at. | ||||
| from enum import IntEnum | ||||
| from typing import Dict, NamedTuple, Optional | ||||
| from typing import Dict, NamedTuple, Optional, Set | ||||
| 
 | ||||
| from BaseClasses import Location | ||||
| 
 | ||||
|  | @ -12,7 +12,7 @@ class NoitaLocation(Location): | |||
| class LocationData(NamedTuple): | ||||
|     id: int | ||||
|     flag: int = 0 | ||||
|     ltype: Optional[str] = "" | ||||
|     ltype: Optional[str] = "shop" | ||||
| 
 | ||||
| 
 | ||||
| class LocationFlag(IntEnum): | ||||
|  | @ -208,7 +208,16 @@ def generate_location_entries(locname: str, locinfo: LocationData) -> Dict[str, | |||
|     return {locname: locinfo.id} | ||||
| 
 | ||||
| 
 | ||||
| location_name_groups: Dict[str, Set[str]] = {"shop": set(), "orb": set(), "boss": set(), "chest": set(), | ||||
|                                              "pedestal": set()} | ||||
| location_name_to_id: Dict[str, int] = {} | ||||
| 
 | ||||
| 
 | ||||
| for location_group in location_region_mapping.values(): | ||||
|     for locname, locinfo in location_group.items(): | ||||
|         location_name_to_id.update(generate_location_entries(locname, locinfo)) | ||||
|         if locinfo.ltype in ["chest", "pedestal"]: | ||||
|             for i in range(20): | ||||
|                 location_name_groups[locinfo.ltype].add(f"{locname} {i + 1}") | ||||
|         else: | ||||
|             location_name_groups[locinfo.ltype].add(locname) | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| from typing import Dict | ||||
| from Options import Choice, DeathLink, DefaultOnToggle, Option, Range | ||||
| from Options import AssembleOptions, Choice, DeathLink, DefaultOnToggle, Range, StartInventoryPool | ||||
| 
 | ||||
| 
 | ||||
| class PathOption(Choice): | ||||
|  | @ -66,9 +66,9 @@ class BossesAsChecks(Choice): | |||
| # The sampo is required for every ending (having orbs and bringing the sampo to a different spot changes the ending). | ||||
| class VictoryCondition(Choice): | ||||
|     """Greed is to get to the bottom, beat the boss, and win the game. | ||||
|     Pure is to get the 11 orbs in the main world, grab the sampo, and bring it to the mountain altar. | ||||
|     Peaceful is to get all 33 orbs in main + parallel, grab the sampo, and bring it to the mountain altar. | ||||
|     Orbs will be added to the randomizer pool according to what victory condition you chose. | ||||
|     Pure is to get 11 orbs, grab the sampo, and bring it to the mountain altar. | ||||
|     Peaceful is to get all 33 orbs, grab the sampo, and bring it to the mountain altar. | ||||
|     Orbs will be added to the randomizer pool based on which victory condition you chose. | ||||
|     The base game orbs will not count towards these victory conditions.""" | ||||
|     display_name = "Victory Condition" | ||||
|     option_greed_ending = 0 | ||||
|  | @ -77,7 +77,30 @@ class VictoryCondition(Choice): | |||
|     default = 0 | ||||
| 
 | ||||
| 
 | ||||
| noita_options: Dict[str, type(Option)] = { | ||||
| class ExtraOrbs(Range): | ||||
|     """Add extra orbs to your item pool, to prevent you from needing to wait as long | ||||
|     for the last orb you need for your victory condition. | ||||
|     Extra orbs received past your victory condition's amount will be received as hearts instead. | ||||
|     Can be turned on for the Greed Ending goal, but will only really make it harder.""" | ||||
|     display_name = "Extra Orbs" | ||||
|     range_start = 0 | ||||
|     range_end = 10 | ||||
|     default = 0 | ||||
| 
 | ||||
| 
 | ||||
| class ShopPrice(Choice): | ||||
|     """Reduce the costs of Archipelago items in shops. | ||||
|     By default, the price of Archipelago items matches the price of wands at that shop.""" | ||||
|     display_name = "Shop Price Reduction" | ||||
|     option_full_price = 100 | ||||
|     option_25_percent_off = 75 | ||||
|     option_50_percent_off = 50 | ||||
|     option_75_percent_off = 25 | ||||
|     default = 100 | ||||
| 
 | ||||
| 
 | ||||
| noita_options: Dict[str, AssembleOptions] = { | ||||
|     "start_inventory_from_pool": StartInventoryPool, | ||||
|     "death_link": DeathLink, | ||||
|     "bad_effects": Traps, | ||||
|     "victory_condition": VictoryCondition, | ||||
|  | @ -86,4 +109,6 @@ noita_options: Dict[str, type(Option)] = { | |||
|     "pedestal_checks": PedestalChecks, | ||||
|     "orbs_as_checks": OrbsAsChecks, | ||||
|     "bosses_as_checks": BossesAsChecks, | ||||
|     "extra_orbs": ExtraOrbs, | ||||
|     "shop_price": ShopPrice, | ||||
| } | ||||
|  |  | |||
|  | @ -78,6 +78,7 @@ def create_all_regions_and_connections(multiworld: MultiWorld, player: int) -> N | |||
| # - Frozen Vault is connected to the Vault instead of the Snowy Wasteland due to similar difficulty | ||||
| # - Lake is connected to The Laboratory, since the boss is hard without specific set-ups (which means late game) | ||||
| # - Snowy Depths connects to Lava Lake orb since you need digging for it, so fairly early is acceptable | ||||
| # - Ancient Laboratory is connected to the Coal Pits, so that Ylialkemisti isn't sphere 1 | ||||
| noita_connections: Dict[str, Set[str]] = { | ||||
|     "Menu": {"Forest"}, | ||||
|     "Forest": {"Mines", "Floating Island", "Desert", "Snowy Wasteland"}, | ||||
|  | @ -96,12 +97,12 @@ noita_connections: Dict[str, Set[str]] = { | |||
|     "Lava Lake": {"Mines", "Abyss Orb Room"}, | ||||
|     "Abyss Orb Room": {"Lava Lake"}, | ||||
|     "Below Lava Lake": {"Snowy Depths"}, | ||||
|     "Dark Cave": {"Ancient Laboratory", "Collapsed Mines"}, | ||||
|     "Ancient Laboratory": {"Dark Cave"}, | ||||
|     "Dark Cave": {"Collapsed Mines"}, | ||||
|     "Ancient Laboratory": {"Coal Pits"}, | ||||
| 
 | ||||
|     ### | ||||
|     "Coal Pits Holy Mountain": {"Coal Pits"}, | ||||
|     "Coal Pits": {"Coal Pits Holy Mountain", "Fungal Caverns", "Snowy Depths Holy Mountain"}, | ||||
|     "Coal Pits": {"Coal Pits Holy Mountain", "Fungal Caverns", "Snowy Depths Holy Mountain", "Ancient Laboratory"}, | ||||
|     "Fungal Caverns": {"Coal Pits"}, | ||||
| 
 | ||||
|     ### | ||||
|  |  | |||
|  | @ -45,9 +45,9 @@ wand_tiers: List[str] = [ | |||
| ] | ||||
| 
 | ||||
| 
 | ||||
| items_hidden_from_shops: Set[str] = {"Gold (200)", "Gold (1000)", "Potion", "Random Potion", "Secret Potion", | ||||
| items_hidden_from_shops: List[str] = ["Gold (200)", "Gold (1000)", "Potion", "Random Potion", "Secret Potion", | ||||
|                                       "Chaos Die", "Greed Die", "Kammi", "Refreshing Gourd", "Sädekivi", "Broken Wand", | ||||
|                                      "Powder Pouch"} | ||||
|                                       "Powder Pouch"] | ||||
| 
 | ||||
| 
 | ||||
| perk_list: List[str] = list(filter(Items.item_is_perk, Items.item_table.keys())) | ||||
|  | @ -126,6 +126,19 @@ def holy_mountain_unlock_conditions(multiworld: MultiWorld, player: int) -> None | |||
|             ) | ||||
| 
 | ||||
| 
 | ||||
| def biome_unlock_conditions(multiworld: MultiWorld, player: int): | ||||
|     lukki_entrances = multiworld.get_region("Lukki Lair", player).entrances | ||||
|     magical_entrances = multiworld.get_region("Magical Temple", player).entrances | ||||
|     wizard_entrances = multiworld.get_region("Wizards' Den", player).entrances | ||||
|     for entrance in lukki_entrances: | ||||
|         entrance.access_rule = lambda state: state.has("Melee Immunity Perk", player) and\ | ||||
|                                              state.has("All-Seeing Eye Perk", player) | ||||
|     for entrance in magical_entrances: | ||||
|         entrance.access_rule = lambda state: state.has("All-Seeing Eye Perk", player) | ||||
|     for entrance in wizard_entrances: | ||||
|         entrance.access_rule = lambda state: state.has("All-Seeing Eye Perk", player) | ||||
| 
 | ||||
| 
 | ||||
| def victory_unlock_conditions(multiworld: MultiWorld, player: int) -> None: | ||||
|     victory_condition = multiworld.victory_condition[player].value | ||||
|     victory_location = multiworld.get_location("Victory", player) | ||||
|  | @ -146,6 +159,7 @@ def create_all_rules(multiworld: MultiWorld, player: int) -> None: | |||
|     ban_early_high_tier_wands(multiworld, player) | ||||
|     lock_holy_mountains_into_spheres(multiworld, player) | ||||
|     holy_mountain_unlock_conditions(multiworld, player) | ||||
|     biome_unlock_conditions(multiworld, player) | ||||
|     victory_unlock_conditions(multiworld, player) | ||||
| 
 | ||||
|     # Prevent the Map perk (used to find Toveri) from being on Toveri (boss) | ||||
|  |  | |||
|  | @ -30,7 +30,8 @@ class NoitaWorld(World): | |||
|     location_name_to_id = Locations.location_name_to_id | ||||
| 
 | ||||
|     item_name_groups = Items.item_name_groups | ||||
|     data_version = 1 | ||||
|     location_name_groups = Locations.location_name_groups | ||||
|     data_version = 2 | ||||
| 
 | ||||
|     web = NoitaWeb() | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue