TUNIC: Fuse and Bell Shuffle (#5420)
* Making the fix better (thanks medic) * Make it actually return false if it gets to the backup lists and fails them * Fix stuff after merge * Add outlet regions, create new regions as needed for them * Put together part of decoupled and direction pairs * make direction pairs work * Make decoupled work * Make fixed shop work again * Fix a few minor bugs * Fix a few minor bugs * Fix plando * god i love programming * Reorder portal list * Update portal sorter for variable shops * Add missing parameter * Some cleanup of prints and functions * Fix typo * it's aliiiiiive * Make seed groups not sync decoupled * Add test with full-shop plando * Fix bug with vanilla portals * Handle plando connections and direction pair errors * Update plando checking for decoupled * Fix typo * Fix exception text to be shorter * Add some more comments * Add todo note * Remove unused safety thing * Remove extra plando connections definition in options * Make seed groups in decoupled with overlapping but not fully overlapped plando connections interact nicely without messing with what the entrances look like in the spoiler log * Fix weird edge case that is technically user error * Add note to fixed shop * Fix parsing shop names in UT * Remove debug print * Actually make UT work * multiworld. to world. * Fix typo from merge * Make it so the shops show up in the entrance hints * Fix bug in ladder storage rules * Remove blank line * # Conflicts: # worlds/tunic/__init__.py # worlds/tunic/er_data.py # worlds/tunic/er_rules.py # worlds/tunic/er_scripts.py # worlds/tunic/rules.py # worlds/tunic/test/test_access.py * Fix issues after merge * Update plando connections stuff in docs * Make early bushes only contain grass * Fix library mistake * Backport changes to grass rando (#20) * Backport changes to grass rando * add_rule instead of set_rule for the special cases, add special cases for back of swamp laurels area cause I should've made a new region for the swamp upper entrance * Remove item name group for grass * Update grass rando option descriptions - Also ignore grass fill for single player games * Ignore grass fill option for solo rando * Update er_rules.py * Fix pre fill issue * Remove duplicate option * Add excluded grass locations back * Hide grass fill option from simple ui options page * Check for start with sword before setting grass rules * Update worlds/tunic/options.py Co-authored-by: Scipio Wright <scipiowright@gmail.com> * has_stick -> has_melee * has_stick -> has_melee * Add a failsafe for direction pairing * Fix playthrough crash bug * Remove init from logicmixin * Updates per code review (thanks hesto) * has_stick to has_melee in newer update * has_stick to has_melee in newer update * Exclude grass from get_filler_item_name - non-grass rando games were accidentally seeing grass items get shuffled in as filler, which is funny but probably shouldn't happen * Update worlds/tunic/__init__.py Co-authored-by: Scipio Wright <scipiowright@gmail.com> * Apply suggestions from code review Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Scipio Wright <scipiowright@gmail.com> * change the rest of grass_fill to local_fill * Filter out grass from filler_items * remove -> discard * Update worlds/tunic/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Starting out * Rules for breakable regions * # Conflicts: # worlds/tunic/__init__.py # worlds/tunic/combat_logic.py # worlds/tunic/er_data.py # worlds/tunic/er_rules.py # worlds/tunic/er_scripts.py * Cleanup more stuff after merge * Revert "Cleanup more stuff after merge" This reverts commit a6ee9a93da8f2fcc4413de6df6927b246017889d. * Revert "# Conflicts:" This reverts commit c74ccd74a45b6ad6b9abe6e339d115a0c98baf30. * Cleanup more stuff after merge * change has_stick to has_melee * Update grass list with combat logic regions * More fixes from combat logic merge * Fix some dumb stuff (#21) * Reorganize pre fill for grass * make the rest of it work, it's pr ready, boom * Make it work in not pot shuffle * Merge grass rando * multiworld -> world get_location, use has_any * Swap out region for West Garden Before Terry grass * Adjust west garden rules to add west combat region * Adjust grass regions for south checkpoint grass * Adjust grass regions for after terry grass * Adjust grass regions for west combat grass * Adjust grass regions for dagger house grass * Adjust grass regions for south checkpoint grass, adjust regions and rules for some related locations * Finish the remainder of the west garden grass, reformat ruined atoll a little * More hex quest updates - Implement page ability shuffle for hex quest - Fix keys behind bosses if hex goal is less than 3 - Added check to fix conflicting hex quest options - Add option to slot data * Change option comparison * Change option checking and fix some stuff - also keep prayer first on low hex counts * Update option defaulting * Update option checking * Fix option assignment again * Merge in hex hunt * Merge in changes * Clean up imports * Add ability type to UT stuff * merge it all * Make local fill work across pot and grass (to be adjusted later) * Make separate pools for the grass and non-grass fills * Fix id overlap * Update option description * Fix default * Reorder localfill option desc * Load the purgatory ones in * Adjustments after merge * Fully remove logicrules * Fix UT support with fixed shop option * Add breakable shuffle to the ut stuff * Make it load in a specific number of locations * Add Silent's spoiler log ability thing * Fix for groups * Fix for groups * Fix typo * Fix hex quest UT support * Use .get * UT fixes, classification fixes * Rename some locations * Adjust guard house names * Adjust guard house names * Rework create_item * Fix for plando connections * Rename, add new breakables * Rename more stuff * Time to rename them again * Fix issue with fixed shop + decoupled * Put in an exception to catch that error in the future * Update create_item to match main * Update spoiler log lines for hex abilities * Burn the signs down * Bring over the combat logic fix * Merge in combat logic fix * Silly static method thing * Move a few areas to before well instead of east forest * Add an all_random hidden option for dev stuff * Port over changes from main * Fix west courtyard pot regions * Remove debug prints * Fix fortress courtyard and beneath the fortress loc groups again * Add exception handling to deal with duplicate apworlds * Fix typo * More missing loc group conversions * Initial fuse shuffle stuff * Fix gun missing from combat_items, add new for combat logic cache, very slight refactor of check_combat_reqs to let it do the changeover in a less complicated fashion, fix area being a boss area rather than non-boss area for a check * Add fuse shuffle logic * reorder atoll statue rule * Update traversal reqs * Remove fuse shuffle from temple door * Combine rules and option checking * Add bell shuffle; fix fuse location groups * Fix portal rules not requiring prayer * Merge the grass laurels exit grass PR * Merge in fortress bridge PR * Do a little clean up * Fix a regression * Update after merge * Some more stuff * More Silent changes * Update more info section in game info page * Fix rules for atoll and swamp fuses * Precollect cathedral fuse in ER * actually just make the fuse useful instead of progression * Add it to the swamp and cath rules too * Fix cath fuse name * Minor fixes and edits * Some UT stuff * Fix a couple more groups * Move a bunch of UT stuff to its own file * Fix up a couple UT things * Couple minor ER fixes * Formatting change * UT poptracker stuff enabled since it's optional in one of the releases * Add author string to world class * Adjust local fill option name * Update ut_stuff to match the PR * Add exception handling for UT with old apworld * Fix missing tracker_world * Remove extra entrance from cath main -> elevator Entry <-> Elev exists, Entry <-> Main exists So no connection is needed between Main and Elev * Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal * Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal * Update for breakables poptracker * Backup and warnings instead * Update typing * Delete old regions and rules, move stuff to logic_helpers and constants * Delete now much less useful tests * Fix breakables map tracking * Add more comments to init * Add todo to grass.py * Fix up tests * Fully remove fixed_shop * Finish hard deprecating FixedShop * Fix zig skip showing up in decoupled fixed shop * Make local_fill show up on the website * Merge with main * Fixes after merge * More fixes after merge * oh right that's why it was there, circular imports * Swap {} to () * Add fuse and bell shuffle to seed groups since they're logically significant for entrance pairing --------- Co-authored-by: silent-destroyer <osilentdestroyer@gmail.com> Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
This commit is contained in:
@@ -3,11 +3,11 @@ from typing import FrozenSet, TYPE_CHECKING
|
||||
from BaseClasses import Region
|
||||
from worlds.generic.Rules import set_rule, add_rule, forbid_item
|
||||
|
||||
# from .bells import set_bell_location_rules
|
||||
from .bells import set_bell_location_rules
|
||||
from .combat_logic import has_combat_reqs
|
||||
from .constants import *
|
||||
from .er_data import Portal, get_portal_outlet_region
|
||||
# from .fuses import set_fuse_location_rules, has_fuses
|
||||
from .fuses import set_fuse_location_rules
|
||||
from .grass import set_grass_location_rules
|
||||
from .ladder_storage_data import ow_ladder_groups, region_ladders, easy_ls, medium_ls, hard_ls
|
||||
from .logic_helpers import (has_ability, has_ladder, has_melee, has_sword, has_lantern, has_mask, has_fuses,
|
||||
@@ -17,9 +17,6 @@ from .options import IceGrappling, LadderStorage, CombatLogic
|
||||
if TYPE_CHECKING:
|
||||
from . import TunicWorld
|
||||
|
||||
fuses_option = False # replace with options.shuffle_fuses when fuse shuffle is in
|
||||
bells_option = False # replace with options.shuffle_bells when bell shuffle is in
|
||||
|
||||
|
||||
def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_pairs: dict[Portal, Portal]) -> None:
|
||||
player = world.player
|
||||
@@ -334,8 +331,8 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
# nmg: ice grapple through temple door
|
||||
regions["Overworld"].connect(
|
||||
connecting_region=regions["Overworld Temple Door"],
|
||||
rule=lambda state: (state.has_all(("Ring Eastern Bell", "Ring Western Bell"), player) and not bells_option)
|
||||
or (state.has_all(("East Bell", "West Bell"), player) and bells_option)
|
||||
rule=lambda state: (state.has_all(("Ring Eastern Bell", "Ring Western Bell"), player) and not options.shuffle_bells)
|
||||
or (state.has_all(("East Bell", "West Bell"), player) and options.shuffle_bells)
|
||||
or has_ice_grapple_logic(False, IceGrappling.option_medium, state, world))
|
||||
|
||||
regions["Overworld Temple Door"].connect(
|
||||
@@ -671,9 +668,9 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
and (has_sword(state, player) or state.has_any((gun, fire_wand), player)))
|
||||
# shoot fuse and have the shot hit you mid-LS
|
||||
or (can_ladder_storage(state, world) and state.has(fire_wand, player)
|
||||
and options.ladder_storage >= LadderStorage.option_hard))) and not fuses_option)
|
||||
and options.ladder_storage >= LadderStorage.option_hard))) and not options.shuffle_fuses)
|
||||
or (state.has_all((atoll_northwest_fuse, atoll_northeast_fuse, atoll_southwest_fuse, atoll_southeast_fuse), player)
|
||||
and fuses_option))
|
||||
and options.shuffle_fuses))
|
||||
)
|
||||
|
||||
regions["Ruined Atoll Statue"].connect(
|
||||
@@ -804,12 +801,12 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
connecting_region=regions["Fortress Exterior from Overworld"],
|
||||
rule=lambda state: state.has(laurels, player)
|
||||
or (has_ability(prayer, state, world) and state.has(fortress_exterior_fuse_1, player)
|
||||
and fuses_option))
|
||||
and options.shuffle_fuses))
|
||||
regions["Fortress Exterior from Overworld"].connect(
|
||||
connecting_region=regions["Fortress Exterior near cave"],
|
||||
rule=lambda state: state.has(laurels, player)
|
||||
or (has_ability(prayer, state, world) and state.has(fortress_exterior_fuse_1, player)
|
||||
if fuses_option else has_ability(prayer, state, world)))
|
||||
if options.shuffle_fuses else has_ability(prayer, state, world)))
|
||||
|
||||
# shoot far fire pot, enemy gets aggro'd
|
||||
regions["Fortress Exterior near cave"].connect(
|
||||
@@ -880,7 +877,7 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
rule=lambda state: has_ice_grapple_logic(False, IceGrappling.option_easy, state, world)
|
||||
or (has_fuses("Activate Eastern Vault West Fuses", state, world)
|
||||
and has_fuses("Activate Eastern Vault East Fuse", state, world)
|
||||
and fuses_option))
|
||||
and options.shuffle_fuses))
|
||||
|
||||
fort_grave_entry_to_combat = regions["Fortress Grave Path Entry"].connect(
|
||||
connecting_region=regions["Fortress Grave Path Combat"])
|
||||
@@ -1027,18 +1024,18 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
connecting_region=regions["Rooted Ziggurat Lower Miniboss Platform"])
|
||||
zig_low_miniboss_to_mid = regions["Rooted Ziggurat Lower Miniboss Platform"].connect(
|
||||
connecting_region=regions["Rooted Ziggurat Lower Mid Checkpoint"],
|
||||
rule=lambda state: state.has(ziggurat_miniboss_fuse, player) if fuses_option
|
||||
rule=lambda state: state.has(ziggurat_miniboss_fuse, player) if options.shuffle_fuses
|
||||
else (has_sword(state, player) and has_ability(prayer, state, world)))
|
||||
# can ice grapple to the voidlings to get to the double admin fight, still need to pray at the fuse
|
||||
zig_low_miniboss_to_back = regions["Rooted Ziggurat Lower Miniboss Platform"].connect(
|
||||
connecting_region=regions["Rooted Ziggurat Lower Back"],
|
||||
rule=lambda state: state.has(laurels, player) or (state.has(ziggurat_miniboss_fuse, player) and fuses_option)
|
||||
or (has_sword(state, player) and has_ability(prayer, state, world) and not fuses_option))
|
||||
rule=lambda state: state.has(laurels, player) or (state.has(ziggurat_miniboss_fuse, player) and options.shuffle_fuses)
|
||||
or (has_sword(state, player) and has_ability(prayer, state, world) and not options.shuffle_fuses))
|
||||
regions["Rooted Ziggurat Lower Back"].connect(
|
||||
connecting_region=regions["Rooted Ziggurat Lower Miniboss Platform"],
|
||||
rule=lambda state: state.has(laurels, player)
|
||||
or has_ice_grapple_logic(True, IceGrappling.option_easy, state, world)
|
||||
or (state.has(ziggurat_miniboss_fuse, player) and fuses_option))
|
||||
or (state.has(ziggurat_miniboss_fuse, player) and options.shuffle_fuses))
|
||||
|
||||
regions["Rooted Ziggurat Lower Back"].connect(
|
||||
connecting_region=regions["Rooted Ziggurat Portal Room Entrance"],
|
||||
@@ -1086,8 +1083,8 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
and state.can_reach_region("Overworld Beach", player)))))
|
||||
and (not options.combat_logic
|
||||
or has_combat_reqs("Swamp", state, player))
|
||||
and not fuses_option)
|
||||
or (state.has_all((swamp_fuse_1, swamp_fuse_2, swamp_fuse_3), player) and fuses_option)
|
||||
and not options.shuffle_fuses)
|
||||
or (state.has_all((swamp_fuse_1, swamp_fuse_2, swamp_fuse_3), player) and options.shuffle_fuses)
|
||||
or has_ice_grapple_logic(False, IceGrappling.option_medium, state, world))
|
||||
|
||||
if options.ladder_storage >= LadderStorage.option_hard and options.shuffle_ladders:
|
||||
@@ -1096,7 +1093,7 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
regions["Swamp to Cathedral Main Entrance Region"].connect(
|
||||
connecting_region=regions["Swamp Mid"],
|
||||
rule=lambda state: has_ice_grapple_logic(False, IceGrappling.option_easy, state, world)
|
||||
or (state.has_all((swamp_fuse_1, swamp_fuse_2, swamp_fuse_3), player) and fuses_option))
|
||||
or (state.has_all((swamp_fuse_1, swamp_fuse_2, swamp_fuse_3), player) and options.shuffle_fuses))
|
||||
|
||||
# grapple push the enemy by the door down, then grapple to it. Really jank
|
||||
regions["Swamp Mid"].connect(
|
||||
@@ -1142,7 +1139,7 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
|
||||
cath_entry_to_elev = regions["Cathedral Entry"].connect(
|
||||
connecting_region=regions["Cathedral to Gauntlet"],
|
||||
rule=lambda state: ((state.has(cathedral_elevator_fuse, player) if fuses_option else has_ability(prayer, state, world))
|
||||
rule=lambda state: ((state.has(cathedral_elevator_fuse, player) if options.shuffle_fuses else has_ability(prayer, state, world))
|
||||
or has_ice_grapple_logic(False, IceGrappling.option_medium, state, world))
|
||||
or options.entrance_rando) # elevator is always there in ER
|
||||
regions["Cathedral to Gauntlet"].connect(
|
||||
@@ -1444,17 +1441,17 @@ def set_er_region_rules(world: "TunicWorld", regions: dict[str, Region], portal_
|
||||
lambda state: has_combat_reqs("Rooted Ziggurat", state, player))
|
||||
set_rule(zig_low_miniboss_to_back,
|
||||
lambda state: state.has(laurels, player)
|
||||
or (state.has(ziggurat_miniboss_fuse, player) if fuses_option
|
||||
or (state.has(ziggurat_miniboss_fuse, player) if options.shuffle_fuses
|
||||
else (has_ability(prayer, state, world) and has_combat_reqs("Rooted Ziggurat", state, player))))
|
||||
set_rule(zig_low_miniboss_to_mid,
|
||||
lambda state: state.has(ziggurat_miniboss_fuse, player) if fuses_option
|
||||
lambda state: state.has(ziggurat_miniboss_fuse, player) if options.shuffle_fuses
|
||||
else (has_ability(prayer, state, world) and has_combat_reqs("Rooted Ziggurat", state, player)))
|
||||
|
||||
# only activating the fuse requires combat logic
|
||||
set_rule(cath_entry_to_elev,
|
||||
lambda state: options.entrance_rando
|
||||
or has_ice_grapple_logic(False, IceGrappling.option_medium, state, world)
|
||||
or (state.has(cathedral_elevator_fuse, player) if fuses_option
|
||||
or (state.has(cathedral_elevator_fuse, player) if options.shuffle_fuses
|
||||
else (has_ability(prayer, state, world) and has_combat_reqs("Swamp", state, player))))
|
||||
|
||||
set_rule(cath_entry_to_main,
|
||||
@@ -1535,11 +1532,11 @@ def set_er_location_rules(world: "TunicWorld") -> None:
|
||||
if options.grass_randomizer:
|
||||
set_grass_location_rules(world)
|
||||
|
||||
# if options.shuffle_fuses:
|
||||
# set_fuse_location_rules(world)
|
||||
#
|
||||
# if options.shuffle_bells:
|
||||
# set_bell_location_rules(world)
|
||||
if options.shuffle_fuses:
|
||||
set_fuse_location_rules(world)
|
||||
|
||||
if options.shuffle_bells:
|
||||
set_bell_location_rules(world)
|
||||
|
||||
forbid_item(world.get_location("Secret Gathering Place - 20 Fairy Reward"), fairies, player)
|
||||
|
||||
@@ -1702,7 +1699,7 @@ def set_er_location_rules(world: "TunicWorld") -> None:
|
||||
and (state.has(laurels, player)
|
||||
or options.entrance_rando)))
|
||||
set_rule(world.get_location("Rooted Ziggurat Lower - After Guarded Fuse"),
|
||||
lambda state: state.has(ziggurat_miniboss_fuse, player) if fuses_option
|
||||
lambda state: state.has(ziggurat_miniboss_fuse, player) if options.shuffle_fuses
|
||||
else has_sword(state, player) and has_ability(prayer, state, world))
|
||||
|
||||
# Bosses
|
||||
@@ -1745,12 +1742,12 @@ def set_er_location_rules(world: "TunicWorld") -> None:
|
||||
lambda state: state.has(laurels, player))
|
||||
|
||||
# Events
|
||||
if not bells_option:
|
||||
if not options.shuffle_bells:
|
||||
set_rule(world.get_location("Eastern Bell"),
|
||||
lambda state: (has_melee(state, player) or state.has(fire_wand, player)))
|
||||
set_rule(world.get_location("Western Bell"),
|
||||
lambda state: (has_melee(state, player) or state.has(fire_wand, player)))
|
||||
if not fuses_option:
|
||||
if not options.shuffle_fuses:
|
||||
set_rule(world.get_location("Furnace Fuse"),
|
||||
lambda state: has_ability(prayer, state, world))
|
||||
set_rule(world.get_location("South and West Fortress Exterior Fuses"),
|
||||
@@ -1877,7 +1874,7 @@ def set_er_location_rules(world: "TunicWorld") -> None:
|
||||
|
||||
# could just do the last two, but this outputs better in the spoiler log
|
||||
# dagger is maybe viable here, but it's sketchy -- activate ladder switch, save to reset enemies, climb up
|
||||
if not fuses_option:
|
||||
if not options.shuffle_fuses:
|
||||
combat_logic_to_loc("Upper and Central Fortress Exterior Fuses", "Eastern Vault Fortress")
|
||||
combat_logic_to_loc("Beneath the Vault Fuse", "Beneath the Vault")
|
||||
combat_logic_to_loc("Eastern Vault West Fuses", "Eastern Vault Fortress")
|
||||
@@ -1896,10 +1893,10 @@ def set_er_location_rules(world: "TunicWorld") -> None:
|
||||
and (state.has(laurels, player) or world.options.entrance_rando))
|
||||
or has_combat_reqs("Rooted Ziggurat", state, player))
|
||||
set_rule(world.get_location("Rooted Ziggurat Lower - After Guarded Fuse"),
|
||||
lambda state: state.has(ziggurat_miniboss_fuse, player) if fuses_option
|
||||
lambda state: state.has(ziggurat_miniboss_fuse, player) if options.shuffle_fuses
|
||||
else (has_ability(prayer, state, world) and has_combat_reqs("Rooted Ziggurat", state, player)))
|
||||
|
||||
if fuses_option:
|
||||
if options.shuffle_fuses:
|
||||
set_rule(world.get_location("Rooted Ziggurat Lower - [Miniboss] Activate Fuse"),
|
||||
lambda state: has_ability(prayer, state, world) and has_combat_reqs("Rooted Ziggurat", state, player))
|
||||
combat_logic_to_loc("Beneath the Fortress - Activate Fuse", "Beneath the Vault")
|
||||
|
||||
Reference in New Issue
Block a user