Partially implement variable crystal requirements

This commit is contained in:
Kevin Cathcart 2019-07-25 18:25:14 -04:00
parent 18f1275050
commit 90e5f522d8
3 changed files with 124 additions and 117 deletions

View File

@ -71,6 +71,8 @@ class World(object):
self.fix_fake_world = True self.fix_fake_world = True
self.boss_shuffle = boss_shuffle self.boss_shuffle = boss_shuffle
self.hints = hints self.hints = hints
self.crystals_needed_for_ganon = 7
self.crystals_needed_for_gt = 7
self.dynamic_regions = [] self.dynamic_regions = []
self.dynamic_locations = [] self.dynamic_locations = []
self.spoiler = Spoiler(self) self.spoiler = Spoiler(self)
@ -367,6 +369,10 @@ class CollectionState(object):
def item_count(self, item, player): def item_count(self, item, player):
return self.prog_items.count((item, player)) return self.prog_items.count((item, player))
def has_crystals(self, count, player):
crystals = ['Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7']
return len([crystal for crystal in crystals if self.has(crystal, player)]) >= count
def can_lift_rocks(self, player): def can_lift_rocks(self, player):
return self.has('Power Glove', player) or self.has('Titans Mitts', player) return self.has('Power Glove', player) or self.has('Titans Mitts', player)

225
Rom.py
View File

