Basic impl. of boss shuffle for VT site enemizer integration
This commit is contained in:
parent
5539143f00
commit
b90a381e9b
|
@ -7,7 +7,7 @@ from Utils import int16_as_bytes
|
|||
|
||||
class World(object):
|
||||
|
||||
def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity, retro, custom, customitemarray):
|
||||
def __init__(self, shuffle, logic, mode, difficulty, timer, progressive, goal, algorithm, place_dungeon_items, check_beatable_only, shuffle_ganon, quickswap, fastmenu, disable_music, keysanity, retro, custom, customitemarray, boss_shuffle):
|
||||
self.shuffle = shuffle
|
||||
self.logic = logic
|
||||
self.mode = mode
|
||||
|
@ -63,6 +63,7 @@ class World(object):
|
|||
self.can_take_damage = True
|
||||
self.difficulty_requirements = None
|
||||
self.fix_fake_world = True
|
||||
self.boss_shuffle = boss_shuffle
|
||||
self.dynamic_regions = []
|
||||
self.dynamic_locations = []
|
||||
self.spoiler = Spoiler(self)
|
||||
|
@ -110,6 +111,15 @@ class World(object):
|
|||
return r_location
|
||||
raise RuntimeError('No such location %s' % location)
|
||||
|
||||
def get_dungeon(self, dungeonname):
|
||||
if isinstance(dungeonname, Dungeon):
|
||||
return dungeonname
|
||||
|
||||
for dungeon in self.dungeons:
|
||||
if dungeon.name == dungeonname:
|
||||
return dungeon
|
||||
raise RuntimeError('No such dungeon %s' % dungeonname)
|
||||
|
||||
def get_all_state(self, keys=False):
|
||||
ret = CollectionState(self)
|
||||
|
||||
|
@ -687,6 +697,15 @@ class Dungeon(object):
|
|||
self.big_key = big_key
|
||||
self.small_keys = small_keys
|
||||
self.dungeon_items = dungeon_items
|
||||
self.bosses = dict()
|
||||
|
||||
@property
|
||||
def boss(self):
|
||||
return self.bosses.get(None, None)
|
||||
|
||||
@boss.setter
|
||||
def boss(self, value):
|
||||
self.bosses[None] = value
|
||||
|
||||
@property
|
||||
def keys(self):
|
||||
|
@ -705,9 +724,16 @@ class Dungeon(object):
|
|||
def __unicode__(self):
|
||||
return '%s' % self.name
|
||||
|
||||
class Boss(object):
|
||||
def __init__(self, name, enemizer_name, defeat_rule):
|
||||
self.name = name
|
||||
self.enemizer_name = enemizer_name
|
||||
self.defeat_rule = defeat_rule
|
||||
|
||||
def can_defeat(self, state):
|
||||
return self.defeat_rule(state)
|
||||
|
||||
class Location(object):
|
||||
|
||||
def __init__(self, name='', address=None, crystal=False, hint_text=None, parent=None):
|
||||
self.name = name
|
||||
self.parent_region = parent
|
||||
|
@ -854,6 +880,7 @@ class Spoiler(object):
|
|||
self.paths = {}
|
||||
self.metadata = {}
|
||||
self.shops = []
|
||||
self.bosses = OrderedDict()
|
||||
|
||||
def set_entrance(self, entrance, exit, direction):
|
||||
self.entrances[(entrance, direction)] = OrderedDict([('entrance', entrance), ('exit', exit), ('direction', direction)])
|
||||
|
@ -898,6 +925,23 @@ class Spoiler(object):
|
|||
shopdata['item_{}'.format(index)] = "{} — {}".format(item['item'], item['price']) if item['price'] else item['item']
|
||||
self.shops.append(shopdata)
|
||||
|
||||
self.bosses["Eastern Palace"] = self.world.get_dungeon("Eastern Palace").boss.name
|
||||
self.bosses["Desert Palace"] = self.world.get_dungeon("Desert Palace").boss.name
|
||||
self.bosses["Tower Of Hera"] = self.world.get_dungeon("Tower of Hera").boss.name
|
||||
self.bosses["Hyrule Castle"] = "Agahnim"
|
||||
self.bosses["Palace Of Darkness"] = self.world.get_dungeon("Palace of Darkness").boss.name
|
||||
self.bosses["Swamp Palace"] = self.world.get_dungeon("Swamp Palace").boss.name
|
||||
self.bosses["Skull Woods"] = self.world.get_dungeon("Skull Woods").boss.name
|
||||
self.bosses["Thieves Town"] = self.world.get_dungeon("Thieves Town").boss.name
|
||||
self.bosses["Ice Palace"] = self.world.get_dungeon("Ice Palace").boss.name
|
||||
self.bosses["Misery Mire"] = self.world.get_dungeon("Misery Mire").boss.name
|
||||
self.bosses["Turtle Rock"] = self.world.get_dungeon("Turtle Rock").boss.name
|
||||
self.bosses["Ganons Tower Basement"] = self.world.get_dungeon('Ganons Tower').bosses['bottom'].name
|
||||
self.bosses["Ganons Tower Middle"] = self.world.get_dungeon('Ganons Tower').bosses['middle'].name
|
||||
self.bosses["Ganons Tower Top"] = self.world.get_dungeon('Ganons Tower').bosses['top'].name
|
||||
self.bosses["Ganons Tower"] = "Agahnim 2"
|
||||
self.bosses["Ganon"] = "Ganon"
|
||||
|
||||
|
||||
from Main import __version__ as ERVersion
|
||||
self.metadata = {'version': ERVersion,
|
||||
|
@ -927,7 +971,10 @@ class Spoiler(object):
|
|||
out['Shops'] = self.shops
|
||||
out['playthrough'] = self.playthrough
|
||||
out['paths'] = self.paths
|
||||
if(self.world.boss_shuffle != 'none'):
|
||||
out['bosses'] = self.bosses
|
||||
out['meta'] = self.metadata
|
||||
|
||||
return json.dumps(out)
|
||||
|
||||
def to_file(self, filename):
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
import logging
|
||||
import random
|
||||
|
||||
from BaseClasses import Boss
|
||||
from Fill import FillError
|
||||
|
||||
def BossFactory(boss):
|
||||
if boss is None:
|
||||
return None
|
||||
if boss in boss_table:
|
||||
enemizer_name, defeat_rule = boss_table[boss]
|
||||
return Boss(boss, enemizer_name, defeat_rule)
|
||||
|
||||
logging.getLogger('').error('Unknown Boss: %s', boss)
|
||||
return None
|
||||
|
||||
def ArmosKnightsDefeatRule(state):
|
||||
# Magic amounts are probably a bit overkill
|
||||
return (
|
||||
state.has_blunt_weapon() or
|
||||
(state.has('Cane of Somaria') and state.can_extend_magic(10)) or
|
||||
(state.has('Cane of Byrna') and state.can_extend_magic(16)) or
|
||||
(state.has('Ice Rod') and state.can_extend_magic(32)) or
|
||||
(state.has('Fire Rod') and state.can_extend_magic(32)) or
|
||||
state.has('Blue Boomerang') or
|
||||
state.has('Red Boomerang'))
|
||||
|
||||
def LanmolasDefeatRule(state):
|
||||
# TODO: Allow the canes here?
|
||||
return (
|
||||
state.has_blunt_weapon() or
|
||||
state.has('Fire Rod') or
|
||||
state.has('Ice Rod') or
|
||||
state.can_shoot_arrows())
|
||||
|
||||
def MoldormDefeatRule(state):
|
||||
return state.has_blunt_weapon()
|
||||
|
||||
def HelmasaurKingDefeatRule(state):
|
||||
return state.has_blunt_weapon() or state.can_shoot_arrows()
|
||||
|
||||
def ArrghusDefeatRule(state):
|
||||
if not state.has('Hookshot'):
|
||||
return False
|
||||
# TODO: ideally we would have a check for bow and silvers, which combined with the
|
||||
# hookshot is enough. This is not coded yet because the silvers that only work in pyramid feature
|
||||
# makes this complicated
|
||||
if state.has_blunt_weapon():
|
||||
return True
|
||||
|
||||
return ((state.has('Fire Rod') and (state.can_shoot_arrows() or state.can_extend_magic(12))) or #assuming mostly gitting two puff with one shot
|
||||
(state.has('Ice Rod') and (state.can_shoot_arrows() or state.can_extend_magic(16))))
|
||||
|
||||
|
||||
def MothulaDefeatRule(state):
|
||||
return (
|
||||
state.has_blunt_weapon() or
|
||||
(state.has('Fire Rod') and state.can_extend_magic(10)) or
|
||||
# TODO: Not sure how much (if any) extend magic is needed for these two, since they only apply
|
||||
# to non-vanilla locations, so are harder to test, so sticking with what VT has for now:
|
||||
(state.has('Cane of Somaria') and state.can_extend_magic(16)) or
|
||||
(state.has('Cane of Byrna') and state.can_extend_magic(16)) or
|
||||
state.can_get_good_bee()
|
||||
)
|
||||
|
||||
def BlindDefeatRule(state):
|
||||
return state.has_blunt_weapon() or state.has('Cane of Somaria') or state.has('Cane of Byrna')
|
||||
|
||||
def KholdstareDefeatRule(state):
|
||||
return (
|
||||
(
|
||||
state.has('Fire Rod') or
|
||||
(
|
||||
state.has('Bombos') and
|
||||
# FIXME: the following only actually works for the vanilla location for swordless mode
|
||||
(state.has_sword() or state.world.mode == 'swordless')
|
||||
)
|
||||
) and
|
||||
(
|
||||
state.has_blunt_weapon() or
|
||||
(state.has('Fire Rod') and state.can_extend_magic(20)) or
|
||||
# FIXME: this actually only works for the vanilla location for swordless mode
|
||||
(
|
||||
state.has('Fire Rod') and
|
||||
state.has('Bombos') and
|
||||
state.world.mode == 'swordless' and
|
||||
state.can_extend_magic(16)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def VitreousDefeatRule(state):
|
||||
return state.can_shoot_arrows() or state.has_blunt_weapon()
|
||||
|
||||
def TrinexxDefeatRule(state):
|
||||
if not (state.has('Fire Rod') and state.has('Ice Rod')):
|
||||
return False
|
||||
return state.has('Hammer') or state.has_beam_sword() or (state.has_sword() and state.can_extend_magic(32))
|
||||
|
||||
def AgahnimDefeatRule(state):
|
||||
return state.has_sword() or state.has('Hammer') or state.has('Bug Catching Net')
|
||||
|
||||
boss_table = {
|
||||
'Armos Knights': ('Armos', ArmosKnightsDefeatRule),
|
||||
'Lanmolas': ('Lanmola', LanmolasDefeatRule),
|
||||
'Moldorm': ('Moldorm', MoldormDefeatRule),
|
||||
'Helmasaur King': ('Helmasaur', HelmasaurKingDefeatRule),
|
||||
'Arrghus': ('Arrghus', ArrghusDefeatRule),
|
||||
'Mothula': ('Mothula', MothulaDefeatRule),
|
||||
'Blind': ('Blind', BlindDefeatRule),
|
||||
'Kholdstare': ('Kholdstare', KholdstareDefeatRule),
|
||||
'Vitreous': ('Vitreous', VitreousDefeatRule),
|
||||
'Trinexx': ('Trinexx', TrinexxDefeatRule),
|
||||
'Agahnim': ('Agahnim', AgahnimDefeatRule),
|
||||
'Agahnim2': ('Agahnim2', AgahnimDefeatRule)
|
||||
}
|
||||
|
||||
def can_place_boss(world, boss, dungeon_name, level=None):
|
||||
if world.mode in ['swordless'] and boss == 'Kholdstare' and dungeon_name != 'Ice Palace':
|
||||
return False
|
||||
|
||||
if dungeon_name == '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 boss in ["Blind"]:
|
||||
return False
|
||||
|
||||
if dungeon_name == 'Tower of Hera' and boss in ["Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"]:
|
||||
return False
|
||||
|
||||
if dungeon_name == 'Skull Woods' and boss in ["Trinexx"]:
|
||||
return False
|
||||
|
||||
if boss in ["Agahnim", "Agahnim2", "Ganon"]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def place_bosses(world):
|
||||
if world.boss_shuffle == 'none':
|
||||
return
|
||||
# Most to least restrictive order
|
||||
boss_locations = [
|
||||
['Ganons Tower', 'top'],
|
||||
['Tower of Hera', None],
|
||||
['Skull Woods', None],
|
||||
['Ganons Tower', 'middle'],
|
||||
['Eastern Palace', None],
|
||||
['Desert Palace', None],
|
||||
['Palace of Darkness', None],
|
||||
['Swamp Palace', None],
|
||||
['Thieves Town', None],
|
||||
['Ice Palace', None],
|
||||
['Misery Mire', None],
|
||||
['Turtle Rock', None],
|
||||
['Ganons Tower', 'bottom'],
|
||||
]
|
||||
all_bosses = sorted(boss_table.keys()) #s orted to be deterministic on older pythons
|
||||
placeable_bosses = [boss for boss in all_bosses if boss not in ['Agahnim', 'Agahnim2', 'Ganon']]
|
||||
|
||||
if world.boss_shuffle in ["basic", "normal"]:
|
||||
# temporary hack for swordless kholdstare:
|
||||
if world.mode == 'swordless':
|
||||
world.get_dungeon('Ice Palace').boss = BossFactory('Kholdstare')
|
||||
logging.getLogger('').debug('Placing boss Kholdstare at Ice Palace')
|
||||
boss_locations.remove(['Ice Palace', None])
|
||||
placeable_bosses.remove('Kholdstare')
|
||||
|
||||
if world.boss_shuffle == "basic": # vanilla bosses shuffled
|
||||
bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm']
|
||||
else: # all bosses present, the three duplicates chosen at random
|
||||
bosses = all_bosses + [random.choice(placeable_bosses) for _ in range(3)]
|
||||
|
||||
logging.getLogger('').debug('Bosses chosen %s', bosses)
|
||||
|
||||
random.shuffle(bosses)
|
||||
for [loc, level] in boss_locations:
|
||||
loc_text = loc + (' ('+level+')' if level else '')
|
||||
boss = next((b for b in bosses if can_place_boss(world, b, loc, level)), None)
|
||||
if not boss:
|
||||
raise FillError('Could not place boss for location %s' % loc_text)
|
||||
bosses.remove(boss)
|
||||
|
||||
logging.getLogger('').debug('Placing boss %s at %s', boss, loc_text)
|
||||
world.get_dungeon(loc).bosses[level] = BossFactory(boss)
|
||||
elif world.boss_shuffle == "chaos": #all bosses chosen at random
|
||||
for [loc, level] in boss_locations:
|
||||
loc_text = loc + (' ('+level+')' if level else '')
|
||||
try:
|
||||
boss = random.choice([b for b in placeable_bosses if can_place_boss(world, b, loc, level)])
|
||||
except IndexError:
|
||||
raise FillError('Could not place boss for location %s' % loc_text)
|
||||
|
||||
logging.getLogger('').debug('Placing boss %s at %s', boss, loc_text)
|
||||
world.get_dungeon(loc).bosses[level] = BossFactory(boss)
|
35
Dungeons.py
35
Dungeons.py
|
@ -1,34 +1,39 @@
|
|||
import random
|
||||
|
||||
from BaseClasses import Dungeon
|
||||
from Bosses import BossFactory
|
||||
from Fill import fill_restrictive
|
||||
from Items import ItemFactory
|
||||
|
||||
|
||||
def create_dungeons(world):
|
||||
def make_dungeon(name, dungeon_regions, big_key, small_keys, dungeon_items):
|
||||
def make_dungeon(name, default_boss, dungeon_regions, big_key, small_keys, dungeon_items):
|
||||
dungeon = Dungeon(name, dungeon_regions, big_key, [] if world.retro else small_keys, dungeon_items)
|
||||
dungeon.boss = BossFactory(default_boss)
|
||||
for region in dungeon.regions:
|
||||
world.get_region(region).dungeon = dungeon
|
||||
return dungeon
|
||||
|
||||
ES = make_dungeon('Hyrule Castle', ['Hyrule Castle', 'Sewers', 'Sewer Drop', 'Sewers (Dark)', 'Sanctuary'], None, [ItemFactory('Small Key (Escape)')], [ItemFactory('Map (Escape)')])
|
||||
EP = make_dungeon('Eastern Palace', ['Eastern Palace'], ItemFactory('Big Key (Eastern Palace)'), [], ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)']))
|
||||
DP = make_dungeon('Desert Palace', ['Desert Palace North', 'Desert Palace Main (Inner)', 'Desert Palace Main (Outer)', 'Desert Palace East'], ItemFactory('Big Key (Desert Palace)'), [ItemFactory('Small Key (Desert Palace)')], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)']))
|
||||
ToH = make_dungeon('Tower of Hera', ['Tower of Hera (Bottom)', 'Tower of Hera (Basement)', 'Tower of Hera (Top)'], ItemFactory('Big Key (Tower of Hera)'), [ItemFactory('Small Key (Tower of Hera)')], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)']))
|
||||
AT = make_dungeon('Agahnims Tower', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2), [])
|
||||
PoD = make_dungeon('Palace of Darkness', ['Palace of Darkness (Entrance)', 'Palace of Darkness (Center)', 'Palace of Darkness (Big Key Chest)', 'Palace of Darkness (Bonk Section)', 'Palace of Darkness (North)', 'Palace of Darkness (Maze)', 'Palace of Darkness (Harmless Hellway)', 'Palace of Darkness (Final Section)'], ItemFactory('Big Key (Palace of Darkness)'), ItemFactory(['Small Key (Palace of Darkness)'] * 6), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)']))
|
||||
TT = make_dungeon('Thieves Town', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], ItemFactory('Big Key (Thieves Town)'), [ItemFactory('Small Key (Thieves Town)')], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)']))
|
||||
SW = make_dungeon('Skull Woods', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', 'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', 'Skull Woods Final Section (Mothula)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], ItemFactory('Big Key (Skull Woods)'), ItemFactory(['Small Key (Skull Woods)'] * 2), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)']))
|
||||
SP = make_dungeon('Swamp Palace', ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], ItemFactory('Big Key (Swamp Palace)'), [ItemFactory('Small Key (Swamp Palace)')], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)']))
|
||||
IP = make_dungeon('Ice Palace', ['Ice Palace (Entrance)', 'Ice Palace (Main)', 'Ice Palace (East)', 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)'), ItemFactory(['Small Key (Ice Palace)'] * 2), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)']))
|
||||
MM = make_dungeon('Misery Mire', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)'), ItemFactory(['Small Key (Misery Mire)'] * 3), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)']))
|
||||
TR = make_dungeon('Turtle Rock', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller 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 = make_dungeon('Ganons Tower', ['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)']))
|
||||
ES = make_dungeon('Hyrule Castle', None, ['Hyrule Castle', 'Sewers', 'Sewer Drop', 'Sewers (Dark)', 'Sanctuary'], None, [ItemFactory('Small Key (Escape)')], [ItemFactory('Map (Escape)')])
|
||||
EP = make_dungeon('Eastern Palace', 'Armos Knights', ['Eastern Palace'], ItemFactory('Big Key (Eastern Palace)'), [], ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)']))
|
||||
DP = make_dungeon('Desert Palace', 'Lanmolas', ['Desert Palace North', 'Desert Palace Main (Inner)', 'Desert Palace Main (Outer)', 'Desert Palace East'], ItemFactory('Big Key (Desert Palace)'), [ItemFactory('Small Key (Desert Palace)')], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)']))
|
||||
ToH = make_dungeon('Tower of Hera', 'Moldorm', ['Tower of Hera (Bottom)', 'Tower of Hera (Basement)', 'Tower of Hera (Top)'], ItemFactory('Big Key (Tower of Hera)'), [ItemFactory('Small Key (Tower of Hera)')], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)']))
|
||||
AT = make_dungeon('Agahnims Tower', 'Agahnim', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2), [])
|
||||
PoD = make_dungeon('Palace of Darkness', 'Helmasaur King', ['Palace of Darkness (Entrance)', 'Palace of Darkness (Center)', 'Palace of Darkness (Big Key Chest)', 'Palace of Darkness (Bonk Section)', 'Palace of Darkness (North)', 'Palace of Darkness (Maze)', 'Palace of Darkness (Harmless Hellway)', 'Palace of Darkness (Final Section)'], ItemFactory('Big Key (Palace of Darkness)'), ItemFactory(['Small Key (Palace of Darkness)'] * 6), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)']))
|
||||
TT = make_dungeon('Thieves Town', 'Blind', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], ItemFactory('Big Key (Thieves Town)'), [ItemFactory('Small Key (Thieves Town)')], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)']))
|
||||
SW = make_dungeon('Skull Woods', 'Mothula', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', 'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', 'Skull Woods Final Section (Mothula)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], ItemFactory('Big Key (Skull Woods)'), ItemFactory(['Small Key (Skull Woods)'] * 2), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)']))
|
||||
SP = make_dungeon('Swamp Palace', 'Arrghus', ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], ItemFactory('Big Key (Swamp Palace)'), [ItemFactory('Small Key (Swamp Palace)')], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)']))
|
||||
IP = make_dungeon('Ice Palace', 'Kholdstare', ['Ice Palace (Entrance)', 'Ice Palace (Main)', 'Ice Palace (East)', 'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)'), ItemFactory(['Small Key (Ice Palace)'] * 2), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)']))
|
||||
MM = make_dungeon('Misery Mire', 'Vitreous', ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', 'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)'), ItemFactory(['Small Key (Misery Mire)'] * 3), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)']))
|
||||
TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller 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 = make_dungeon('Ganons Tower', 'Agahnim2', ['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)']))
|
||||
|
||||
GT.bosses['bottom'] = BossFactory('Armos Knights')
|
||||
GT.bosses['middle'] = BossFactory('Lanmolas')
|
||||
GT.bosses['top'] = BossFactory('Moldorm')
|
||||
|
||||
world.dungeons = [ES, EP, DP, ToH, AT, PoD, TT, SW, SP, IP, MM, TR, GT]
|
||||
|
||||
|
||||
def fill_dungeons(world):
|
||||
freebes = ['Ganons Tower - Map Chest', 'Palace of Darkness - Harmless Hellway', 'Palace of Darkness - Big Key Chest', 'Turtle Rock - Big Key Chest']
|
||||
|
||||
|
|
|
@ -204,6 +204,8 @@ def start():
|
|||
''')
|
||||
parser.add_argument('--suppress_rom', help='Do not create an output rom file.', action='store_true')
|
||||
parser.add_argument('--gui', help='Launch the GUI', action='store_true')
|
||||
# Deliberately not documented, only useful for vt site integration right now:
|
||||
parser.add_argument('--shufflebosses', help=argparse.SUPPRESS, default='none', const='none', nargs='?', choices=['none', 'basic', 'normal', 'chaos'])
|
||||
parser.add_argument('--jsonout', action='store_true', help='''\
|
||||
Output .json patch to stdout instead of a patched rom. Used
|
||||
for VT site integration, do not use otherwise.
|
||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
|||
import random
|
||||
|
||||
from BaseClasses import Region, RegionType, Shop, ShopType, Location
|
||||
from Bosses import place_bosses
|
||||
from Dungeons import get_dungeon_item_pool
|
||||
from EntranceShuffle import connect_entrance
|
||||
from Fill import FillError, fill_restrictive
|
||||
|
@ -265,6 +266,7 @@ def generate_itempool(world):
|
|||
tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)]
|
||||
world.required_medallions = (mm_medallion, tr_medallion)
|
||||
|
||||
place_bosses(world)
|
||||
set_up_shops(world)
|
||||
|
||||
if world.retro:
|
||||
|
|
4
Items.py
4
Items.py
|
@ -84,8 +84,8 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
|
|||
'Blue Mail': (False, True, None, 0x22, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again'),
|
||||
'Red Mail': (False, True, None, 0x23, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again'),
|
||||
'Progressive Armor': (False, True, None, 0x60, 'time for a\nchange of\nclothes?', 'and the unknown hat', 'the protected kid', 'new hat for sale', 'the clothing store', 'tailor boy has threads again'),
|
||||
'Blue Boomerang': (False, True, None, 0x0C, 'No matter what\nyou do, blue\nreturns to you', 'and the bluemarang', 'the bat-throwing kid', 'bent stick for sale', 'fungus for puma-stick', 'throwing boy plays fetch again'),
|
||||
'Red Boomerang': (False, True, None, 0x2A, 'No matter what\nyou do, red\nreturns to you', 'and the badmarang', 'the bat-throwing kid', 'air foil for sale', 'fungus for return-stick', 'magical boy plays fetch again'),
|
||||
'Blue Boomerang': (True, True, None, 0x0C, 'No matter what\nyou do, blue\nreturns to you', 'and the bluemarang', 'the bat-throwing kid', 'bent stick for sale', 'fungus for puma-stick', 'throwing boy plays fetch again'),
|
||||
'Red Boomerang': (True, True, None, 0x2A, 'No matter what\nyou do, red\nreturns to you', 'and the badmarang', 'the bat-throwing kid', 'air foil for sale', 'fungus for return-stick', 'magical boy plays fetch again'),
|
||||
'Blue Shield': (False, True, None, 0x04, 'Now you can\ndefend against\npebbles!', 'and the stone blocker', 'shield-wielding kid', 'shield for sale', 'fungus for shield', 'shield boy defends again'),
|
||||
'Red Shield': (False, True, None, 0x05, 'Now you can\ndefend against\nfireballs!', 'and the shot blocker', 'shield-wielding kid', 'fire shield for sale', 'fungus for fire shield', 'shield boy defends again'),
|
||||
'Mirror Shield': (True, False, None, 0x06, 'Now you can\ndefend against\nlasers!', 'and the laser blocker', 'shield-wielding kid', 'face shield for sale', 'fungus for face shield', 'shield boy defends again'),
|
||||
|
|
9
Main.py
9
Main.py
|
@ -40,7 +40,7 @@ def main(args, seed=None):
|
|||
start = time.clock()
|
||||
|
||||
# initialize the world
|
||||
world = World(args.shuffle, args.logic, args.mode, args.difficulty, args.timer, args.progressive, args.goal, args.algorithm, not args.nodungeonitems, args.beatableonly, args.shuffleganon, args.quickswap, args.fastmenu, args.disablemusic, args.keysanity, args.retro, args.custom, args.customitemarray)
|
||||
world = World(args.shuffle, args.logic, args.mode, args.difficulty, args.timer, args.progressive, args.goal, args.algorithm, not args.nodungeonitems, args.beatableonly, args.shuffleganon, args.quickswap, args.fastmenu, args.disablemusic, args.keysanity, args.retro, args.custom, args.customitemarray, args.shufflebosses)
|
||||
logger = logging.getLogger('')
|
||||
if seed is None:
|
||||
random.seed(None)
|
||||
|
@ -140,7 +140,7 @@ def gt_filler(world):
|
|||
|
||||
def copy_world(world):
|
||||
# ToDo: Not good yet
|
||||
ret = World(world.shuffle, world.logic, world.mode, world.difficulty, world.timer, world.progressive, world.goal, world.algorithm, world.place_dungeon_items, world.check_beatable_only, world.shuffle_ganon, world.quickswap, world.fastmenu, world.disable_music, world.keysanity, world.retro, world.custom, world.customitemarray)
|
||||
ret = World(world.shuffle, world.logic, world.mode, world.difficulty, world.timer, world.progressive, world.goal, world.algorithm, world.place_dungeon_items, world.check_beatable_only, world.shuffle_ganon, world.quickswap, world.fastmenu, world.disable_music, world.keysanity, world.retro, world.custom, world.customitemarray, world.boss_shuffle)
|
||||
ret.required_medallions = list(world.required_medallions)
|
||||
ret.swamp_patch_required = world.swamp_patch_required
|
||||
ret.ganon_at_pyramid = world.ganon_at_pyramid
|
||||
|
@ -160,6 +160,11 @@ def copy_world(world):
|
|||
|
||||
copy_dynamic_regions_and_locations(world, ret)
|
||||
|
||||
# copy bosses
|
||||
for dungeon in world.dungeons:
|
||||
for level, boss in dungeon.bosses.items():
|
||||
ret.get_dungeon(dungeon.name).bosses[level] = boss
|
||||
|
||||
for shop in world.shops:
|
||||
copied_shop = ret.get_region(shop.region.name).shop
|
||||
copied_shop.active = shop.active
|
||||
|
|
61
Rules.py
61
Rules.py
|
@ -49,6 +49,10 @@ def set_rules(world):
|
|||
def set_rule(spot, rule):
|
||||
spot.access_rule = rule
|
||||
|
||||
def set_defeat_dungeon_boss_rule(location):
|
||||
# Lambda required to defer evaluation of dungeon.boss since it will change later if boos shuffle is used
|
||||
set_rule(location, lambda state: location.parent_region.dungeon.boss.can_defeat(state))
|
||||
|
||||
def set_always_allow(spot, rule):
|
||||
spot.always_allow = rule
|
||||
|
||||
|
@ -138,6 +142,7 @@ def global_rules(world):
|
|||
set_rule(world.get_location('Sahasrahla'), lambda state: state.has('Green Pendant'))
|
||||
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has_beam_sword() or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
|
||||
set_rule(world.get_entrance('Agahnim 1'), lambda state: state.has_sword() and state.has_key('Small Key (Agahnims Tower)', 2))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Agahnim 1'))
|
||||
set_rule(world.get_location('Castle Tower - Dark Maze'), lambda state: state.has_key('Small Key (Agahnims Tower)'))
|
||||
set_rule(world.get_entrance('Top of Pyramid'), lambda state: state.has('Beat Agahnim 1'))
|
||||
set_rule(world.get_entrance('Old Man Cave Exit (West)'), lambda state: False) # drop cannot be climbed up
|
||||
|
@ -228,18 +233,16 @@ def global_rules(world):
|
|||
set_rule(world.get_entrance('Sewers Back Door'), lambda state: state.has_key('Small Key (Escape)'))
|
||||
|
||||
set_rule(world.get_location('Eastern Palace - Big Chest'), lambda state: state.has('Big Key (Eastern Palace)'))
|
||||
set_rule(world.get_location('Eastern Palace - Armos Knights'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)'))
|
||||
set_rule(world.get_location('Eastern Palace - Prize'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)'))
|
||||
set_rule(world.get_location('Eastern Palace - Armos Knights'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)') and world.get_location('Eastern Palace - Armos Knights').parent_region.dungeon.boss.can_defeat(state))
|
||||
set_rule(world.get_location('Eastern Palace - Prize'), lambda state: state.can_shoot_arrows() and state.has('Big Key (Eastern Palace)') and world.get_location('Eastern Palace - Prize').parent_region.dungeon.boss.can_defeat(state))
|
||||
for location in ['Eastern Palace - Armos Knights', 'Eastern Palace - Big Chest']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Eastern Palace)')
|
||||
|
||||
set_rule(world.get_location('Desert Palace - Big Chest'), lambda state: state.has('Big Key (Desert Palace)'))
|
||||
set_rule(world.get_location('Desert Palace - Torch'), lambda state: state.has_Boots())
|
||||
set_rule(world.get_entrance('Desert Palace East Wing'), lambda state: state.has_key('Small Key (Desert Palace)'))
|
||||
set_rule(world.get_location('Desert Palace - Prize'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and
|
||||
(state.has_blunt_weapon() or state.has('Fire Rod') or state.has('Ice Rod') or state.can_shoot_arrows()))
|
||||
set_rule(world.get_location('Desert Palace - Lanmolas'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and
|
||||
(state.has_blunt_weapon() or state.has('Fire Rod') or state.has('Ice Rod') or state.can_shoot_arrows()))
|
||||
set_rule(world.get_location('Desert Palace - Prize'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and world.get_location('Desert Palace - Prize').parent_region.dungeon.boss.can_defeat(state))
|
||||
set_rule(world.get_location('Desert Palace - Lanmolas'), lambda state: state.has_key('Small Key (Desert Palace)') and state.has('Big Key (Desert Palace)') and state.has_fire_source() and world.get_location('Desert Palace - Lanmolas').parent_region.dungeon.boss.can_defeat(state))
|
||||
for location in ['Desert Palace - Lanmolas', 'Desert Palace - Big Chest']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Desert Palace)')
|
||||
|
||||
|
@ -251,8 +254,8 @@ def global_rules(world):
|
|||
set_rule(world.get_location('Tower of Hera - Big Chest'), lambda state: state.has('Big Key (Tower of Hera)'))
|
||||
set_rule(world.get_location('Tower of Hera - Big Key Chest'), lambda state: state.has_fire_source())
|
||||
set_always_allow(world.get_location('Tower of Hera - Big Key Chest'), lambda state, item: item.name == 'Small Key (Tower of Hera)')
|
||||
set_rule(world.get_location('Tower of Hera - Moldorm'), lambda state: state.has_blunt_weapon())
|
||||
set_rule(world.get_location('Tower of Hera - Prize'), lambda state: state.has_blunt_weapon())
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Moldorm'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Tower of Hera - Prize'))
|
||||
for location in ['Tower of Hera - Moldorm', 'Tower of Hera - Big Chest', 'Tower of Hera - Compass Chest']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Tower of Hera)')
|
||||
# for location in ['Tower of Hera - Big Key Chest']:
|
||||
|
@ -266,13 +269,15 @@ def global_rules(world):
|
|||
set_rule(world.get_location('Swamp Palace - Big Chest'), lambda state: state.has('Big Key (Swamp Palace)') or item_name(state, 'Swamp Palace - Big Chest') == 'Big Key (Swamp Palace)')
|
||||
set_always_allow(world.get_location('Swamp Palace - Big Chest'), lambda state, item: item.name == 'Big Key (Swamp Palace)')
|
||||
set_rule(world.get_entrance('Swamp Palace (North)'), lambda state: state.has('Hookshot'))
|
||||
set_rule(world.get_location('Swamp Palace - Arrghus'), lambda state: state.has_blunt_weapon())
|
||||
set_rule(world.get_location('Swamp Palace - Prize'), lambda state: state.has_blunt_weapon())
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Arrghus'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Swamp Palace - Prize'))
|
||||
for location in ['Swamp Palace - Entrance']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Swamp Palace)')
|
||||
|
||||
set_rule(world.get_entrance('Thieves Town Big Key Door'), lambda state: state.has('Big Key (Thieves Town)'))
|
||||
set_rule(world.get_entrance('Blind Fight'), lambda state: state.has_key('Small Key (Thieves Town)') and (state.has_blunt_weapon() or state.has('Cane of Somaria') or state.has('Cane of Byrna')))
|
||||
set_rule(world.get_entrance('Blind Fight'), lambda state: state.has_key('Small Key (Thieves Town)'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Thieves Town - Blind'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Thieves Town - Prize'))
|
||||
set_rule(world.get_location('Thieves\' Town - Big Chest'), lambda state: (state.has_key('Small Key (Thieves Town)') or item_name(state, 'Thieves\' Town - Big Chest') == 'Small Key (Thieves Town)') and state.has('Hammer'))
|
||||
set_always_allow(world.get_location('Thieves\' Town - Big Chest'), lambda state, item: item.name == 'Small Key (Thieves Town)' and state.has('Hammer'))
|
||||
set_rule(world.get_location('Thieves\' Town - Attic'), lambda state: state.has_key('Small Key (Thieves Town)'))
|
||||
|
@ -288,6 +293,8 @@ def global_rules(world):
|
|||
set_rule(world.get_location('Skull Woods - Big Chest'), lambda state: state.has('Big Key (Skull Woods)') or item_name(state, 'Skull Woods - Big Chest') == 'Big Key (Skull Woods)')
|
||||
set_always_allow(world.get_location('Skull Woods - Big Chest'), lambda state, item: item.name == 'Big Key (Skull Woods)')
|
||||
set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and state.has_sword()) # sword required for curtain
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Mothula'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize'))
|
||||
for location in ['Skull Woods - Mothula']:
|
||||
forbid_item(world.get_location(location), 'Small Key (Skull Woods)')
|
||||
|
||||
|
@ -297,6 +304,8 @@ def global_rules(world):
|
|||
# TODO: investigate change from VT. Changed to hookshot or 2 keys (no checking for big key in specific chests)
|
||||
set_rule(world.get_entrance('Ice Palace (East)'), lambda state: (state.has('Hookshot') or (item_in_locations(state, 'Big Key (Ice Palace)', ['Ice Palace - Spike Room', 'Ice Palace - Big Key Chest', 'Ice Palace - Map Chest']) and state.has_key('Small Key (Ice Palace)'))) and (state.world.can_take_damage or state.has('Hookshot') or state.has('Cape') or state.has('Cane of Byrna')))
|
||||
set_rule(world.get_entrance('Ice Palace (East Top)'), lambda state: state.can_lift_rocks() and state.has('Hammer'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Kholdstare'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Ice Palace - Prize'))
|
||||
for location in ['Ice Palace - Big Chest', 'Ice Palace - Kholdstare']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Ice Palace)')
|
||||
|
||||
|
@ -314,7 +323,9 @@ def global_rules(world):
|
|||
(item_name(state, 'Misery Mire - Big Key Chest') in ['Big Key (Misery Mire)'])) else state.has_key('Small Key (Misery Mire)', 3))
|
||||
set_rule(world.get_location('Misery Mire - Compass Chest'), lambda state: state.has_fire_source())
|
||||
set_rule(world.get_location('Misery Mire - Big Key Chest'), lambda state: state.has_fire_source())
|
||||
set_rule(world.get_entrance('Misery Mire (Vitreous)'), lambda state: state.has('Cane of Somaria') and (state.can_shoot_arrows() or state.has_blunt_weapon()))
|
||||
set_rule(world.get_entrance('Misery Mire (Vitreous)'), lambda state: state.has('Cane of Somaria'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Misery Mire - Vitreous'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Misery Mire - Prize'))
|
||||
for location in ['Misery Mire - Big Chest', 'Misery Mire - Vitreous']:
|
||||
forbid_item(world.get_location(location), 'Big Key (Misery Mire)')
|
||||
|
||||
|
@ -333,8 +344,9 @@ def global_rules(world):
|
|||
set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Right'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
||||
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Left'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
||||
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Right'), lambda state: state.has('Cane of Byrna') or state.has('Cape') or state.has('Mirror Shield'))
|
||||
set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has_key('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_sword() and state.can_extend_magic(32))))
|
||||
set_rule(world.get_entrance('Turtle Rock (Trinexx)'), lambda state: state.has_key('Small Key (Turtle Rock)', 4) and state.has('Big Key (Turtle Rock)') and state.has('Cane of Somaria'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Trinexx'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Prize'))
|
||||
|
||||
set_trock_key_rules(world)
|
||||
|
||||
|
@ -351,6 +363,8 @@ def global_rules(world):
|
|||
set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door'), lambda state: state.has_key('Small Key (Palace of Darkness)', 6) or (item_name(state, 'Palace of Darkness - Harmless Hellway') in ['Small Key (Palace of Darkness)'] and state.has_key('Small Key (Palace of Darkness)', 4)))
|
||||
set_always_allow(world.get_location('Palace of Darkness - Harmless Hellway'), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and state.has_key('Small Key (Palace of Darkness)', 5))
|
||||
set_rule(world.get_entrance('Palace of Darkness Maze Door'), lambda state: state.has_key('Small Key (Palace of Darkness)', 6))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Helmasaur'))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Prize'))
|
||||
|
||||
# these key rules are conservative, you might be able to get away with more lenient rules
|
||||
randomizer_room_chests = ['Ganons Tower - Randomizer Room - Top Left', 'Ganons Tower - Randomizer Room - Top Right', 'Ganons Tower - Randomizer Room - Bottom Left', 'Ganons Tower - Randomizer Room - Bottom Right']
|
||||
|
@ -381,15 +395,17 @@ def global_rules(world):
|
|||
set_rule(world.get_location(location), lambda state: state.has('Fire Rod') and (state.has_key('Small Key (Ganons Tower)', 4) or (item_in_locations(state, 'Big Key (Ganons Tower)', compass_room_chests) and state.has_key('Small Key (Ganons Tower)', 3))))
|
||||
|
||||
set_rule(world.get_location('Ganons Tower - Big Chest'), lambda state: state.has('Big Key (Ganons Tower)'))
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Room - Left'), lambda state: state.can_shoot_arrows() or state.has_blunt_weapon())
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Chest'), lambda state: state.can_shoot_arrows() or state.has_blunt_weapon())
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Room - Right'), lambda state: state.can_shoot_arrows() or state.has_blunt_weapon())
|
||||
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Room - Left'), lambda state: world.get_location('Ganons Tower - Big Key Room - Left').parent_region.dungeon.bosses['bottom'].can_defeat(state))
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Chest'), lambda state: world.get_location('Ganons Tower - Big Key Chest').parent_region.dungeon.bosses['bottom'].can_defeat(state))
|
||||
set_rule(world.get_location('Ganons Tower - Big Key Room - Right'), lambda state: world.get_location('Ganons Tower - Big Key Room - Right').parent_region.dungeon.bosses['bottom'].can_defeat(state))
|
||||
|
||||
set_rule(world.get_entrance('Ganons Tower Big Key Door'), lambda state: state.has('Big Key (Ganons Tower)') and state.can_shoot_arrows())
|
||||
set_rule(world.get_entrance('Ganons Tower Torch Rooms'), lambda state: state.has_fire_source())
|
||||
set_rule(world.get_entrance('Ganons Tower Torch Rooms'), lambda state: state.has_fire_source() and world.get_entrance('Ganons Tower Torch Rooms').parent_region.dungeon.bosses['middle'].can_defeat(state))
|
||||
set_rule(world.get_location('Ganons Tower - Pre-Moldorm Chest'), lambda state: state.has_key('Small Key (Ganons Tower)', 3))
|
||||
set_rule(world.get_entrance('Ganons Tower Moldorm Door'), lambda state: state.has_key('Small Key (Ganons Tower)', 4))
|
||||
set_rule(world.get_entrance('Ganons Tower Moldorm Gap'), lambda state: state.has('Hookshot') and state.has_blunt_weapon())
|
||||
set_rule(world.get_location('Agahnim 2'), lambda state: state.has_sword() or state.has('Hammer') or state.has('Bug Catching Net'))
|
||||
set_rule(world.get_entrance('Ganons Tower Moldorm Gap'), lambda state: state.has('Hookshot') and world.get_entrance('Ganons Tower Moldorm Gap').parent_region.dungeon.bosses['top'].can_defeat(state))
|
||||
set_defeat_dungeon_boss_rule(world.get_location('Agahnim 2'))
|
||||
set_rule(world.get_entrance('Pyramid Hole'), lambda state: state.has('Beat Agahnim 2'))
|
||||
for location in ['Ganons Tower - Big Chest', 'Ganons Tower - Mini Helmasaur Room - Left', 'Ganons Tower - Mini Helmasaur Room - Right',
|
||||
'Ganons Tower - Pre-Moldorm Chest', 'Ganons Tower - Validation Chest']:
|
||||
|
@ -474,14 +490,13 @@ def swordless_rules(world):
|
|||
open_rules(world)
|
||||
|
||||
set_rule(world.get_entrance('Agahnims Tower'), lambda state: state.has('Cape') or state.has('Hammer') or state.has('Beat Agahnim 1')) # barrier gets removed after killing agahnim, relevant for entrance shuffle
|
||||
set_rule(world.get_entrance('Agahnim 1'), lambda state: (state.has('Hammer') or (state.has('Bug Catching Net') and (state.has('Fire Rod') or state.can_shoot_arrows() or state.has('Cane of Somaria')))) and state.has_key('Small Key (Agahnims Tower)', 2))
|
||||
set_rule(world.get_entrance('Agahnim 1'), lambda state: (state.has('Hammer') or state.has('Fire Rod') or state.can_shoot_arrows() or state.has('Cane of Somaria')) and state.has_key('Small Key (Agahnims Tower)', 2))
|
||||
set_rule(world.get_location('Ether Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer'))
|
||||
set_rule(world.get_location('Bombos Tablet'), lambda state: state.has('Book of Mudora') and state.has('Hammer') and state.has_Mirror())
|
||||
set_rule(world.get_entrance('Misery Mire'), lambda state: state.has_Pearl() and state.has_misery_mire_medallion()) # sword not required to use medallion for opening in swordless (!)
|
||||
set_rule(world.get_entrance('Turtle Rock'), lambda state: state.has_Pearl() and state.has_turtle_rock_medallion() and state.can_reach('Turtle Rock (Top)', 'Region')) # sword not required to use medallion for opening in swordless (!)
|
||||
set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod') and (state.has('Hammer') or state.can_extend_magic(10))) # no curtain
|
||||
set_rule(world.get_entrance('Skull Woods Torch Room'), lambda state: state.has_key('Small Key (Skull Woods)', 3) and state.has('Fire Rod')) # no curtain
|
||||
set_rule(world.get_entrance('Ice Palace Entrance Room'), lambda state: state.has('Fire Rod') or state.has('Bombos')) #in swordless mode bombos pads are present in the relevant parts of ice palace
|
||||
set_rule(world.get_location('Agahnim 2'), lambda state: state.has('Hammer') or state.has('Bug Catching Net'))
|
||||
set_rule(world.get_location('Ganon'), lambda state: state.has('Hammer') and state.has_fire_source() and state.has('Silver Arrows') and state.can_shoot_arrows() and state.has('Crystal 1') and state.has('Crystal 2')
|
||||
and state.has('Crystal 3') and state.has('Crystal 4') and state.has('Crystal 5') and state.has('Crystal 6') and state.has('Crystal 7'))
|
||||
set_rule(world.get_entrance('Ganon Drop'), lambda state: state.has('Hammer')) # need to damage ganon to get tiles to drop
|
||||
|
|
Loading…
Reference in New Issue