Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed Forest with ER and adult start #1305

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions EntranceShuffle.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def build_one_way_targets(world, types_to_include, exclude=(), target_region_nam
('Graveyard Dampes Grave -> Graveyard', { 'index': 0x0359 })),

('Overworld', ('Kokiri Forest -> LW Bridge From Forest', { 'index': 0x05E0 }),
('LW Bridge -> Kokiri Forest', { 'index': 0x020D })),
('LW Bridge -> Kokiri Forest From Bridge', { 'index': 0x020D })),
('Overworld', ('Kokiri Forest -> Lost Woods', { 'index': 0x011E }),
('LW Forest Exit -> Kokiri Forest', { 'index': 0x0286 })),
('Overworld', ('Lost Woods -> GC Woods Warp', { 'index': 0x04E2 }),
Expand Down Expand Up @@ -398,11 +398,6 @@ def shuffle_random_entrances(worlds):

if worlds[0].shuffle_dungeon_entrances:
entrance_pools['Dungeon'] = world.get_shufflable_entrances(type='Dungeon', only_primary=True)
# The fill algorithm will already make sure gohma is reachable, however it can end up putting
# a forest escape via the hands of spirit on Deku leading to Deku on spirit in logic. This is
# not really a closed forest anymore, so specifically remove Deku Tree from closed forest.
if worlds[0].open_forest == 'closed':
entrance_pools['Dungeon'].remove(world.get_entrance('KF Outside Deku Tree -> Deku Tree Lobby'))

if worlds[0].shuffle_interior_entrances:
entrance_pools['Interior'] = world.get_shufflable_entrances(type='Interior', only_primary=True)
Expand All @@ -415,6 +410,14 @@ def shuffle_random_entrances(worlds):

if worlds[0].shuffle_overworld_entrances:
entrance_pools['Overworld'] = world.get_shufflable_entrances(type='Overworld')
if world.logic_rules == 'glitchless' and worlds[0].open_forest == 'closed' and worlds[0].starting_age == 'child' and \
worlds[0].logic_require_gohma and not (worlds[0].shuffle_special_interior_entrances or worlds[0].spawn_positions):
entrance_pools['Overworld'].remove(world.get_entrance('Kokiri Forest -> Lost Woods'))
entrance_pools['Overworld'].remove(world.get_entrance('LW Forest Exit -> Kokiri Forest'))
entrance_pools['Overworld'].remove(world.get_entrance('Lost Woods -> GC Woods Warp'))
entrance_pools['Overworld'].remove(world.get_entrance('GC Woods Warp -> Lost Woods'))
entrance_pools['Overworld'].remove(world.get_entrance('LW Beyond Mido -> SFM Entryway'))
entrance_pools['Overworld'].remove(world.get_entrance('SFM Entryway -> LW Beyond Mido'))

# Set shuffled entrances as such
for entrance in list(chain.from_iterable(one_way_entrance_pools.values())) + list(chain.from_iterable(entrance_pools.values())):
Expand Down Expand Up @@ -749,7 +752,8 @@ def validate_world(world, worlds, entrance_placed, locations_to_ensure_reachable
if impas_front_entrance is not None and impas_back_entrance is not None and not same_hint_area(impas_front_entrance, impas_back_entrance):
raise EntranceShuffleError('Kak Impas House entrances are not in the same hint area')

if (world.shuffle_special_interior_entrances or world.shuffle_overworld_entrances or world.spawn_positions) and \
if (world.shuffle_special_interior_entrances or world.spawn_positions or (world.shuffle_overworld_entrances and \
not (world.logic_rules == 'glitchless' and world.open_forest == 'closed' and world.starting_age == 'child' and world.logic_require_gohma))) and \
(entrance_placed == None or entrance_placed.type in ['SpecialInterior', 'Overworld', 'Spawn', 'WarpSong', 'OwlDrop']):
# At least one valid starting region with all basic refills should be reachable without using any items at the beginning of the seed
# Note this creates new empty states rather than reuse the worlds' states (which already have starting items)
Expand Down
90 changes: 59 additions & 31 deletions SettingsList.py
Original file line number Diff line number Diff line change
Expand Up @@ -1197,8 +1197,8 @@ def __init__(self, name, gui_text, min, max, default, step=1,
'tooltip' : '''\
A precise jump can be used to skip
needing to use the Slingshot to go
around B1 of the Deku Tree. If used
with the "Closed Forest" setting, a
around B1 of the Deku Tree. If using
"Closed Forest Requires Gohma", a
Slingshot will not be guaranteed to
exist somewhere inside the Forest.
This trick applies to both Vanilla
Expand Down Expand Up @@ -1882,31 +1882,28 @@ def __init__(self, name, gui_text, min, max, default, step=1,
'closed': 'Closed Forest',
},
gui_tooltip = '''\
'Open Forest': Mido no longer blocks the path to the
Deku Tree, and the Kokiri boy no longer blocks the path
out of the forest.

In the child era, Mido blocks the path to the Deku Tree,
and a Kokiri boy blocks the path out of the forest.
Mido requires the Kokiri Sword and a Deku Shield.
The Kokiri boy moves after Gohma is defeated.

'Open Forest': Both paths are always open.

'Closed Deku': The Kokiri boy no longer blocks the path
out of the forest, but Mido still blocks the path to the
Deku Tree, requiring Kokiri Sword and Deku Shield to access
the Deku Tree.

'Closed Forest': Beating Deku Tree is logically required
to leave the forest area (Kokiri Forest/Lost Woods/Sacred Forest
Meadow/Deku Tree), while the Kokiri Sword and a Deku Shield are
required to access the Deku Tree. Items needed for this will be
guaranteed inside the forest area. This setting is incompatible
with starting as adult, and so Starting Age will be locked to Child.
With either "Shuffle Interior Entrances" set to "All", "Shuffle
Overworld Entrances" on, "Randomize Warp Song Destinations" on
or "Randomize Overworld Spawns" on, Closed Forest will instead
be treated as Closed Deku with starting age Child and WILL NOT
guarantee that these items are available in the forest area.
out of the forest, but Mido still guards the Deku Tree.

'Closed Forest': The paths to the Deku Tree and out of
the forest are both blocked. Closed Forest requires
AT LEAST ONE of the following settings to apply:
- Starting as Child
- Open Door of Time
- Shuffle Overworld Entrances
- Shuffle Interior Entrances set to "All Interiors"
- Randomize Overworld Spawns
- Logic Rules set to "Glitched" or "No Logic"
Otherwise, it will instead be treated as Closed Deku.
''',
shared = True,
disable = {
'closed' : {'settings' : ['starting_age']}
},
gui_params = {
'randomize_key': 'randomize_settings',
'distribution': [
Expand Down Expand Up @@ -2021,7 +2018,7 @@ def __init__(self, name, gui_text, min, max, default, step=1,
choices = {
'open': 'Always Open',
'vanilla': 'Vanilla Requirements',
'stones': 'Spiritual Stones',
'stones': 'Spiritual Stones',
'medallions': 'Medallions',
'dungeons': 'Dungeons',
'tokens': 'Gold Skulltula Tokens'
Expand Down Expand Up @@ -2193,7 +2190,8 @@ def __init__(self, name, gui_text, min, max, default, step=1,
'glitched' : {'settings' : ['allowed_tricks', 'shuffle_interior_entrances', 'shuffle_grotto_entrances',
'shuffle_dungeon_entrances', 'shuffle_overworld_entrances', 'owl_drops',
'warp_songs', 'spawn_positions', 'mq_dungeons_random', 'mq_dungeons', ]},
'none' : {'settings' : ['allowed_tricks', 'logic_no_night_tokens_without_suns_song', 'reachable_locations']},
'none' : {'settings' : ['allowed_tricks', 'logic_no_night_tokens_without_suns_song', 'reachable_locations',
'logic_require_gohma', ]},
},
shared = True,
),
Expand Down Expand Up @@ -2414,11 +2412,44 @@ def __init__(self, name, gui_text, min, max, default, step=1,
Song to collect them. This prevents needing
to wait until night for some locations.
''',
gui_params={
gui_params = {
'no_line_break' : True,
'web:no_line_break' : False,
"hide_when_disabled": True,
},
shared = True,
),
Checkbutton(
name = 'logic_require_gohma',
gui_text = 'Closed Forest Requires Gohma',
gui_tooltip = '''\
If Closed Forest is enabled, beating Gohma is
logically required for accessing any overworld
area outside of Kokiri Forest, Lost Woods, and
Sacred Forest Meadow.

This typically guarantees that the Kokiri Sword, a
Deku Shield, and a Slingshot will be in the forest
or connected dungeons, interiors, and grottos.

Explosives, Silver Scale, Din's Fire, and warp songs,
with the exception of Minuet of Forest if warp song
destinations are not randomized, are not considered
in logic until Gohma is beaten because they can be
used to escape the forest early.

This will not apply with certain settings:
- Glitched logic
- Starting as Adult
- Shuffle Interior Entrances set to "All Interiors"
- Randomize Overworld Spawns
''',
gui_params = {
"hide_when_disabled": True,
},
default = True,
shared = True,
),
Checkbutton(
name = 'free_scarecrow',
gui_text = 'Free Scarecrow\'s Song',
Expand Down Expand Up @@ -3733,10 +3764,7 @@ def __init__(self, name, gui_text, min, max, default, step=1,
Choose which age Link will start as.

Starting as adult means you start with
the master sword in your inventory.

Only the child option is compatible with
Closed Forest.
the Master Sword in your inventory.
''',
shared = True,
gui_params = {
Expand Down
20 changes: 10 additions & 10 deletions World.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,8 @@ def __init__(self, id, settings):
self.entrance_shuffle = self.shuffle_interior_entrances or self.shuffle_grotto_entrances or self.shuffle_dungeon_entrances or \
self.shuffle_overworld_entrances or self.owl_drops or self.warp_songs or self.spawn_positions

self.ensure_tod_access = self.shuffle_interior_entrances or self.shuffle_overworld_entrances or self.spawn_positions
self.disable_trade_revert = self.shuffle_interior_entrances or self.shuffle_overworld_entrances

if self.open_forest == 'closed' and (self.shuffle_special_interior_entrances or self.shuffle_overworld_entrances or
self.warp_songs or self.spawn_positions):
self.open_forest = 'closed_deku'

self.triforce_goal = self.triforce_goal_per_world * settings.world_count

if self.triforce_hunt:
Expand Down Expand Up @@ -100,6 +95,15 @@ def __init__(self, id, settings):

self.resolve_random_settings()

if self.open_forest == 'closed' and self.starting_age == 'adult' and self.logic_rules == 'glitchless' and \
not (self.open_door_of_time or ('Ocarina' and 'Song of Time') in self.distribution.starting_items or \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'Ocarina' and 'Song of Time' just evaluates to 'Song of Time'.

self.shuffle_special_interior_entrances or self.shuffle_overworld_entrances or self.spawn_positions):
# adult is not compatible with glitchless closed forest without shuffled entrances or open door of time
Copy link
Collaborator

@fenhl fenhl Mar 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment explaining why this is the case would be nice. It took us a while to figure out why the Door of Time setting affects this in #dev-glitchless-logic.

self.open_forest = 'closed_deku'

self.ensure_tod_access = self.shuffle_special_interior_entrances or self.shuffle_overworld_entrances or self.spawn_positions or \
(self.open_forest == 'closed' and (self.starting_age == 'adult' or not self.logic_require_gohma))

if len(settings.hint_dist_user) == 0:
for d in HintDistFiles():
dist = read_json(d)
Expand Down Expand Up @@ -247,11 +251,7 @@ def resolve_random_settings(self):
self.starting_tod = random.choice(choices)
self.randomized_list.append('starting_tod')
if self.starting_age == 'random':
if self.settings.open_forest == 'closed':
# adult is not compatible
self.starting_age = 'child'
else:
self.starting_age = random.choice(['child', 'adult'])
self.starting_age = random.choice(['child', 'adult'])
self.randomized_list.append('starting_age')
if self.chicken_count_random:
self.chicken_count = random.randint(0, 7)
Expand Down
6 changes: 3 additions & 3 deletions data/Glitched World/Deku Tree MQ.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@
"region_name": "Deku Tree Boss Room",
"dungeon": "Deku Tree",
"events": {
"Deku Tree Clear": "Buy_Deku_Shield and (Kokiri_Sword or Sticks)"
"Defeat Gohma": "Buy_Deku_Shield and (Kokiri_Sword or Sticks)"
},
"locations": {
"Deku Tree MQ Before Spinning Log Chest": "True",
"Deku Tree MQ After Spinning Log Chest": "can_play(Song_of_Time)",
"Deku Tree MQ GS Basement Graves Room": "Boomerang and can_play(Song_of_Time)",
"Deku Tree MQ GS Basement Back Room": "Boomerang",
"Deku Tree MQ Deku Scrub": "True",
"Deku Tree Queen Gohma Heart": "Buy_Deku_Shield and (Kokiri_Sword or Sticks)",
"Queen Gohma": "Buy_Deku_Shield and (Kokiri_Sword or Sticks)"
"Deku Tree Queen Gohma Heart": "'Defeat Gohma'",
"Queen Gohma": "'Defeat Gohma'"
},
"exits": {
"Deku Tree Lobby": "True"
Expand Down
8 changes: 3 additions & 5 deletions data/Glitched World/Deku Tree.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,12 @@
"region_name": "Deku Tree Boss Room",
"dungeon": "Deku Tree",
"events": {
"Deku Tree Clear": "(Nuts or can_use(Slingshot) or has_bombchus or can_use(Hookshot) or can_use(Bow) or can_use(Boomerang)) and
"Defeat Gohma": "(Nuts or can_use(Slingshot) or has_bombchus or can_use(Hookshot) or can_use(Bow) or can_use(Boomerang)) and
((here(has_shield or can_use(Megaton_Hammer)) and (is_adult or Kokiri_Sword or Sticks)) or is_adult)"
},
"locations": {
"Deku Tree Queen Gohma Heart": "(Nuts or can_use(Slingshot) or has_bombchus or can_use(Hookshot) or can_use(Bow) or can_use(Boomerang)) and
((here(has_shield or can_use(Megaton_Hammer)) and (is_adult or Kokiri_Sword or Sticks)) or is_adult)",
"Queen Gohma": "(Nuts or can_use(Slingshot) or has_bombchus or can_use(Hookshot) or can_use(Bow) or can_use(Boomerang)) and
((here(has_shield or can_use(Megaton_Hammer)) and (is_adult or Kokiri_Sword or Sticks)) or is_adult)"
"Deku Tree Queen Gohma Heart": "'Defeat Gohma'",
"Queen Gohma": "'Defeat Gohma'"
},
"exits": {
"Deku Tree Lobby": "True"
Expand Down
2 changes: 1 addition & 1 deletion data/Glitched World/Forest Temple MQ.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"exits": {
"Forest Temple NE Outdoors": "
can_use(Iron_Boots) or can_use(Longshot) or
(Progressive_Scale, 2) or (logic_forest_well_swim and can_use(Hookshot))",
Golden_Scale or (logic_forest_well_swim and can_use(Hookshot))",
"Forest Temple Outdoors Top Ledges": "can_use(Fire_Arrows)"
}
},
Expand Down
2 changes: 1 addition & 1 deletion data/Glitched World/Forest Temple.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"exits": {
"Forest Temple Outdoors High Balconies": "can_use(Hookshot)",
#Longshot can grab some very high up vines to drain the well.
"Forest Temple NW Outdoors": "can_use(Iron_Boots) or (Progressive_Scale, 2)",
"Forest Temple NW Outdoors": "can_use(Iron_Boots) or Golden_Scale",
"Forest Temple Lobby": "True",
"Forest Temple Falling Room": "can_hover or
at('Forest Temple Outdoors High Balconies',
Expand Down
10 changes: 5 additions & 5 deletions data/Glitched World/Overworld.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"exits": {
"Kokiri Forest": "True",
"GC Woods Warp": "True",
"Zora River": "(can_dive or can_jumpslash) and can_leave_forest",
"Zora River": "(Silver_Scale or can_jumpslash) and can_leave_forest",
"LW Beyond Mido": "True",
"LW Near Shortcuts Grotto": "can_blast_or_smash"
#//Can Exit to Woods bridge with megaflip, but walking through kokiri forest is true anyway
Expand Down Expand Up @@ -230,7 +230,7 @@
},
"locations": {
"Pierre": "is_adult and Bonooru and not free_scarecrow",
"LH Underwater Item": "is_child and can_dive",
"LH Underwater Item": "is_child and Silver_Scale",
"LH Sun": "
is_adult and
(can_use(Distant_Scarecrow) or 'Water Temple Clear' or can_hover) and can_use(Bow)",
Expand Down Expand Up @@ -261,7 +261,7 @@
"region_name": "LH Lab",
"locations": {
"LH Lab Dive": "
(Progressive_Scale, 2) or
Golden_Scale or
(Iron_Boots and can_use(Hookshot)) or (has_bottle and can_use(Hover_Boots))",
"LH GS Lab Crate": "Iron_Boots and can_use(Hookshot)"
}
Expand Down Expand Up @@ -1004,7 +1004,7 @@
"ZR Front": "True",
"ZR Open Grotto": "True",
"ZR Fairy Grotto": "can_blast_or_smash",
"Lost Woods": "can_dive or can_use(Iron_Boots) or (is_child and (can_isg or Nuts)) or can_mega",
"Lost Woods": "Silver_Scale or can_use(Iron_Boots) or (is_child and (can_isg or Nuts)) or can_mega",
"ZR Storms Grotto": "can_play(Song_of_Storms) and can_stun_deku",
"Zoras Domain": "can_play(Zeldas_Lullaby) or can_mega or can_use(Hover_Boots) or is_child"
}
Expand Down Expand Up @@ -1233,7 +1233,7 @@
"region_name": "HF Tektite Grotto",
"locations": {
"HF Tektite Grotto Freestanding PoH": "
(Progressive_Scale, 2) or can_use(Iron_Boots)"
Golden_Scale or can_use(Iron_Boots)"
}
},
{
Expand Down
Loading