@ -929,6 +929,9 @@ def patch_rom(world, player, rom):
else: else:
rom.write_byte(0x18003E, 0x03) # make ganon invincible until all crystals and aga 2 are collected rom.write_byte(0x18003E, 0x03) # make ganon invincible until all crystals and aga 2 are collected
rom.write_byte(0x18005E, world.crystals_needed_for_gt)
rom.write_byte(0x18005F, world.crystals_needed_for_ganon)
rom.write_byte(0x18016A, 0x01 if world.keysanity else 0x00) # free roaming item text boxes rom.write_byte(0x18016A, 0x01 if world.keysanity else 0x00) # free roaming item text boxes
rom.write_byte(0x18003B, 0x01 if world.keysanity else 0x00) # maps showing crystals on overworld rom.write_byte(0x18003B, 0x01 if world.keysanity else 0x00) # maps showing crystals on overworld
@ -1739,114 +1742,114 @@ InsanityEntrances = {'Sanctuary': 'Sanctuary',
'Hookshot Cave Back Entrance': 'The stairs on the floating island' 'Hookshot Cave Back Entrance': 'The stairs on the floating island'
} }
HintLocations = ['telepathic_tile_eastern_palace', HintLocations = ['telepathic_tile_eastern_palace',
'telepathic_tile_tower_of_hera_floor_4', 'telepathic_tile_tower_of_hera_floor_4',
'telepathic_tile_spectacle_rock', 'telepathic_tile_spectacle_rock',
'telepathic_tile_swamp_entrance', 'telepathic_tile_swamp_entrance',
'telepathic_tile_thieves_town_upstairs', 'telepathic_tile_thieves_town_upstairs',
'telepathic_tile_misery_mire', 'telepathic_tile_misery_mire',
'telepathic_tile_palace_of_darkness', 'telepathic_tile_palace_of_darkness',
'telepathic_tile_desert_bonk_torch_room', 'telepathic_tile_desert_bonk_torch_room',
'telepathic_tile_castle_tower', 'telepathic_tile_castle_tower',
'telepathic_tile_ice_large_room', 'telepathic_tile_ice_large_room',
'telepathic_tile_turtle_rock', 'telepathic_tile_turtle_rock',
'telepathic_tile_ice_entrace', 'telepathic_tile_ice_entrace',
'telepathic_tile_ice_stalfos_knights_room', 'telepathic_tile_ice_stalfos_knights_room',
'telepathic_tile_tower_of_hera_entrance', 'telepathic_tile_tower_of_hera_entrance',
'telepathic_tile_south_east_darkworld_cave', 'telepathic_tile_south_east_darkworld_cave',
'dark_palace_tree_dude', 'dark_palace_tree_dude',
'dark_sanctuary_hint_0', 'dark_sanctuary_hint_0',
'dark_sanctuary_hint_1', 'dark_sanctuary_hint_1',
'dark_sanctuary_yes', 'dark_sanctuary_yes',
'dark_sanctuary_hint_2'] 'dark_sanctuary_hint_2']
InconvenientLocations = ['Spike Cave', InconvenientLocations = ['Spike Cave',
'Sahasrahla', 'Sahasrahla',
'Purple Chest', 'Purple Chest',
'Swamp Left', 'Swamp Left',
'Mire Left', 'Mire Left',
'Tower of Hera - Big Key Chest', 'Tower of Hera - Big Key Chest',
'Eastern Palace - Big Key Chest', 'Eastern Palace - Big Key Chest',
'Thieves\' Town - Big Chest', 'Thieves\' Town - Big Chest',
'Ice Palace - Big Chest', 'Ice Palace - Big Chest',
'Ganons Tower - Big Chest', 'Ganons Tower - Big Chest',
'Magic Bat'] 'Magic Bat']
RelevantItems = ['Bow', RelevantItems = ['Bow',
'Book of Mudora', 'Book of Mudora',
'Hammer', 'Hammer',
'Hookshot', 'Hookshot',
'Magic Mirror', 'Magic Mirror',
'Ocarina', 'Ocarina',
'Pegasus Boots', 'Pegasus Boots',
'Power Glove', 'Power Glove',
'Cape', 'Cape',
'Mushroom', 'Mushroom',
'Shovel', 'Shovel',
'Lamp', 'Lamp',
'Magic Powder', 'Magic Powder',
'Moon Pearl', 'Moon Pearl',
'Cane of Somaria', 'Cane of Somaria',
'Fire Rod', 'Fire Rod',
'Flippers', 'Flippers',
'Ice Rod', 'Ice Rod',
'Titans Mitts', 'Titans Mitts',
'Ether', 'Ether',
'Bombos', 'Bombos',
'Quake', 'Quake',
'Bottle', 'Bottle',
'Bottle (Red Potion)', 'Bottle (Red Potion)',
'Bottle (Green Potion)', 'Bottle (Green Potion)',
'Bottle (Blue Potion)', 'Bottle (Blue Potion)',
'Bottle (Fairy)', 'Bottle (Fairy)',
'Bottle (Bee)', 'Bottle (Bee)',
'Bottle (Good Bee)', 'Bottle (Good Bee)',
'Master Sword', 'Master Sword',
'Tempered Sword', 'Tempered Sword',
'Fighter Sword', 'Fighter Sword',
'Golden Sword', 'Golden Sword',
'Progressive Sword', 'Progressive Sword',
'Progressive Glove', 'Progressive Glove',
'Master Sword', 'Master Sword',
'Power Star', 'Power Star',
'Triforce Piece', 'Triforce Piece',
'Single Arrow', 'Single Arrow',
'Blue Mail', 'Blue Mail',
'Red Mail', 'Red Mail',
'Progressive Armor', 'Progressive Armor',
'Blue Boomerang', 'Blue Boomerang',
'Red Boomerang', 'Red Boomerang',
'Blue Shield', 'Blue Shield',
'Red Shield', 'Red Shield',
'Mirror Shield', 'Mirror Shield',
'Progressive Shield', 'Progressive Shield',
'Bug Catching Net', 'Bug Catching Net',
'Cane of Byrna', 'Cane of Byrna',
'Magic Upgrade (1/2)', 'Magic Upgrade (1/2)',
'Magic Upgrade (1/4)' 'Magic Upgrade (1/4)'
] ]
KeysanityItems = ['Small Key (Eastern Palace)', KeysanityItems = ['Small Key (Eastern Palace)',
'Big Key (Eastern Palace)', 'Big Key (Eastern Palace)',
'Small Key (Escape)', 'Small Key (Escape)',
'Small Key (Desert Palace)', 'Small Key (Desert Palace)',
'Big Key (Desert Palace)', 'Big Key (Desert Palace)',
'Small Key (Tower of Hera)', 'Small Key (Tower of Hera)',
'Big Key (Tower of Hera)', 'Big Key (Tower of Hera)',
'Small Key (Agahnims Tower)', 'Small Key (Agahnims Tower)',
'Small Key (Palace of Darkness)', 'Small Key (Palace of Darkness)',
'Big Key (Palace of Darkness)', 'Big Key (Palace of Darkness)',
'Small Key (Thieves Town)', 'Small Key (Thieves Town)',
'Big Key (Thieves Town)', 'Big Key (Thieves Town)',
'Small Key (Swamp Palace)', 'Small Key (Swamp Palace)',
'Big Key (Swamp Palace)', 'Big Key (Swamp Palace)',
'Small Key (Skull Woods)', 'Small Key (Skull Woods)',
'Big Key (Skull Woods)', 'Big Key (Skull Woods)',
'Small Key (Ice Palace)', 'Small Key (Ice Palace)',
'Big Key (Ice Palace)', 'Big Key (Ice Palace)',
'Small Key (Misery Mire)', 'Small Key (Misery Mire)',
'Big Key (Misery Mire)', 'Big Key (Misery Mire)',
'Small Key (Turtle Rock)', 'Small Key (Turtle Rock)',
'Big Key (Turtle Rock)', 'Big Key (Turtle Rock)',
'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)',
'Big Key (Ganons Tower)' 'Big Key (Ganons Tower)'
] ]

