Files
Grinch-AP/worlds/oot/Location.py
espeon65536 724999fc43 Ocarina of Time: long-awaited bugfixes (#2344)
- Added location name groups, so you can make your entire Water Temple priority to annoy everyone else
- Significant improvement to ER generation success rate (~80% to >99%)
- Changed `adult_trade_start` option to a choice option instead of a list (this shouldn't actually break any YAMLs though, due to the lesser-known property of lists parsing as a uniformly-weighted choice)
- Major improvements to the option tooltips where needed. (Possibly too much text now)
- Changed default hint distribution to `async` to help people's generation times. The tooltip explains that it removes WOTH hints so people hopefully don't get tripped up.
- Makes stick and nut capacity upgrades useful items
- Added shop prices and required trials to spoiler log
- Added Cojiro to adult trade item group, because it had been forgotten previously
- Fixed size-modified chests not being moved properly due to trap appearance changing the size
- Fixed Thieves Hideout keyring not being allowed in start inventory
- Fixed hint generation not accurately flagging barren locations on certain dungeon item shuffle settings
- Fixed bug where you could plando arbitrarily-named items into the world, breaking everything
2023-10-22 18:38:47 +02:00

142 lines
4.4 KiB
Python

from enum import Enum
from .LocationList import location_table
from BaseClasses import Location
non_indexed_location_types = {'Boss', 'Event', 'Drop', 'HintStone', 'Hint'}
location_id_offset = 67000
locnames_pre_70 = {
"Gift from Sages",
"ZR Frogs Zeldas Lullaby",
"ZR Frogs Eponas Song",
"ZR Frogs Sarias Song",
"ZR Frogs Suns Song",
"ZR Frogs Song of Time",
}
loctypes_70 = {'Beehive', 'Pot', 'FlyingPot', 'Crate', 'SmallCrate', 'RupeeTower', 'Freestanding', 'ActorOverride'}
new_name_order = sorted(location_table.keys(),
key=lambda name: 2 if location_table[name][0] in loctypes_70
else 1 if name in locnames_pre_70
else 0)
location_name_to_id = {name: (location_id_offset + index) for (index, name) in enumerate(new_name_order)
if location_table[name][0] not in non_indexed_location_types}
class DisableType(Enum):
ENABLED = 0
PENDING = 1
DISABLED = 2
class OOTLocation(Location):
game: str = 'Ocarina of Time'
def __init__(self, player, name='', code=None, address1=None, address2=None,
default=None, type='Chest', scene=None, parent=None, filter_tags=None,
internal=False, vanilla_item=None
):
super(OOTLocation, self).__init__(player, name, code, parent)
self.address1 = address1
self.address2 = address2
self.default = default
self.type = type
self.scene = scene
self.internal = internal
self.vanilla_item = vanilla_item
if filter_tags is None:
self.filter_tags = None
else:
self.filter_tags = list(filter_tags)
self.never = False # no idea what this does
self.disabled = DisableType.ENABLED
if type == 'Event':
self.event = True
@property
def dungeon(self):
return self.parent_region.dungeon
def LocationFactory(locations, player: int):
ret = []
singleton = False
if isinstance(locations, str):
locations = [locations]
singleton = True
for location in locations:
if location in location_table:
match_location = location
else:
match_location = next(filter(lambda k: k.lower() == location.lower(), location_table), None)
if match_location:
type, scene, default, addresses, vanilla_item, filter_tags = location_table[match_location]
if addresses is None:
addresses = (None, None)
address1, address2 = addresses
ret.append(OOTLocation(player, match_location,
location_name_to_id.get(match_location, None),
address1, address2, default, type, scene,
filter_tags=filter_tags, vanilla_item=vanilla_item))
else:
raise KeyError('Unknown Location: %s', location)
if singleton:
return ret[0]
return ret
def build_location_name_groups() -> dict:
def fix_sing(t) -> tuple:
if isinstance(t, str):
return (t,)
return t
def rename(d, k1, k2) -> None:
d[k2] = d[k1]
del d[k1]
# whoever wrote the location table didn't realize they need to add a comma to mark a singleton as a tuple
# so we have to check types unfortunately
tags = set()
for v in location_table.values():
if v[5] is not None:
tags.update(fix_sing(v[5]))
sorted_tags = sorted(list(tags))
ret = {
tag: {k for k, v in location_table.items()
if v[5] is not None
and tag in fix_sing(v[5])
and v[0] not in non_indexed_location_types}
for tag in sorted_tags
}
# Delete tags which are a combination of other tags
del ret['Death Mountain']
del ret['Forest']
del ret['Gerudo']
del ret['Kakariko']
del ret['Market']
# Delete Vanilla and MQ tags because they are just way too broad
del ret['Vanilla']
del ret['Master Quest']
rename(ret, 'Beehive', 'Beehives')
rename(ret, 'Cow', 'Cows')
rename(ret, 'Crate', 'Crates')
rename(ret, 'Deku Scrub', 'Deku Scrubs')
rename(ret, 'FlyingPot', 'Flying Pots')
rename(ret, 'Freestanding', 'Freestanding Items')
rename(ret, 'Pot', 'Pots')
rename(ret, 'RupeeTower', 'Rupee Groups')
rename(ret, 'SmallCrate', 'Small Crates')
rename(ret, 'the Market', 'Market')
rename(ret, 'the Graveyard', 'Graveyard')
rename(ret, 'the Lost Woods', 'Lost Woods')
return ret