This commit is contained in:
CookieCat
2023-11-04 17:55:48 -04:00
parent 60df274157
commit bd8698e1fd
102 changed files with 1190 additions and 1463 deletions
+1 -2
View File
@@ -520,8 +520,7 @@ class ALTTPSNIClient(SNIClient):
gamemode = await snes_read(ctx, WRAM_START + 0x10, 1)
if "DeathLink" in ctx.tags and gamemode and ctx.last_death_link + 1 < time.time():
currently_dead = gamemode[0] in DEATH_MODES
await ctx.handle_deathlink_state(currently_dead,
ctx.player_names[ctx.slot] + " ran out of hearts." if ctx.slot else "")
await ctx.handle_deathlink_state(currently_dead)
gameend = await snes_read(ctx, SAVEDATA_START + 0x443, 1)
game_timer = await snes_read(ctx, SAVEDATA_START + 0x42E, 4)
+1 -2
View File
@@ -264,8 +264,7 @@ def fill_dungeons_restrictive(multiworld: MultiWorld):
if loc in all_state_base.events:
all_state_base.events.remove(loc)
fill_restrictive(multiworld, all_state_base, locations, in_dungeon_items, True, True,
name="LttP Dungeon Items")
fill_restrictive(multiworld, all_state_base, locations, in_dungeon_items, True, True)
dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A],
+1
View File
@@ -293,6 +293,7 @@ def generate_itempool(world):
loc.access_rule = lambda state: has_triforce_pieces(state, player)
region.locations.append(loc)
multiworld.clear_location_cache()
multiworld.push_item(loc, ItemFactory('Triforce', player), False)
loc.event = True
+3 -3
View File
@@ -786,8 +786,8 @@ def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool):
# patch items
for location in world.get_locations(player):
if location.address is None or location.shop_slot is not None:
for location in world.get_locations():
if location.player != player or location.address is None or location.shop_slot is not None:
continue
itemid = location.item.code if location.item is not None else 0x5A
@@ -2247,7 +2247,7 @@ def write_strings(rom, world, player):
tt['sign_north_of_links_house'] = '> Randomizer The telepathic tiles can have hints!'
hint_locations = HintLocations.copy()
local_random.shuffle(hint_locations)
all_entrances = list(world.get_entrances(player))
all_entrances = [entrance for entrance in world.get_entrances() if entrance.player == player]
local_random.shuffle(all_entrances)
# First we take care of the one inconvenient dungeon in the appropriately simple shuffles.
+12 -16
View File
@@ -197,13 +197,8 @@ def global_rules(world, player):
# determines which S&Q locations are available - hide from paths since it isn't an in-game location
for exit in world.get_region('Menu', player).exits:
exit.hide_path = True
try:
old_man_sq = world.get_entrance('Old Man S&Q', player)
except KeyError:
pass # it doesn't exist, should be dungeon-only unittests
else:
old_man = world.get_location("Old Man", player)
set_rule(old_man_sq, lambda state: old_man.can_reach(state))
set_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.can_reach('Old Man', 'Location', player))
set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player))
@@ -1531,16 +1526,16 @@ def set_bunny_rules(world: MultiWorld, player: int, inverted: bool):
# Helper functions to determine if the moon pearl is required
if inverted:
def is_bunny(region):
return region and region.is_light_world
return region.is_light_world
def is_link(region):
return region and region.is_dark_world
return region.is_dark_world
else:
def is_bunny(region):
return region and region.is_dark_world
return region.is_dark_world
def is_link(region):
return region and region.is_light_world
return region.is_light_world
def get_rule_to_add(region, location = None, connecting_entrance = None):
# In OWG, a location can potentially be superbunny-mirror accessible or
@@ -1608,20 +1603,21 @@ def set_bunny_rules(world: MultiWorld, player: int, inverted: bool):
return options_to_access_rule(possible_options)
# Add requirements for bunny-impassible caves if link is a bunny in them
for region in (world.get_region(name, player) for name in bunny_impassable_caves):
for region in [world.get_region(name, player) for name in bunny_impassable_caves]:
if not is_bunny(region):
continue
rule = get_rule_to_add(region)
for region_exit in region.exits:
add_rule(region_exit, rule)
for exit in region.exits:
add_rule(exit, rule)
paradox_shop = world.get_region('Light World Death Mountain Shop', player)
if is_bunny(paradox_shop):
add_rule(paradox_shop.entrances[0], get_rule_to_add(paradox_shop))
# Add requirements for all locations that are actually in the dark world, except those available to the bunny, including dungeon revival
for entrance in world.get_entrances(player):
if is_bunny(entrance.connected_region):
for entrance in world.get_entrances():
if entrance.player == player and is_bunny(entrance.connected_region):
if world.logic[player] in ['minorglitches', 'owglitches', 'hybridglitches', 'nologic'] :
if entrance.connected_region.type == LTTPRegionType.Dungeon:
if entrance.parent_region.type != LTTPRegionType.Dungeon and entrance.connected_region.name in OverworldGlitchRules.get_invalid_bunny_revival_dungeons():
+3
View File
@@ -348,6 +348,7 @@ def create_shops(world, player: int):
loc.item = ItemFactory(GetBeemizerItem(world, player, 'Nothing'), player)
loc.shop_slot_disabled = True
shop.region.locations.append(loc)
world.clear_location_cache()
class ShopData(NamedTuple):
@@ -618,4 +619,6 @@ def create_dynamic_shop_locations(world, player):
if shop.type == ShopType.TakeAny:
loc.shop_slot_disabled = True
shop.region.locations.append(loc)
world.clear_location_cache()
loc.shop_slot = i
+1 -1
View File
@@ -31,7 +31,7 @@ def fake_pearl_state(state, player):
if state.has('Moon Pearl', player):
return state
fake_state = state.copy()
fake_state.prog_items[player]['Moon Pearl'] += 1
fake_state.prog_items['Moon Pearl', player] += 1
return fake_state
+23 -23
View File
@@ -470,8 +470,7 @@ class ALTTPWorld(World):
prizepool = unplaced_prizes.copy()
prize_locs = empty_crystal_locations.copy()
world.random.shuffle(prize_locs)
fill_restrictive(world, all_state, prize_locs, prizepool, True, lock=True,
name="LttP Dungeon Prizes")
fill_restrictive(world, all_state, prize_locs, prizepool, True, lock=True)
except FillError as e:
lttp_logger.exception("Failed to place dungeon prizes (%s). Will retry %s more times", e,
attempts - attempt)
@@ -586,26 +585,27 @@ class ALTTPWorld(World):
for player in checks_in_area:
checks_in_area[player]["Total"] = 0
for location in multiworld.get_locations(player):
if location.game == cls.game and type(location.address) is int:
main_entrance = location.parent_region.get_connecting_entrance(is_main_entrance)
if location.parent_region.dungeon:
dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
'Inverted Ganons Tower': 'Ganons Tower'} \
.get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
checks_in_area[location.player][dungeonname].append(location.address)
elif location.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif location.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
else:
assert False, "Unknown Location area."
# TODO: remove Total as it's duplicated data and breaks consistent typing
checks_in_area[location.player]["Total"] += 1
for location in multiworld.get_locations():
if location.game == cls.game and type(location.address) is int:
main_entrance = location.parent_region.get_connecting_entrance(is_main_entrance)
if location.parent_region.dungeon:
dungeonname = {'Inverted Agahnims Tower': 'Agahnims Tower',
'Inverted Ganons Tower': 'Ganons Tower'} \
.get(location.parent_region.dungeon.name, location.parent_region.dungeon.name)
checks_in_area[location.player][dungeonname].append(location.address)
elif location.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif location.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.LightWorld:
checks_in_area[location.player]["Light World"].append(location.address)
elif main_entrance.parent_region.type == LTTPRegionType.DarkWorld:
checks_in_area[location.player]["Dark World"].append(location.address)
else:
assert False, "Unknown Location area."
# TODO: remove Total as it's duplicated data and breaks consistent typing
checks_in_area[location.player]["Total"] += 1
multidata["checks_in_area"].update(checks_in_area)
@@ -830,4 +830,4 @@ class ALttPLogic(LogicMixin):
return True
if self.multiworld.smallkey_shuffle[player] == smallkey_shuffle.option_universal:
return can_buy_unlimited(self, 'Small Key (Universal)', player)
return self.prog_items[player][item] >= count
return self.prog_items[item, player] >= count
+1 -1
View File
@@ -1,5 +1,5 @@
from BaseClasses import CollectionState, ItemClassification
from worlds.alttp.Dungeons import get_dungeon_item_pool
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import mandatory_connections, connect_simple
from worlds.alttp.ItemPool import difficulties
from worlds.alttp.Items import ItemFactory