From 4ec20fa99721042117631d037c2934ff49db0d71 Mon Sep 17 00:00:00 2001 From: LLCoolDave Date: Fri, 23 Jun 2017 21:32:31 +0200 Subject: [PATCH] Fix up TRock key rules. Should be good enough, may still prevent some valid fire rod/cane of somaria placements with shuffled entrances, but not a big deal I hope. --- BaseClasses.py | 4 ++-- Dungeons.py | 4 +++- Main.py | 19 ++++++++++--------- Rules.py | 46 +++++++++++++++++++++++++++++++++++++--------- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index d2e0a999..ceb21b8e 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -112,7 +112,7 @@ class World(object): def find_items(self, item): return [location for location in self.get_locations() if location.item is not None and location.item.name == item] - def push_item(self, location, item, collect=True): + def push_item(self, location, item, collect=True, do_not_sweep=False): if not isinstance(location, Location): location = self.get_location(location) @@ -120,7 +120,7 @@ class World(object): location.item = item item.location = location if collect: - self.state.collect(item, location.event) + self.state.collect(item, True if do_not_sweep else location.event) logging.getLogger('').debug('Placed %s at %s' % (item, location)) else: diff --git a/Dungeons.py b/Dungeons.py index e77805bc..96e23d04 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -18,7 +18,7 @@ def fill_dungeons(world): TR = (['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Roller Switch Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)'), ItemFactory(['Small Key (Turtle Rock)'] * 4), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'])) GT = (['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)'), ItemFactory(['Small Key (Ganons Tower)'] * 4), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'])) - freebes = ['[dungeon-A2-1F] Ganons Tower - Map Room', '[dungeon-D1-1F] Dark Palace - Spike Statue Room', '[dungeon-D1-1F] Dark Palace - Big Key Room'] + freebes = ['[dungeon-A2-1F] Ganons Tower - Map Room', '[dungeon-D1-1F] Dark Palace - Spike Statue Room', '[dungeon-D1-1F] Dark Palace - Big Key Room', '[dungeon-D7-B1] Turtle Rock - Big Key Room'] all_state_base = world.get_all_state() @@ -76,6 +76,8 @@ def fill_dungeons(world): world.state._clear_cache() + return '' + dungeon_music_addresses = {'Armos - Pendant': [0x1559A], 'Lanmolas - Pendant': [0x1559B, 0x1559C, 0x1559D, 0x1559E], diff --git a/Main.py b/Main.py index a1d6718c..5e02a0a6 100644 --- a/Main.py +++ b/Main.py @@ -48,13 +48,17 @@ def main(args, seed=None): world.spoiler += link_entrances(world) + logger.info('Generating Item Pool.') + + world.spoiler += generate_itempool(world) + logger.info('Calculating Access Rules.') world.spoiler += set_rules(world) - logger.info('Generating Item Pool and placing Dungeon Items.') + logger.info('Placing Dungeon Items.') - world.spoiler += generate_itempool(world) + world.spoiler += fill_dungeons(world) logger.info('Fill the world.') @@ -417,19 +421,19 @@ def generate_itempool(world): ['Arrows (10)'] * 4 + ['Bombs (3)'] * 10) if world.mode == 'standard': - world.push_item('Uncle', ItemFactory('Progressive Sword')) + world.push_item('Uncle', ItemFactory('Progressive Sword'), do_not_sweep=True) else: world.itempool.append(ItemFactory('Progressive Sword')) # provide mirror and pearl so you can avoid fake DW/LW and do dark world exploration as intended by algorithm, for now if world.shuffle == 'insanity': - world.push_item('[cave-040] Links House', ItemFactory('Magic Mirror')) - world.push_item('[dungeon-C-1F] Sanctuary', ItemFactory('Moon Pearl')) + world.push_item('[cave-040] Links House', ItemFactory('Magic Mirror'), do_not_sweep=True) + world.push_item('[dungeon-C-1F] Sanctuary', ItemFactory('Moon Pearl'), do_not_sweep=True) else: world.itempool.extend(ItemFactory(['Magic Mirror', 'Moon Pearl'])) if world.goal == 'pedestal': - world.push_item('Altar', ItemFactory('Triforce')) + world.push_item('Altar', ItemFactory('Triforce'), False) elif world.goal == 'starhunt': world.treasure_hunt_count = 10 world.treasure_hunt_icon = 'Power Star' @@ -459,9 +463,6 @@ def generate_itempool(world): tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] world.required_medallions = (mm_medallion, tr_medallion) - # push dungeon items - fill_dungeons(world) - return 'Misery Mire Medallion: %s\nTurtle Rock Medallion: %s\n\n' % (mm_medallion, tr_medallion) diff --git a/Rules.py b/Rules.py index ef9d0b4e..2a423cb5 100644 --- a/Rules.py +++ b/Rules.py @@ -256,27 +256,20 @@ def global_rules(world): for location in ['[dungeon-D6-B1] Misery Mire - Big Chest', 'Vitreous - Heart Container']: forbid_item(world.get_location(location), 'Big Key (Misery Mire)') - # ToDo: This needs a complete overhaul set_rule(world.get_entrance('Turtle Rock Entrance Gap'), lambda state: state.has('Cane of Somaria')) set_rule(world.get_entrance('Turtle Rock Entrance Gap Reverse'), lambda state: state.has('Cane of Somaria')) set_rule(world.get_location('[dungeon-D7-1F] Turtle Rock - Compass Room'), lambda state: state.has('Cane of Somaria')) # We could get here from the middle section without Cane as we don't cross the entrance gap! set_rule(world.get_location('[dungeon-D7-1F] Turtle Rock - Map Room [left chest]'), lambda state: state.has('Cane of Somaria') and state.has('Fire Rod')) set_rule(world.get_location('[dungeon-D7-1F] Turtle Rock - Map Room [right chest]'), lambda state: state.has('Cane of Somaria') and state.has('Fire Rod')) - set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 3) if state.can_reach('Turtle Rock (Dark Room) (North)', 'Entrance') else state.has('Small Key (Turtle Rock)', 2) if state.can_reach('Turtle Rock (Eye Bridge)') else state.has('Small Key (Turtle Rock)', 1)) # May waste keys from back entrance if accessible - set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has('Small Key (Turtle Rock)', 4)) # Just to be save - set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has('Small Key (Turtle Rock)', 4) if state.can_reach('Turtle Rock (Dark Room) (North)', 'Entrance') else state.has('Small Key (Turtle Rock)', 3) if state.can_reach('Turtle Rock (Eye Bridge)') else state.has('Small Key (Turtle Rock)', 2)) # May waste keys from back entrance if accessible set_rule(world.get_location('[dungeon-D7-B1] Turtle Rock - Big Chest'), lambda state: state.has('Big Key (Turtle Rock)') and (state.has('Cane of Somaria') or state.has('Hookshot'))) set_rule(world.get_entrance('Turtle Rock (Big Chest) (North)'), lambda state: state.has('Cane of Somaria') or state.has('Hookshot')) set_rule(world.get_entrance('Turtle Rock Big Key Door'), lambda state: state.has('Big Key (Turtle Rock)')) set_rule(world.get_entrance('Turtle Rock Dark Room Staircase'), lambda state: state.has('Small Key (Turtle Rock)', 3)) set_rule(world.get_entrance('Turtle Rock (Dark Room) (North)'), lambda state: state.has('Cane of Somaria')) set_rule(world.get_entrance('Turtle Rock (Dark Room) (South)'), lambda state: state.has('Cane of Somaria')) - set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and - state.has('Cane of Somaria') and state.has('Fire Rod') and state.has('Ice Rod') and + set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and state.has('Cane of Somaria') and state.has('Fire Rod') and state.has('Ice Rod') and (state.has('Hammer') or state.has_beam_sword() or state.has('Bottle') or state.has('Half Magic') or state.has('Quarter Magic'))) - for location in ['[dungeon-D7-B1] Turtle Rock - Big Chest', 'Trinexx - Heart Container', '[dungeon-D7-B1] Turtle Rock - Roller Switch Room', '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [bottom left chest]', - '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [bottom right chest]', '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [top left chest]', '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [top right chest]']: # ToDo Big Key can be elsewhere if we have an entrance shuffle - forbid_item(world.get_location(location), 'Big Key (Turtle Rock)') + set_trock_key_rules(world) set_rule(world.get_entrance('Dark Palace Bonk Wall'), lambda state: state.has('Bow')) set_rule(world.get_entrance('Dark Palace Hammer Peg Drop'), lambda state: state.has('Hammer')) @@ -390,6 +383,41 @@ def standard_rules(world): add_rule(world.get_location('[dungeon-C-B1] Escape - Final Basement Room [right chest]'), lambda state: state.can_reach('Sewer Drop')) add_rule(world.get_location('[dungeon-C-B1] Escape - First B1 Room'), lambda state: state.can_reach('Sewer Drop') or (state.world.get_location('[dungeon-C-B1] Escape - First B1 Room').item is not None and state.world.get_location('[dungeon-C-B1] Escape - First B1 Room').item.name in ['Small Key (Escape)'])) # you could skip this chest and be unable to go back until you can drop into escape +def set_trock_key_rules(world): + # this is good enough to allow even key distribution but may still prevent certain valid item combinations from being placed + + all_state = world.get_all_state() + + # check if the back entrance into trock can be accessed. As no small keys are placed yet, the rule on the dark room staircase door + # prevents us from reach the eye bridge from within the dungeon (!) + can_reach_back = all_state.can_reach(world.get_region('Turtle Rock (Eye Bridge)')) + + # if we have backdoor access we can waste a key on the trinexx door, then have no lamp to reverse traverse the maze room. We simply require an additional key just to be super safe then. The backdoor access to the chest is otherwise free + set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 1)) if not can_reach_back else set_rule(world.get_entrance('Turtle Rock Pokey Room'), lambda state: state.has('Small Key (Turtle Rock)', 2)) + + # if we have front access this transition is useless. If we don't, it's a dead end so cannot hold any small keys + set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)'), lambda state: state.has('Small Key (Turtle Rock)', 4)) + + # this is just the pokey room with one more key + set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has('Small Key (Turtle Rock)', 2)) if not can_reach_back else set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)'), lambda state: state.has('Small Key (Turtle Rock)', 3)) + + # the most complicated one + # if we have back entrance access, we could waste all keys before touching this + # if we don't, we have access to all chests by the time we can waste a key on trinexx door + # in that case, if it contains the big key, we can also not waste a key on the roller switch door + set_rule(world.get_location('[dungeon-D7-B1] Turtle Rock - Big Key Room'), lambda state: state.has('Small Key (Turtle Rock)', 4) or (state.world.get_location('[dungeon-D7-B1] Turtle Rock - Big Key Room').item is not None and (state.world.get_location('[dungeon-D7-B1] Turtle Rock - Big Key Room').item.name in ['Small Key (Turtle Rock)']))) if can_reach_back else \ + set_rule(world.get_location('[dungeon-D7-B1] Turtle Rock - Big Key Room'), lambda state: state.has('Small Key (Turtle Rock)', 2) if (state.world.get_location('[dungeon-D7-B1] Turtle Rock - Big Key Room').item is not None and (state.world.get_location('[dungeon-D7-B1] Turtle Rock - Big Key Room').item.name in ['Big Key (Turtle Rock)'])) else state.has('Small Key (Turtle Rock)', 3)) + + # set big key restrictions + non_big_key_locations = ['[dungeon-D7-B1] Turtle Rock - Big Chest', 'Trinexx - Heart Container'] + if not can_reach_back: + non_big_key_locations += ['[dungeon-D7-B1] Turtle Rock - Roller Switch Room', '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [bottom left chest]', + '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [bottom right chest]', '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [top left chest]', + '[dungeon-D7-B2] Turtle Rock - Eye Bridge Room [top right chest]'] + + for location in non_big_key_locations: + forbid_item(world.get_location(location), 'Big Key (Turtle Rock)') + def set_big_bomb_rules(world): # this is a mess