View File

@ -43,7 +43,7 @@ def set_rules(world, player):
if world.goal == 'dungeons': if world.goal == 'dungeons':
# require all dungeons to beat ganon # require all dungeons to beat ganon
add_rule(world.get_location('Ganon', player), lambda state: state.can_reach('Master Sword Pedestal', 'Location', player) and state.has('Beat Agahnim 1', player) and state.has('Beat Agahnim 2', player)) add_rule(world.get_location('Ganon', player), lambda state: state.can_reach('Master Sword Pedestal', 'Location', player) and state.has('Beat Agahnim 1', player) and state.has('Beat Agahnim 2', player) and state.has_crystals(7, player))
elif world.goal == 'ganon': elif world.goal == 'ganon':
# require aga2 to beat ganon # require aga2 to beat ganon
add_rule(world.get_location('Ganon', player), lambda state: state.has('Beat Agahnim 2', player)) add_rule(world.get_location('Ganon', player), lambda state: state.has('Beat Agahnim 2', player))
@ -427,8 +427,7 @@ def global_rules(world, player):
'Ganons Tower - Pre-Moldorm Chest', 'Ganons Tower - Validation Chest']: 'Ganons Tower - Pre-Moldorm Chest', 'Ganons Tower - Validation Chest']:
forbid_item(world.get_location(location, player), 'Big Key (Ganons Tower)', player) forbid_item(world.get_location(location, player), 'Big Key (Ganons Tower)', player)
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has('Crystal 1', player) and state.has('Crystal 2', player) set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon, player)
and state.has('Crystal 3', player) and state.has('Crystal 4', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player) and state.has('Crystal 7', player)
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop
@ -436,7 +435,7 @@ def global_rules(world, player):
set_trock_key_rules(world, player) set_trock_key_rules(world, player)
set_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has('Crystal 1', player) and state.has('Crystal 2', player) and state.has('Crystal 3', player) and state.has('Crystal 4', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player) and state.has('Crystal 7', player)) set_rule(world.get_entrance('Ganons Tower', player), lambda state: state.has_crystals(world.crystals_needed_for_gt, player))
def inverted_rules(world, player): def inverted_rules(world, player):
world.get_location('Ganon', player).item_rule = lambda item: item.name == 'Triforce' and item.player == player world.get_location('Ganon', player).item_rule = lambda item: item.name == 'Triforce' and item.player == player
@ -901,8 +900,7 @@ def swordless_rules(world, player):
set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!) set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player)) # sword not required to use medallion for opening in swordless (!)
set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player)) # no curtain set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player)) # no curtain
set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) #in swordless mode bombos pads are present in the relevant parts of ice palace set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) #in swordless mode bombos pads are present in the relevant parts of ice palace
set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has('Crystal 1', player) and state.has('Crystal 2', player) set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Arrows', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon, player))
and state.has('Crystal 3', player) and state.has('Crystal 4', player) and state.has('Crystal 5', player) and state.has('Crystal 6', player) and state.has('Crystal 7', player))
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player)) # need to damage ganon to get tiles to drop