Skip to content

Commit

Permalink
Fix Big Octo ice trap preview
Browse files Browse the repository at this point in the history
  • Loading branch information
fenhl committed May 20, 2024
1 parent afc324f commit c6cfd0d
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 66 deletions.
11 changes: 6 additions & 5 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ def distribute_items_restrictive(worlds: list[World], fill_locations: Optional[l
ice_traps = [item for item in itempool if item.name == 'Ice Trap']
# Extend with ice traps manually placed in plandomizer
ice_traps.extend(
location.item for location in cloakable_locations
if (location.has_preview()
and location.item is not None
and location.item.name == 'Ice Trap'
and location.item.looks_like_item is None))
location.item
for location in cloakable_locations
if location.item is not None
and location.item.name == 'Ice Trap'
and location.item.looks_like_item is None
)
junk_items = remove_junk_items.copy()
junk_items.remove('Ice Trap')
major_items = [name for name, item in ItemInfo.items.items() if item.type == 'Item' and item.advancement and item.index is not None]
Expand Down
2 changes: 1 addition & 1 deletion Location.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def is_disabled(self) -> bool:
def has_preview(self) -> bool:
if self.world is None:
return False
return location_is_viewable(self.name, self.world.settings.correct_chest_appearances, self.world.settings.fast_chests)
return location_is_viewable(self.name, self.world.settings.correct_chest_appearances, self.world.settings.fast_chests, world=self.world)

def has_item(self) -> bool:
return self.item is not None
Expand Down
14 changes: 10 additions & 4 deletions LocationList.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations
import sys
from collections import OrderedDict
from typing import Optional
from typing import Optional, TYPE_CHECKING

if sys.version_info >= (3, 10):
from typing import TypeAlias
Expand All @@ -13,6 +13,9 @@
LocationAddresses: TypeAlias = "Optional[tuple[LocationAddress, LocationAddress]]"
LocationFilterTags: TypeAlias = "Optional[tuple[str, ...] | str]"

if TYPE_CHECKING:
from World import World


def shop_address(shop_id: int, shelf_id: int) -> int:
return 0xC71ED0 + (0x40 * shop_id) + (0x08 * shelf_id)
Expand Down Expand Up @@ -2516,6 +2519,9 @@ def shop_address(shop_id: int, shelf_id: int) -> int:
}


def location_is_viewable(loc_name: str, correct_chest_appearances: str, fast_chests: bool) -> bool:
return (((correct_chest_appearances in ('textures', 'both', 'classic') or not fast_chests) and loc_name in location_groups['Chest'])
or loc_name in location_groups['CanSee'])
def location_is_viewable(loc_name: str, correct_chest_appearances: str, fast_chests: bool, *, world: Optional[World] = None) -> bool:
return (
((correct_chest_appearances in ('textures', 'both', 'classic') or not fast_chests) and loc_name in location_groups['Chest'])
or loc_name in location_groups['CanSee']
or (world is not None and world.bigocto_location() is not None and world.bigocto_location().name == loc_name)
)
57 changes: 1 addition & 56 deletions Patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -1766,63 +1766,8 @@ def calculate_traded_flags(world):
new_message = "\x08What should I do!?\x01My \x05\x41Cuccos\x05\x40 have all flown away!\x04You, little boy, please!\x01Please gather at least \x05\x41%d Cuccos\x05\x40\x01for me.\x02" % world.settings.chicken_count
update_message_by_id(messages, 0x5036, new_message)

