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",
|
||||
"Chaos Die", "Greed Die", "Kammi", "Refreshing Gourd", "Sädekivi", "Broken Wand",
|
||||
"Powder Pouch"}
|
||||
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"]
|
||||
|
||||
|
||||
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