From ab99e8c223183e4e24e271f2743982b57b08cac4 Mon Sep 17 00:00:00 2001 From: Kevin Cathcart Date: Wed, 28 Aug 2019 21:12:44 -0400 Subject: [PATCH 1/7] Triforce Hunt turn-in logic --- BaseClasses.py | 2 +- ItemList.py | 14 ++++++++++++++ Main.py | 5 +++++ Rom.py | 2 ++ Text.py | 1 + 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 4715fff6..ca6044c1 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -263,7 +263,7 @@ class World(object): def has_beaten_game(self, state, player=None): if player: - return state.has('Triforce', player) or (self.goal in ['triforcehunt'] and (state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) > self.treasure_hunt_count)) + return state.has('Triforce', player) else: return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1))) diff --git a/ItemList.py b/ItemList.py index d8df5fbd..a25423fb 100644 --- a/ItemList.py +++ b/ItemList.py @@ -137,6 +137,20 @@ def generate_itempool(world, player): else: world.push_item(world.get_location('Ganon', player), ItemFactory('Triforce', player), False) + if world.goal in ['triforcehunt']: + region = world.get_region('Hyrule Castle Courtyard', player) + + loc = Location(player, "Murahdahla", parent=region) + loc.access_rule = lambda state: state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) > state.world.treasure_hunt_count + region.locations.append(loc) + world.dynamic_locations.append(loc) + + world.clear_location_cache() + + world.push_item(loc, ItemFactory('Triforce', player), False) + loc.event = True + loc.locked = True + world.get_location('Ganon', player).event = True world.get_location('Ganon', player).locked = True world.push_item(world.get_location('Agahnim 1', player), ItemFactory('Beat Agahnim 1', player), False) diff --git a/Main.py b/Main.py index bba6c61a..9442c8ab 100644 --- a/Main.py +++ b/Main.py @@ -276,6 +276,11 @@ def copy_dynamic_regions_and_locations(world, ret): for location in world.dynamic_locations: new_reg = ret.get_region(location.parent_region.name, location.parent_region.player) new_loc = Location(location.player, location.name, location.address, location.crystal, location.hint_text, new_reg) + # todo: this is potentially dangerous. later refactor so we + # can apply dynamic region rules on top of copied world like other rules + new_loc.access_rule = location.access_rule + new_loc.always_allow = location.always_allow + new_loc.item_rule = location.item_rule new_reg.locations.append(new_loc) ret.clear_location_cache() diff --git a/Rom.py b/Rom.py index 01d25247..2db68438 100644 --- a/Rom.py +++ b/Rom.py @@ -837,6 +837,7 @@ def patch_rom(world, player, rom): # set up goals for treasure hunt rom.write_bytes(0x180165, [0x0E, 0x28] if world.treasure_hunt_icon == 'Triforce Piece' else [0x0D, 0x28]) rom.write_byte(0x180167, world.treasure_hunt_count % 256) + rom.write_byte(0x180194, 1) # Must turn in triforced pieces (instant win not enabled) # TODO: a proper race rom mode should be implemented, that changes the following flag, and rummages the table (or uses the future encryption feature, etc) rom.write_bytes(0x180213, [0x00, 0x01]) # Not a Tournament Seed @@ -1318,6 +1319,7 @@ def write_strings(rom, world, player): tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Get the Triforce Pieces.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!' + tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % world.treasure_hunt_count elif world.goal 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.' diff --git a/Text.py b/Text.py index 517ccf18..ac254287 100644 --- a/Text.py +++ b/Text.py @@ -1890,5 +1890,6 @@ class TextTable(object): text['ganon_phase_3_no_silvers_alt'] = CompressedTextMapper.convert("You can't best me without silver arrows!") text['ganon_phase_3_no_silvers'] = CompressedTextMapper.convert("You can't best me without silver arrows!") text['ganon_phase_3_silvers'] = CompressedTextMapper.convert("Oh no! Silver! My one true weakness!") + text['murahdahla'] = CompressedTextMapper.convert("Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! you can see me? I knew I should have\nhidden in a hollow tree.") text['end_pad_data'] = bytearray([0xfb]) text['terminator'] = bytearray([0xFF, 0xFF]) From 0a759f18d653f2575aa145ff9da4a5aee9069df4 Mon Sep 17 00:00:00 2001 From: cassidoxa <43386495+cassidoxa@users.noreply.github.com> Date: Wed, 28 Aug 2019 21:13:35 -0400 Subject: [PATCH 2/7] Undo write causing map tile glitch in EP area (#9) --- Rom.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Rom.py b/Rom.py index 2db68438..f7960bfa 100644 --- a/Rom.py +++ b/Rom.py @@ -1403,8 +1403,6 @@ def set_inverted_mode(world, rom): rom.write_int16s(snes_to_pc(0x02E849), [0x0043, 0x0056, 0x0058, 0x006C, 0x006F, 0x0070, 0x007B, 0x007F, 0x001B]) # dw flute rom.write_int16(snes_to_pc(0x02E8D5), 0x07C8) rom.write_int16(snes_to_pc(0x02E8F7), 0x01F8) - rom.write_byte(0x7A943, 0xF0) - rom.write_byte(0x7A96D, 0xD0) rom.write_byte(snes_to_pc(0x08D40C), 0xD0) # morph proof # the following bytes should only be written in vanilla # or they'll overwrite the randomizer's shuffles From 80217b269e3eae009d0772147ef0ef8cce6feae6 Mon Sep 17 00:00:00 2001 From: Kevin Cathcart Date: Wed, 28 Aug 2019 21:38:08 -0400 Subject: [PATCH 3/7] Fix inverted triforce hunt --- ItemList.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index a25423fb..6dac7a01 100644 --- a/ItemList.py +++ b/ItemList.py @@ -138,7 +138,10 @@ def generate_itempool(world, player): world.push_item(world.get_location('Ganon', player), ItemFactory('Triforce', player), False) if world.goal in ['triforcehunt']: - region = world.get_region('Hyrule Castle Courtyard', player) + if world.mode == 'inverted': + region = world.get_region('Light World',player) + else: + region = world.get_region('Hyrule Castle Courtyard', player) loc = Location(player, "Murahdahla", parent=region) loc.access_rule = lambda state: state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) > state.world.treasure_hunt_count From 7249429f69ee2aaafb08a7fb4c7ace7af2c7b26d Mon Sep 17 00:00:00 2001 From: Kevin Cathcart Date: Mon, 2 Sep 2019 15:33:34 -0400 Subject: [PATCH 4/7] Fix silvers hint --- Rom.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Rom.py b/Rom.py index f7960bfa..04c0a5d5 100644 --- a/Rom.py +++ b/Rom.py @@ -1278,17 +1278,18 @@ def write_strings(rom, world, player): random.shuffle(silverarrows) silverarrow_hint = (' %s?' % hint_text(silverarrows[0]).replace('Ganon\'s', 'my')) if silverarrows else '?\nI think not!' tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint + tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint prog_bow_locs = world.find_items('Progressive Bow', player) distinguished_prog_bow_loc = next((location for location in prog_bow_locs if location.item.code == 0x65), None) if distinguished_prog_bow_loc: prog_bow_locs.remove(distinguished_prog_bow_loc) silverarrow_hint = (' %s?' % hint_text(distinguished_prog_bow_loc).replace('Ganon\'s', 'my')) - tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint + tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint if any(prog_bow_locs): silverarrow_hint = (' %s?' % hint_text(random.choice(prog_bow_locs)).replace('Ganon\'s', 'my')) - tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint + tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint silverarrow_hint = (' %s?' % hint_text(silverarrows[0]).replace('Ganon\'s', 'my')) if silverarrows else '?\nI think not!' From f2c62e87ef7af9561d1cce810ed736c93b864aca Mon Sep 17 00:00:00 2001 From: Kevin Cathcart Date: Mon, 2 Sep 2019 15:34:52 -0400 Subject: [PATCH 5/7] Update flavor text --- Rom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index 04c0a5d5..843cabf2 100644 --- a/Rom.py +++ b/Rom.py @@ -1320,7 +1320,7 @@ def write_strings(rom, world, player): tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Get the Triforce Pieces.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!' - tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % world.treasure_hunt_count + tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % world.treasure_hunt_count elif world.goal 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.' From f593370ec042643fc8a4be623c086b5a5dfbca4e Mon Sep 17 00:00:00 2001 From: cassidoxa Date: Sat, 31 Aug 2019 17:41:33 -0400 Subject: [PATCH 6/7] Prevent placing incorrect bosses in GT in inverted enemizer --- Bosses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bosses.py b/Bosses.py index 30cd56da..2713c92c 100644 --- a/Bosses.py +++ b/Bosses.py @@ -119,11 +119,11 @@ def can_place_boss(world, boss, dungeon_name, level=None): if world.swords in ['swordless'] and boss == 'Kholdstare' and dungeon_name != 'Ice Palace': return False - if dungeon_name == 'Ganons Tower' and level == 'top': + if dungeon_name in ['Ganons Tower', 'Inverted Ganons Tower'] and level == 'top': if boss in ["Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"]: return False - if dungeon_name == 'Ganons Tower' and level == 'middle': + if dungeon_name in ['Ganons Tower', 'Inverted Ganons Tower'] and level == 'middle': if boss in ["Blind"]: return False From d393657eac69a6630b424908cda676ea6eed6bc8 Mon Sep 17 00:00:00 2001 From: cassidoxa Date: Sat, 31 Aug 2019 17:54:20 -0400 Subject: [PATCH 7/7] Fix mixup of DM Return caves East and West --- EntranceShuffle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 0fafb1d2..1cd053ba 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -3511,8 +3511,8 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Bumper Cave (Top)', 'Dark Death Mountain Healer Fairy'), ('Bumper Cave Exit (Top)', 'Death Mountain Return Ledge'), ('Bumper Cave Exit (Bottom)', 'Light World'), - ('Death Mountain Return Cave (East)', 'Bumper Cave'), - ('Death Mountain Return Cave (West)', 'Death Mountain Return Cave'), + ('Death Mountain Return Cave (West)', 'Bumper Cave'), + ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), ('Hookshot Cave Exit (South)', 'Dark Death Mountain'),