# Find an item location behind the Jabu boss door by searching regions breadth-first without going back into Jabu proper
if world.settings.logic_rules == 'glitched':
location = world.get_location('Barinade')
else:
jabu_reward_regions = {world.get_entrance('Jabu Jabus Belly Before Boss -> Barinade Boss Room').connected_region}
already_checked = set()
location = None
while jabu_reward_regions:
locations = [
loc
for region in jabu_reward_regions
if region is not None and region.locations is not None
for loc in region.locations
if not loc.locked
and loc.has_item()
and not loc.item.event
and (loc.type != "Shop" or loc.name in world.shop_prices) # ignore regular shop items (but keep special deals)
]
if locations:
# Location types later in the list will be preferred over earlier ones or ones not in the list.
# This ensures that if the region behind the boss door is a boss arena, the medallion or stone will be used.
priority_types = (
"Freestanding",
"ActorOverride",
"RupeeTower",
"Pot",
"Crate",
"FlyingPot",
"SmallCrate",
"Beehive",
"SilverRupee",
"GS Token",
"GrottoScrub",
"Scrub",
"Shop",
"MaskShop",
"NPC",
"Collectable",
"Chest",
"Cutscene",
"Song",
"BossHeart",
"Boss",
)
best_type = max((location.type for location in locations), key=lambda type: priority_types.index(type) if type in priority_types else -1)
location = random.choice(list(filter(lambda loc: loc.type == best_type, locations)))
break
already_checked |= jabu_reward_regions
jabu_reward_regions = {
exit.connected_region
for region in jabu_reward_regions
if region is not None
for exit in region.exits
if exit.connected_region is not None and exit.connected_region.dungeon != 'Jabu Jabus Belly' and exit.connected_region.name not in already_checked
}

# Update "Princess Ruto got the Spiritual Stone!" text before the midboss in Jabu
location = world.bigocto_location()
if location is None or location.item is None:
jabu_item = None
new_message = f"\x08Princess Ruto got \x01\x05\x43nothing\x05\x40!\x01Well, that's disappointing...\x02"
Expand Down
62 changes: 62 additions & 0 deletions World.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__(self, world_id: int, settings: Settings, resolve_randomized_setting
self.barren_dungeon: int = 0
self.woth_dungeon: int = 0
self.randomized_list: list[str] = []
self.cached_bigocto_location: Optional[Location] = None

self.parser: Rule_AST_Transformer = Rule_AST_Transformer(self)
self.event_items: set[str] = set()
Expand Down Expand Up @@ -1108,6 +1109,67 @@ def silver_rupee_puzzles(self) -> list[str]:
+ (['Ganons Castle Shadow Trial', 'Ganons Castle Water Trial'] if self.dungeon_mq['Ganons Castle'] else ['Ganons Castle Spirit Trial', 'Ganons Castle Light Trial', 'Ganons Castle Forest Trial'])
)

def bigocto_location(self) -> Optional[Location]:
if self.cached_bigocto_location is not None:
return self.cached_bigocto_location
# Find an item location behind the Jabu boss door by searching regions breadth-first without going back into Jabu proper
if self.settings.logic_rules == 'glitched':
location = self.get_location('Barinade')
else:
jabu_reward_regions = {self.get_entrance('Jabu Jabus Belly Before Boss -> Barinade Boss Room').connected_region}
already_checked = set()
location = None
while jabu_reward_regions:
locations = [
loc
for region in jabu_reward_regions
if region is not None and region.locations is not None
for loc in region.locations
if not loc.locked
and loc.has_item()
and not loc.item.event
and (loc.type != "Shop" or loc.name in self.shop_prices) # ignore regular shop items (but keep special deals)
]
if locations:
# Location types later in the list will be preferred over earlier ones or ones not in the list.
# This ensures that if the region behind the boss door is a boss arena, the medallion or stone will be used.
priority_types = (
"Freestanding",
"ActorOverride",
"RupeeTower",
"Pot",
"Crate",
"FlyingPot",
"SmallCrate",
"Beehive",
"SilverRupee",
"GS Token",
"GrottoScrub",
"Scrub",
"Shop",
"MaskShop",
"NPC",
"Collectable",
"Chest",
"Cutscene",
"Song",
"BossHeart",
"Boss",
)
best_type = max((location.type for location in locations), key=lambda type: priority_types.index(type) if type in priority_types else -1)
location = random.choice(list(filter(lambda loc: loc.type == best_type, locations)))
break
already_checked |= jabu_reward_regions
jabu_reward_regions = {
exit.connected_region
for region in jabu_reward_regions
if region is not None
for exit in region.exits
if exit.connected_region is not None and exit.connected_region.dungeon != 'Jabu Jabus Belly' and exit.connected_region.name not in already_checked
}
self.cached_bigocto_location = location
return location

def find_items(self, item: str) -> list[Location]:
return [location for location in self.get_locations() if location.item is not None and location.item.name == item]

Expand Down

0 comments on commit c6cfd0d

Please sign in to comment.