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:
Scipio Wright 2023-07-18 22:51:01 -04:00 committed by GitHub
parent 83387da6a4
commit 8360435607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 22 deletions

View File

@ -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])
)

View File

@ -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)

View File

@ -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,
}

View File

@ -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"},
###

View File

@ -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)

View File

@ -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()