From 4f1e6962438e1c298403b02e800684d3c317257a Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Fri, 26 Apr 2024 14:29:01 -0500 Subject: [PATCH 1/5] The Messenger: fix import that shouldn't be relative (#3219) --- worlds/messenger/portals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/messenger/portals.py b/worlds/messenger/portals.py index 51f51d7e379e..f5603736c3a7 100644 --- a/worlds/messenger/portals.py +++ b/worlds/messenger/portals.py @@ -2,8 +2,8 @@ from typing import List, TYPE_CHECKING from BaseClasses import CollectionState, PlandoOptions +from worlds.generic import PlandoConnection from .options import ShufflePortals -from ..generic import PlandoConnection if TYPE_CHECKING: from . import MessengerWorld From e76ba928a8b8cf43794349fd649e9d610a6c01e1 Mon Sep 17 00:00:00 2001 From: Zach Parks Date: Fri, 26 Apr 2024 22:18:12 -0400 Subject: [PATCH 2/5] WebHost: Prevent committing data packages with invalid checksums to database and prevent 500 error from invalid `zip` files. (#3206) --- WebHostLib/upload.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/WebHostLib/upload.py b/WebHostLib/upload.py index 884c1913f8f9..45b26b175eb3 100644 --- a/WebHostLib/upload.py +++ b/WebHostLib/upload.py @@ -63,12 +63,13 @@ def process_multidata(compressed_multidata, files={}): game_data = games_package_schema.validate(game_data) game_data = {key: value for key, value in sorted(game_data.items())} game_data["checksum"] = data_package_checksum(game_data) - game_data_package = GameDataPackage(checksum=game_data["checksum"], - data=pickle.dumps(game_data)) if original_checksum != game_data["checksum"]: raise Exception(f"Original checksum {original_checksum} != " f"calculated checksum {game_data['checksum']} " f"for game {game}.") + + game_data_package = GameDataPackage(checksum=game_data["checksum"], + data=pickle.dumps(game_data)) decompressed_multidata["datapackage"][game] = { "version": game_data.get("version", 0), "checksum": game_data["checksum"], @@ -192,6 +193,8 @@ def uploads(): res = upload_zip_to_db(zfile) except VersionException: flash(f"Could not load multidata. Wrong Version detected.") + except Exception as e: + flash(f"Could not load multidata. File may be corrupted or incompatible. ({e})") else: if res is str: return res From 9e20fa48e133fee6d9c97efd1ed1028c662e695e Mon Sep 17 00:00:00 2001 From: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com> Date: Sat, 27 Apr 2024 17:41:30 -0600 Subject: [PATCH 3/5] CV64: fix import that shouldn't be relative (#3223) --- worlds/cv64/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/cv64/__init__.py b/worlds/cv64/__init__.py index afa59b31da1b..84bf03ff27aa 100644 --- a/worlds/cv64/__init__.py +++ b/worlds/cv64/__init__.py @@ -14,7 +14,7 @@ from .regions import get_region_info from .rules import CV64Rules from .data import iname, rname, ename -from ..AutoWorld import WebWorld, World +from worlds.AutoWorld import WebWorld, World from .aesthetics import randomize_lighting, shuffle_sub_weapons, rom_empty_breakables_flags, rom_sub_weapon_flags, \ randomize_music, get_start_inventory_data, get_location_data, randomize_shop_prices, get_loading_zone_bytes, \ get_countdown_numbers From 9afe45166cda3dfb8b9ab8aa754ead6bddf3da3a Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Sat, 27 Apr 2024 19:48:59 -0400 Subject: [PATCH 4/5] ALTTP: 0.4.6 fixes (#3215) * Fix randomizer room logic * Fix Triforce Hunt HUD always present * Fix Circle of Pots enemy byte * treasure_hunt_total for Murahdala text --- worlds/alttp/ItemPool.py | 33 +++++++++++-------- worlds/alttp/Rom.py | 20 +++++------ worlds/alttp/Rules.py | 4 +-- worlds/alttp/StateHelpers.py | 2 +- worlds/alttp/__init__.py | 3 +- worlds/alttp/test/dungeons/TestDungeon.py | 2 +- worlds/alttp/test/dungeons/TestGanonsTower.py | 12 ++++--- worlds/alttp/test/inverted/TestInverted.py | 2 +- .../TestInvertedMinor.py | 2 +- .../test/inverted_owg/TestInvertedOWG.py | 2 +- worlds/alttp/test/minor_glitches/TestMinor.py | 2 +- worlds/alttp/test/owg/TestVanillaOWG.py | 2 +- worlds/alttp/test/vanilla/TestVanilla.py | 2 +- 13 files changed, 49 insertions(+), 39 deletions(-) diff --git a/worlds/alttp/ItemPool.py b/worlds/alttp/ItemPool.py index 69ecadc79d07..125475561bb2 100644 --- a/worlds/alttp/ItemPool.py +++ b/worlds/alttp/ItemPool.py @@ -276,13 +276,14 @@ def generate_itempool(world): # set up item pool additional_triforce_pieces = 0 + treasure_hunt_total = 0 if multiworld.custom: - pool, placed_items, precollected_items, clock_mode, treasure_hunt_count = ( + pool, placed_items, precollected_items, clock_mode, treasure_hunt_required = ( make_custom_item_pool(multiworld, player)) multiworld.rupoor_cost = min(multiworld.customitemarray[67], 9999) else: - pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, additional_triforce_pieces = ( - get_pool_core(multiworld, player)) + (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required, treasure_hunt_total, + additional_triforce_pieces) = get_pool_core(multiworld, player) for item in precollected_items: multiworld.push_precollected(item_factory(item, world)) @@ -337,7 +338,8 @@ def generate_itempool(world): if clock_mode: world.clock_mode = clock_mode - multiworld.worlds[player].treasure_hunt_count = treasure_hunt_count % 999 + multiworld.worlds[player].treasure_hunt_required = treasure_hunt_required % 999 + multiworld.worlds[player].treasure_hunt_total = treasure_hunt_total dungeon_items = [item for item in get_dungeon_item_pool_player(world) if item.name not in multiworld.worlds[player].dungeon_local_item_names] @@ -590,7 +592,8 @@ def get_pool_core(world, player: int): placed_items = {} precollected_items = [] clock_mode: str = "" - treasure_hunt_count: int = 1 + treasure_hunt_required: int = 0 + treasure_hunt_total: int = 0 diff = difficulties[difficulty] pool.extend(diff.alwaysitems) @@ -679,20 +682,21 @@ def place_item(loc, item): if 'triforce_hunt' in goal: if world.triforce_pieces_mode[player].value == TriforcePiecesMode.option_extra: - triforce_pieces = world.triforce_pieces_available[player].value + world.triforce_pieces_extra[player].value + treasure_hunt_total = (world.triforce_pieces_available[player].value + + world.triforce_pieces_extra[player].value) elif world.triforce_pieces_mode[player].value == TriforcePiecesMode.option_percentage: percentage = float(world.triforce_pieces_percentage[player].value) / 100 - triforce_pieces = int(round(world.triforce_pieces_required[player].value * percentage, 0)) + treasure_hunt_total = int(round(world.triforce_pieces_required[player].value * percentage, 0)) else: # available - triforce_pieces = world.triforce_pieces_available[player].value + treasure_hunt_total = world.triforce_pieces_available[player].value - triforce_pieces = min(90, max(triforce_pieces, world.triforce_pieces_required[player].value)) + triforce_pieces = min(90, max(treasure_hunt_total, world.triforce_pieces_required[player].value)) pieces_in_core = min(extraitems, triforce_pieces) additional_pieces_to_place = triforce_pieces - pieces_in_core pool.extend(["Triforce Piece"] * pieces_in_core) extraitems -= pieces_in_core - treasure_hunt_count = world.triforce_pieces_required[player].value + treasure_hunt_required = world.triforce_pieces_required[player].value for extra in diff.extras: if extraitems >= len(extra): @@ -733,7 +737,7 @@ def place_item(loc, item): place_item(key_location, "Small Key (Universal)") pool = pool[:-3] - return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, + return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required, treasure_hunt_total, additional_pieces_to_place) @@ -749,7 +753,8 @@ def make_custom_item_pool(world, player): placed_items = {} precollected_items = [] clock_mode: str = "" - treasure_hunt_count: int = 1 + treasure_hunt_required: int = 0 + treasure_hunt_total: int = 0 def place_item(loc, item): assert loc not in placed_items, "cannot place item twice" @@ -844,7 +849,7 @@ def place_item(loc, item): if "triforce" in world.goal[player]: pool.extend(["Triforce Piece"] * world.triforce_pieces_available[player]) itemtotal += world.triforce_pieces_available[player] - treasure_hunt_count = world.triforce_pieces_required[player] + treasure_hunt_required = world.triforce_pieces_required[player] if timer in ['display', 'timed', 'timed_countdown']: clock_mode = 'countdown' if timer == 'timed_countdown' else 'stopwatch' @@ -889,4 +894,4 @@ def place_item(loc, item): pool.extend(['Nothing'] * (total_items_to_place - itemtotal)) logging.warning(f"Pool was filled up with {total_items_to_place - itemtotal} Nothing's for player {player}") - return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count) + return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required) diff --git a/worlds/alttp/Rom.py b/worlds/alttp/Rom.py index 7c3c87683a37..05460e0f9b8c 100644 --- a/worlds/alttp/Rom.py +++ b/worlds/alttp/Rom.py @@ -433,7 +433,7 @@ def patch_enemizer(world, rom: LocalRom, enemizercli, output_directory): if multiworld.key_drop_shuffle[player]: key_drop_enemies = { 0x4DA20, 0x4DA5C, 0x4DB7F, 0x4DD73, 0x4DDC3, 0x4DE07, 0x4E201, - 0x4E20A, 0x4E326, 0x4E4F7, 0x4E686, 0x4E70C, 0x4E7C8, 0x4E7FA + 0x4E20A, 0x4E326, 0x4E4F7, 0x4E687, 0x4E70C, 0x4E7C8, 0x4E7FA } for enemy in key_drop_enemies: if rom.read_byte(enemy) == 0x12: @@ -1269,7 +1269,7 @@ def chunk(l, n): rom.write_int32(0x18020C, 0) # starting time (in frames, sint32) # set up goals for treasure hunt - rom.write_int16(0x180163, local_world.treasure_hunt_count) + rom.write_int16(0x180163, local_world.treasure_hunt_required) rom.write_bytes(0x180165, [0x0E, 0x28]) # Triforce Piece Sprite rom.write_byte(0x180194, 1) # Must turn in triforced pieces (instant win not enabled) @@ -2482,16 +2482,16 @@ def hint_text(dest, ped_hint=False): tt['sign_ganon'] = 'Go find the Triforce pieces with your friends... Ganon is invincible!' else: tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!' - if w.treasure_hunt_count > 1: + if w.treasure_hunt_required > 1: tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\n" \ "invisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\n" \ "hidden in a hollow tree. If you bring\n%d Triforce pieces out of %d, I can reassemble it." % \ - (w.treasure_hunt_count, world.triforce_pieces_available[player]) + (w.treasure_hunt_required, w.treasure_hunt_total) else: tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\n" \ "invisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\n" \ "hidden in a hollow tree. If you bring\n%d Triforce piece out of %d, I can reassemble it." % \ - (w.treasure_hunt_count, world.triforce_pieces_available[player]) + (w.treasure_hunt_required, w.treasure_hunt_total) elif world.goal[player] in ['pedestal']: tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' @@ -2500,20 +2500,20 @@ def hint_text(dest, ped_hint=False): tt['ganon_fall_in'] = Ganon1_texts[local_random.randint(0, len(Ganon1_texts) - 1)] tt['ganon_fall_in_alt'] = 'You cannot defeat me until you finish your goal!' tt['ganon_phase_3_alt'] = 'Got wax in\nyour ears?\nI can not die!' - if w.treasure_hunt_count > 1: + if w.treasure_hunt_required > 1: if world.goal[player] == 'ganon_triforce_hunt' and world.players > 1: tt['sign_ganon'] = 'You need to find %d Triforce pieces out of %d with your friends to defeat Ganon.' % \ - (w.treasure_hunt_count, world.triforce_pieces_available[player]) + (w.treasure_hunt_required, w.treasure_hunt_total) elif world.goal[player] in ['ganon_triforce_hunt', 'local_ganon_triforce_hunt']: tt['sign_ganon'] = 'You need to find %d Triforce pieces out of %d to defeat Ganon.' % \ - (w.treasure_hunt_count, world.triforce_pieces_available[player]) + (w.treasure_hunt_required, w.treasure_hunt_total) else: if world.goal[player] == 'ganon_triforce_hunt' and world.players > 1: tt['sign_ganon'] = 'You need to find %d Triforce piece out of %d with your friends to defeat Ganon.' % \ - (w.treasure_hunt_count, world.triforce_pieces_available[player]) + (w.treasure_hunt_required, w.treasure_hunt_total) elif world.goal[player] in ['ganon_triforce_hunt', 'local_ganon_triforce_hunt']: tt['sign_ganon'] = 'You need to find %d Triforce piece out of %d to defeat Ganon.' % \ - (w.treasure_hunt_count, world.triforce_pieces_available[player]) + (w.treasure_hunt_required, w.treasure_hunt_total) tt['kakariko_tavern_fisherman'] = TavernMan_texts[local_random.randint(0, len(TavernMan_texts) - 1)] diff --git a/worlds/alttp/Rules.py b/worlds/alttp/Rules.py index 5e4635fa2754..e13f0914f93b 100644 --- a/worlds/alttp/Rules.py +++ b/worlds/alttp/Rules.py @@ -554,8 +554,8 @@ def global_rules(multiworld: MultiWorld, player: int): set_rule(multiworld.get_location('Ganons Tower - Firesnake Room', player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 7) or ((item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) or item_name_in_location_names(state, 'Small Key (Ganons Tower)', player, [('Ganons Tower - Firesnake Room', player)])) and state._lttp_has_key('Small Key (Ganons Tower)', player, 5))) for location in randomizer_room_chests: - set_rule(multiworld.get_location(location, player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 8) or ( - item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) and state._lttp_has_key('Small Key (Ganons Tower)', player, 6))) + set_rule(multiworld.get_location(location, player), lambda state: can_use_bombs(state, player) and (state._lttp_has_key('Small Key (Ganons Tower)', player, 8) or ( + item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) and state._lttp_has_key('Small Key (Ganons Tower)', player, 6)))) # Once again it is possible to need more than 7 keys... set_rule(multiworld.get_entrance('Ganons Tower (Tile Room) Key Door', player), lambda state: state.has('Fire Rod', player) and (state._lttp_has_key('Small Key (Ganons Tower)', player, 7) or ( diff --git a/worlds/alttp/StateHelpers.py b/worlds/alttp/StateHelpers.py index fe3a43ee0f55..964a77fefbaf 100644 --- a/worlds/alttp/StateHelpers.py +++ b/worlds/alttp/StateHelpers.py @@ -30,7 +30,7 @@ def can_shoot_arrows(state: CollectionState, player: int) -> bool: def has_triforce_pieces(state: CollectionState, player: int) -> bool: - count = state.multiworld.worlds[player].treasure_hunt_count + count = state.multiworld.worlds[player].treasure_hunt_required return state.count('Triforce Piece', player) + state.count('Power Star', player) >= count diff --git a/worlds/alttp/__init__.py b/worlds/alttp/__init__.py index f4a374ce0201..ae3dfe9e3b1a 100644 --- a/worlds/alttp/__init__.py +++ b/worlds/alttp/__init__.py @@ -261,7 +261,8 @@ def enemizer_path(self) -> str: fix_fake_world: bool = True clock_mode: str = "" - treasure_hunt_count: int = 1 + treasure_hunt_required: int = 0 + treasure_hunt_total: int = 0 def __init__(self, *args, **kwargs): self.dungeon_local_item_names = set() diff --git a/worlds/alttp/test/dungeons/TestDungeon.py b/worlds/alttp/test/dungeons/TestDungeon.py index a31ddd68b2e1..91fc462c4ecc 100644 --- a/worlds/alttp/test/dungeons/TestDungeon.py +++ b/worlds/alttp/test/dungeons/TestDungeon.py @@ -15,7 +15,7 @@ def setUp(self): self.remove_exits = [] # Block dungeon exits self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 create_regions(self.multiworld, 1) self.multiworld.worlds[1].create_dungeons() create_shops(self.multiworld, 1) diff --git a/worlds/alttp/test/dungeons/TestGanonsTower.py b/worlds/alttp/test/dungeons/TestGanonsTower.py index 1e70f580de4e..08274d0fe7d9 100644 --- a/worlds/alttp/test/dungeons/TestGanonsTower.py +++ b/worlds/alttp/test/dungeons/TestGanonsTower.py @@ -33,22 +33,26 @@ def testGanonsTower(self): ["Ganons Tower - Randomizer Room - Top Left", False, []], ["Ganons Tower - Randomizer Room - Top Left", False, [], ['Hammer']], ["Ganons Tower - Randomizer Room - Top Left", False, [], ['Hookshot']], - ["Ganons Tower - Randomizer Room - Top Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']], + ["Ganons Tower - Randomizer Room - Top Left", False, [], ['Bomb Upgrade (50)']], + ["Ganons Tower - Randomizer Room - Top Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']], ["Ganons Tower - Randomizer Room - Top Right", False, []], ["Ganons Tower - Randomizer Room - Top Right", False, [], ['Hammer']], ["Ganons Tower - Randomizer Room - Top Right", False, [], ['Hookshot']], - ["Ganons Tower - Randomizer Room - Top Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']], + ["Ganons Tower - Randomizer Room - Top Right", False, [], ['Bomb Upgrade (50)']], + ["Ganons Tower - Randomizer Room - Top Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']], ["Ganons Tower - Randomizer Room - Bottom Left", False, []], ["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Hammer']], ["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Hookshot']], - ["Ganons Tower - Randomizer Room - Bottom Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']], + ["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Bomb Upgrade (50)']], + ["Ganons Tower - Randomizer Room - Bottom Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']], ["Ganons Tower - Randomizer Room - Bottom Right", False, []], ["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Hammer']], ["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Hookshot']], - ["Ganons Tower - Randomizer Room - Bottom Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']], + ["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Bomb Upgrade (50)']], + ["Ganons Tower - Randomizer Room - Bottom Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']], ["Ganons Tower - Firesnake Room", False, []], ["Ganons Tower - Firesnake Room", False, [], ['Hammer']], diff --git a/worlds/alttp/test/inverted/TestInverted.py b/worlds/alttp/test/inverted/TestInverted.py index 59a3d7f5f4fa..0a2aa7a18653 100644 --- a/worlds/alttp/test/inverted/TestInverted.py +++ b/worlds/alttp/test/inverted/TestInverted.py @@ -16,7 +16,7 @@ def setUp(self): self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] self.multiworld.mode[1].value = 2 self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 create_inverted_regions(self.multiworld, 1) self.world.create_dungeons() create_shops(self.multiworld, 1) diff --git a/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py b/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py index 029de39bc232..a8fa5c808c3b 100644 --- a/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py +++ b/worlds/alttp/test/inverted_minor_glitches/TestInvertedMinor.py @@ -17,7 +17,7 @@ def setUp(self): self.multiworld.mode[1].value = 2 self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches") self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] create_inverted_regions(self.multiworld, 1) self.world.create_dungeons() diff --git a/worlds/alttp/test/inverted_owg/TestInvertedOWG.py b/worlds/alttp/test/inverted_owg/TestInvertedOWG.py index 86afae3e2a67..bbdf0f792444 100644 --- a/worlds/alttp/test/inverted_owg/TestInvertedOWG.py +++ b/worlds/alttp/test/inverted_owg/TestInvertedOWG.py @@ -17,7 +17,7 @@ def setUp(self): self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches") self.multiworld.mode[1].value = 2 self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] create_inverted_regions(self.multiworld, 1) self.world.create_dungeons() diff --git a/worlds/alttp/test/minor_glitches/TestMinor.py b/worlds/alttp/test/minor_glitches/TestMinor.py index 55fef61ebf99..8432028bf007 100644 --- a/worlds/alttp/test/minor_glitches/TestMinor.py +++ b/worlds/alttp/test/minor_glitches/TestMinor.py @@ -13,7 +13,7 @@ def setUp(self): self.world_setup() self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches") self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] self.world.er_seed = 0 self.world.create_regions() diff --git a/worlds/alttp/test/owg/TestVanillaOWG.py b/worlds/alttp/test/owg/TestVanillaOWG.py index 61b528f6fb91..67156eb97275 100644 --- a/worlds/alttp/test/owg/TestVanillaOWG.py +++ b/worlds/alttp/test/owg/TestVanillaOWG.py @@ -14,7 +14,7 @@ def setUp(self): self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches") self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 self.multiworld.worlds[1].er_seed = 0 self.multiworld.worlds[1].create_regions() self.multiworld.worlds[1].create_items() diff --git a/worlds/alttp/test/vanilla/TestVanilla.py b/worlds/alttp/test/vanilla/TestVanilla.py index 496b2ba0f9ac..7eebc349d43f 100644 --- a/worlds/alttp/test/vanilla/TestVanilla.py +++ b/worlds/alttp/test/vanilla/TestVanilla.py @@ -13,7 +13,7 @@ def setUp(self): self.multiworld.glitches_required[1] = GlitchesRequired.from_any("no_glitches") self.multiworld.worlds[1].difficulty_requirements = difficulties['normal'] self.multiworld.bombless_start[1].value = True - self.multiworld.shuffle_capacity_upgrades[1].value = True + self.multiworld.shuffle_capacity_upgrades[1].value = 2 self.multiworld.worlds[1].er_seed = 0 self.multiworld.worlds[1].create_regions() self.multiworld.worlds[1].create_items() From 9cdc90513be72c2ff8ad2924207de9454c5036c3 Mon Sep 17 00:00:00 2001 From: t3hf1gm3nt <59876300+t3hf1gm3nt@users.noreply.github.com> Date: Sat, 27 Apr 2024 19:49:59 -0400 Subject: [PATCH 5/5] [TLOZ]: Dark Rooms and Level 8 Logic Fixes (#3222) Properly name the Book to Book of Magic in Rules.py so you can actually possibly be expected to use Magical Rod plus Book of Magic to get through dark rooms. No wonder we tend to see candles so early oops. Also adding a rule that you need candles for access to Level 8 so you aren't required to time a Rod+Book shot against a moblin to burn the bush. Might make this a logic trick or something later. --- worlds/tloz/Rules.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/worlds/tloz/Rules.py b/worlds/tloz/Rules.py index f8b21bff712c..ceb1041ba576 100644 --- a/worlds/tloz/Rules.py +++ b/worlds/tloz/Rules.py @@ -49,7 +49,7 @@ def set_rules(tloz_world: "TLoZWorld"): for location in level.locations: add_rule(world.get_location(location.name, player), lambda state: state.has_group("candles", player) - or (state.has("Magical Rod", player) and state.has("Book", player))) + or (state.has("Magical Rod", player) and state.has("Book of Magic", player))) # Everything from 5 on up has gaps for level in tloz_world.levels[5:]: @@ -84,6 +84,11 @@ def set_rules(tloz_world: "TLoZWorld"): add_rule(world.get_location(location, player), lambda state: state.has_group("swords", player) or state.has("Magical Rod", player)) + # Candle access for Level 8 + for location in tloz_world.levels[8].locations: + add_rule(world.get_location(location.name, player), + lambda state: state.has_group("candles", player)) + add_rule(world.get_location("Level 8 Item (Magical Key)", player), lambda state: state.has("Bow", player) and state.has_group("arrows", player)) if options.ExpandedPool: