TUNIC: Breakable Shuffle (#4489)
* Starting out * Rules for breakable regions * make the rest of it work, it's pr ready, boom * Make it work in not pot shuffle * Fix after merge * Fix item id overlap * Move breakable, grass, and local fill options in yaml * Fix groups getting overwritten * Rename, add new breakables * Rename more stuff * Time to rename them again * Make it actually default for breakable shuffle * Burn the signs down * Fix west courtyard pot regions * Fix fortress courtyard and beneath the fortress loc groups again * More missing loc group conversions * Replace instances of world.player with player, same for multiworld * Update worlds/tunic/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Remove unused import
This commit is contained in:
@@ -13,10 +13,10 @@ from .er_data import portal_mapping, RegionInfo, tunic_er_regions
|
||||
from .options import (TunicOptions, EntranceRando, tunic_option_groups, tunic_option_presets, TunicPlandoConnections,
|
||||
LaurelsLocation, LogicRules, LaurelsZips, IceGrappling, LadderStorage, check_options,
|
||||
get_hexagons_in_pool, HexagonQuestAbilityUnlockType)
|
||||
from .breakables import breakable_location_name_to_id, breakable_location_groups, breakable_location_table
|
||||
from .combat_logic import area_data, CombatState
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
from Options import PlandoConnection, OptionError
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
from settings import Group, Bool
|
||||
|
||||
|
||||
@@ -81,10 +81,13 @@ class TunicWorld(World):
|
||||
location_name_groups = location_name_groups
|
||||
for group_name, members in grass_location_name_groups.items():
|
||||
location_name_groups.setdefault(group_name, set()).update(members)
|
||||
for group_name, members in breakable_location_groups.items():
|
||||
location_name_groups.setdefault(group_name, set()).update(members)
|
||||
|
||||
item_name_to_id = item_name_to_id
|
||||
location_name_to_id = standard_location_name_to_id.copy()
|
||||
location_name_to_id.update(grass_location_name_to_id)
|
||||
location_name_to_id.update(breakable_location_name_to_id)
|
||||
|
||||
player_location_table: Dict[str, int]
|
||||
ability_unlocks: Dict[str, int]
|
||||
@@ -158,6 +161,7 @@ class TunicWorld(World):
|
||||
self.options.entrance_rando.value = self.passthrough["entrance_rando"]
|
||||
self.options.shuffle_ladders.value = self.passthrough["shuffle_ladders"]
|
||||
self.options.grass_randomizer.value = self.passthrough.get("grass_randomizer", 0)
|
||||
self.options.breakable_shuffle.value = self.passthrough.get("breakable_shuffle", 0)
|
||||
self.options.fixed_shop.value = self.options.fixed_shop.option_false
|
||||
self.options.laurels_location.value = self.options.laurels_location.option_anywhere
|
||||
self.options.combat_logic.value = self.passthrough["combat_logic"]
|
||||
@@ -170,7 +174,12 @@ class TunicWorld(World):
|
||||
|
||||
if self.options.local_fill == -1:
|
||||
if self.options.grass_randomizer:
|
||||
self.options.local_fill.value = 95
|
||||
if self.options.breakable_shuffle:
|
||||
self.options.local_fill.value = 96
|
||||
else:
|
||||
self.options.local_fill.value = 95
|
||||
elif self.options.breakable_shuffle:
|
||||
self.options.local_fill.value = 40
|
||||
else:
|
||||
self.options.local_fill.value = 0
|
||||
|
||||
@@ -182,6 +191,13 @@ class TunicWorld(World):
|
||||
|
||||
self.player_location_table.update(grass_location_name_to_id)
|
||||
|
||||
if self.options.breakable_shuffle:
|
||||
if self.options.entrance_rando:
|
||||
self.player_location_table.update(breakable_location_name_to_id)
|
||||
else:
|
||||
self.player_location_table.update({name: num for name, num in breakable_location_name_to_id.items()
|
||||
if not name.startswith("Purgatory")})
|
||||
|
||||
@classmethod
|
||||
def stage_generate_early(cls, multiworld: MultiWorld) -> None:
|
||||
tunic_worlds: Tuple[TunicWorld] = multiworld.get_game_worlds("TUNIC")
|
||||
@@ -258,7 +274,8 @@ class TunicWorld(World):
|
||||
itemclass: ItemClassification = (classification
|
||||
or (item_data.combat_ic if self.options.combat_logic else None)
|
||||
or (ItemClassification.progression | ItemClassification.useful
|
||||
if name == "Glass Cannon" and self.options.grass_randomizer
|
||||
if name == "Glass Cannon"
|
||||
and (self.options.grass_randomizer or self.options.breakable_shuffle)
|
||||
and not self.options.start_with_sword else None)
|
||||
or (ItemClassification.progression | ItemClassification.useful
|
||||
if name == "Shield" and self.options.ladder_storage
|
||||
@@ -280,6 +297,13 @@ class TunicWorld(World):
|
||||
items_to_create["Fool Trap"] += items_to_create[money_fool]
|
||||
items_to_create[money_fool] = 0
|
||||
|
||||
# creating these after the fool traps are made mostly so we don't have to mess with it
|
||||
if self.options.breakable_shuffle:
|
||||
for loc_data in breakable_location_table.values():
|
||||
if not self.options.entrance_rando and loc_data.er_region == "Purgatory":
|
||||
continue
|
||||
items_to_create[f"Money x{self.random.randint(1, 5)}"] += 1
|
||||
|
||||
if self.options.start_with_sword:
|
||||
self.multiworld.push_precollected(self.create_item("Sword"))
|
||||
|
||||
@@ -472,9 +496,9 @@ class TunicWorld(World):
|
||||
self.ability_unlocks["Pages 42-43 (Holy Cross)"] = self.passthrough["Hexagon Quest Holy Cross"]
|
||||
self.ability_unlocks["Pages 52-53 (Icebolt)"] = self.passthrough["Hexagon Quest Icebolt"]
|
||||
|
||||
# Ladders and Combat Logic uses ER rules with vanilla connections for easier maintenance
|
||||
# Most non-standard options use ER regions
|
||||
if (self.options.entrance_rando or self.options.shuffle_ladders or self.options.combat_logic
|
||||
or self.options.grass_randomizer):
|
||||
or self.options.grass_randomizer or self.options.breakable_shuffle):
|
||||
portal_pairs = create_er_regions(self)
|
||||
if self.options.entrance_rando:
|
||||
# these get interpreted by the game to tell it which entrances to connect
|
||||
@@ -502,9 +526,9 @@ class TunicWorld(World):
|
||||
victory_region.locations.append(victory_location)
|
||||
|
||||
def set_rules(self) -> None:
|
||||
# same reason as in create_regions, could probably be put into create_regions
|
||||
# same reason as in create_regions
|
||||
if (self.options.entrance_rando or self.options.shuffle_ladders or self.options.combat_logic
|
||||
or self.options.grass_randomizer):
|
||||
or self.options.grass_randomizer or self.options.breakable_shuffle):
|
||||
set_er_location_rules(self)
|
||||
else:
|
||||
set_region_rules(self)
|
||||
@@ -609,6 +633,7 @@ class TunicWorld(World):
|
||||
"Hexagon Quest Goal": self.options.hexagon_goal.value,
|
||||
"Entrance Rando": self.tunic_portal_pairs,
|
||||
"disable_local_spoiler": int(self.settings.disable_local_spoiler or self.multiworld.is_race),
|
||||
"breakable_shuffle": self.options.breakable_shuffle.value,
|
||||
}
|
||||
|
||||
# this would be in a stage if there was an appropriate stage for it
|
||||
|
||||
Reference in New Issue
Block a user