314 lines
18 KiB
Python
314 lines
18 KiB
Python
import random
|
|
|
|
from BaseClasses import Dungeon
|
|
from Bosses import BossFactory
|
|
from Fill import fill_restrictive
|
|
from Items import ItemFactory
|
|
|
|
|
|
def create_dungeons(world, player):
|
|
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, player)
|
|
dungeon.boss = BossFactory(default_boss, player)
|
|
for region in dungeon.regions:
|
|
world.get_region(region, player).dungeon = dungeon
|
|
dungeon.world = world
|
|
return dungeon
|
|
|
|
ES = make_dungeon('Hyrule Castle', None, hyrule_castle_regions, None, [ItemFactory('Small Key (Escape)', player)], [ItemFactory('Map (Escape)', player)])
|
|
EP = make_dungeon('Eastern Palace', 'Armos Knights', eastern_regions, ItemFactory('Big Key (Eastern Palace)', player), [], ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)'], player))
|
|
DP = make_dungeon('Desert Palace', 'Lanmolas', desert_regions, ItemFactory('Big Key (Desert Palace)', player), [ItemFactory('Small Key (Desert Palace)', player)], ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)'], player))
|
|
ToH = make_dungeon('Tower of Hera', 'Moldorm', hera_regions, ItemFactory('Big Key (Tower of Hera)', player), [ItemFactory('Small Key (Tower of Hera)', player)], ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)'], player))
|
|
PoD = make_dungeon('Palace of Darkness', 'Helmasaur King', pod_regions, ItemFactory('Big Key (Palace of Darkness)', player), ItemFactory(['Small Key (Palace of Darkness)'] * 6, player), ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)'], player))
|
|
TT = make_dungeon('Thieves Town', 'Blind', thieves_regions, ItemFactory('Big Key (Thieves Town)', player), [ItemFactory('Small Key (Thieves Town)', player)], ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)'], player))
|
|
SW = make_dungeon('Skull Woods', 'Mothula', skull_regions, ItemFactory('Big Key (Skull Woods)', player), ItemFactory(['Small Key (Skull Woods)'] * 2, player), ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)'], player))
|
|
SP = make_dungeon('Swamp Palace', 'Arrghus', swamp_regions, ItemFactory('Big Key (Swamp Palace)', player), [ItemFactory('Small Key (Swamp Palace)', player)], ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'], player))
|
|
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)', player), ItemFactory(['Small Key (Ice Palace)'] * 2, player), ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)'], player))
|
|
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)', player), ItemFactory(['Small Key (Misery Mire)'] * 3, player), ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player))
|
|
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)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player))
|
|
|
|
if world.mode != 'inverted':
|
|
AT = make_dungeon('Agahnims Tower', 'Agahnim', tower_regions, None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), [])
|
|
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)', player), ItemFactory(['Small Key (Ganons Tower)'] * 4, player), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player))
|
|
else:
|
|
AT = make_dungeon('Inverted Agahnims Tower', 'Agahnim', ['Inverted Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), [])
|
|
GT = make_dungeon('Inverted Ganons Tower', 'Agahnim2', ['Inverted 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)', player), ItemFactory(['Small Key (Ganons Tower)'] * 4, player), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player))
|
|
|
|
GT.bosses['bottom'] = BossFactory('Armos Knights', player)
|
|
GT.bosses['middle'] = BossFactory('Lanmolas', player)
|
|
GT.bosses['top'] = BossFactory('Moldorm', player)
|
|
|
|
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']
|
|
|
|
all_state_base = world.get_all_state()
|
|
|
|
for player in range(1, world.players + 1):
|
|
pinball_room = world.get_location('Skull Woods - Pinball Room', player)
|
|
if world.retro:
|
|
world.push_item(pinball_room, ItemFactory('Small Key (Universal)', player), False)
|
|
else:
|
|
world.push_item(pinball_room, ItemFactory('Small Key (Skull Woods)', player), False)
|
|
pinball_room.event = True
|
|
pinball_room.locked = True
|
|
|
|
dungeons = [(list(dungeon.regions), dungeon.big_key, list(dungeon.small_keys), list(dungeon.dungeon_items)) for dungeon in world.dungeons]
|
|
|
|
loopcnt = 0
|
|
while dungeons:
|
|
loopcnt += 1
|
|
dungeon_regions, big_key, small_keys, dungeon_items = dungeons.pop(0)
|
|
# this is what we need to fill
|
|
dungeon_locations = [location for location in world.get_unfilled_locations() if location.parent_region.name in dungeon_regions]
|
|
random.shuffle(dungeon_locations)
|
|
|
|
all_state = all_state_base.copy()
|
|
|
|
# first place big key
|
|
if big_key is not None:
|
|
bk_location = None
|
|
for location in dungeon_locations:
|
|
if location.item_rule(big_key):
|
|
bk_location = location
|
|
break
|
|
|
|
if bk_location is None:
|
|
raise RuntimeError('No suitable location for %s' % big_key)
|
|
|
|
world.push_item(bk_location, big_key, False)
|
|
bk_location.event = True
|
|
bk_location.locked = True
|
|
dungeon_locations.remove(bk_location)
|
|
big_key = None
|
|
|
|
# next place small keys
|
|
while small_keys:
|
|
small_key = small_keys.pop()
|
|
all_state.sweep_for_events()
|
|
sk_location = None
|
|
for location in dungeon_locations:
|
|
if location.name in freebes or (location.can_reach(all_state) and location.item_rule(small_key)):
|
|
sk_location = location
|
|
break
|
|
|
|
if sk_location is None:
|
|
# need to retry this later
|
|
small_keys.append(small_key)
|
|
dungeons.append((dungeon_regions, big_key, small_keys, dungeon_items))
|
|
# infinite regression protection
|
|
if loopcnt < (30 * world.players):
|
|
break
|
|
else:
|
|
raise RuntimeError('No suitable location for %s' % small_key)
|
|
|
|
world.push_item(sk_location, small_key, False)
|
|
sk_location.event = True
|
|
sk_location.locked = True
|
|
dungeon_locations.remove(sk_location)
|
|
|
|
if small_keys:
|
|
# key placement not finished, loop again
|
|
continue
|
|
|
|
# next place dungeon items
|
|
if world.place_dungeon_items:
|
|
for dungeon_item in dungeon_items:
|
|
di_location = dungeon_locations.pop()
|
|
world.push_item(di_location, dungeon_item, False)
|
|
|
|
|
|
def get_dungeon_item_pool(world):
|
|
return [item for dungeon in world.dungeons for item in dungeon.all_items if item.key or world.place_dungeon_items]
|
|
|
|
def fill_dungeons_restrictive(world, shuffled_locations):
|
|
all_state_base = world.get_all_state()
|
|
|
|
for player in range(1, world.players + 1):
|
|
pinball_room = world.get_location('Skull Woods - Pinball Room', player)
|
|
if world.retro:
|
|
world.push_item(pinball_room, ItemFactory('Small Key (Universal)', player), False)
|
|
else:
|
|
world.push_item(pinball_room, ItemFactory('Small Key (Skull Woods)', player), False)
|
|
pinball_room.event = True
|
|
pinball_room.locked = True
|
|
shuffled_locations.remove(pinball_room)
|
|
|
|
if world.keysanity:
|
|
#in keysanity dungeon items are distributed as part of the normal item pool
|
|
for item in world.get_items():
|
|
if item.key:
|
|
item.advancement = True
|
|
elif item.map or item.compass:
|
|
item.priority = True
|
|
return
|
|
|
|
dungeon_items = get_dungeon_item_pool(world)
|
|
|
|
# sort in the order Big Key, Small Key, Other before placing dungeon items
|
|
sort_order = {"BigKey": 3, "SmallKey": 2}
|
|
dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))
|
|
|
|
fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items)
|
|
|
|
|
|
dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A],
|
|
'Desert Palace - Prize': [0x1559B, 0x1559C, 0x1559D, 0x1559E],
|
|
'Tower of Hera - Prize': [0x155C5, 0x1107A, 0x10B8C],
|
|
'Palace of Darkness - Prize': [0x155B8],
|
|
'Swamp Palace - Prize': [0x155B7],
|
|
'Thieves\' Town - Prize': [0x155C6],
|
|
'Skull Woods - Prize': [0x155BA, 0x155BB, 0x155BC, 0x155BD, 0x15608, 0x15609, 0x1560A, 0x1560B],
|
|
'Ice Palace - Prize': [0x155BF],
|
|
'Misery Mire - Prize': [0x155B9],
|
|
'Turtle Rock - Prize': [0x155C7, 0x155A7, 0x155AA, 0x155AB]}
|
|
|
|
hyrule_castle_regions = [
|
|
'Hyrule Castle Lobby', 'Hyrule Castle West Lobby', 'Hyrule Castle East Lobby', 'Hyrule Castle East Hall',
|
|
'Hyrule Castle West Hall', 'Hyrule Castle Back Hall', 'Hyrule Castle Throne Room', 'Hyrule Dungeon Map Room',
|
|
'Hyrule Dungeon North Abyss', 'Hyrule Dungeon North Abyss Catwalk', 'Hyrule Dungeon South Abyss',
|
|
'Hyrule Dungeon South Abyss Catwalk', 'Hyrule Dungeon Guardroom', 'Hyrule Dungeon Armory Main',
|
|
'Hyrule Dungeon Armory North Branch', 'Hyrule Dungeon Staircase', 'Hyrule Dungeon Cellblock',
|
|
'Sewers Behind Tapestry', 'Sewers Rope Room', 'Sewers Dark Cross', 'Sewers Water', 'Sewers Key Rat',
|
|
'Sewers Secret Room Blocked Path', 'Sewers Secret Room', 'Sewers Pull Switch', 'Sanctuary'
|
|
]
|
|
|
|
eastern_regions = [
|
|
'Eastern Lobby', 'Eastern Cannonball', 'Eastern Cannonball Ledge', 'Eastern Courtyard Ledge', 'Eastern Map Area',
|
|
'Eastern Compass Area', 'Eastern Hint Tile Blocked Path', 'Eastern Courtyard', 'Eastern Fairies',
|
|
'Eastern Map Valley', 'Eastern Dark Square', 'Eastern Big Key', 'Eastern Darkness', 'Eastern Attic Start',
|
|
'Eastern Attic Switches', 'Eastern Eyegores', 'Eastern Boss'
|
|
]
|
|
|
|
desert_regions = [
|
|
'Desert Main Lobby', 'Desert Dead End', 'Desert East Lobby', 'Desert East Wing', 'Desert Compass Room',
|
|
'Desert Cannonball', 'Desert Arrow Pot Corner', 'Desert North Hall', 'Desert Map Room', 'Desert Sandworm Corner',
|
|
'Desert Bonk Torch', 'Desert Circle of Pots', 'Desert Big Chest Room', 'Desert West Wing',
|
|
'Desert West Lobby', 'Desert Back Lobby', 'Desert Tiles 1',
|
|
'Desert Bridge', 'Desert Four Statues', 'Desert Beamos Hall', 'Desert Tiles 2', 'Desert Wall Slide', 'Desert Boss',
|
|
]
|
|
|
|
hera_regions = [
|
|
'Hera Lobby', 'Hera Basement Cage', 'Hera Tile Room', 'Hera Tridorm', 'Hera Torches', 'Hera Beetles',
|
|
'Hera Startile Corner', 'Hera Startile Wide', 'Hera 4F', 'Hera Big Chest Landing', 'Hera 5F',
|
|
'Hera Fairies', 'Hera Boss'
|
|
]
|
|
|
|
tower_regions = [
|
|
'Tower Lobby', 'Tower Gold Knights', 'Tower Room 03', 'Tower Lone Statue', 'Tower Dark Maze', 'Tower Dark Chargers',
|
|
'Tower Dual Statues', 'Tower Dark Pits', 'Tower Dark Archers', 'Tower Red Spears', 'Tower Red Guards',
|
|
'Tower Circle of Pots', 'Tower Pacifist Run', 'Tower Push Statue', 'Tower Catwalk', 'Tower Antechamber',
|
|
'Tower Altar', 'Tower Agahnim 1'
|
|
]
|
|
|
|
pod_regions = [
|
|
'PoD Lobby', 'PoD Left Cage', 'PoD Middle Cage', 'PoD Shooter Room', 'PoD Pit Room', 'PoD Arena Main',
|
|
'PoD Arena Crystal', 'PoD Arena Bridge', 'PoD Arena Ledge', 'PoD Sexy Statue', 'PoD Map Balcony', 'PoD Conveyor',
|
|
'PoD Mimics 1', 'PoD Jelly Hall', 'PoD Warp Hint', 'PoD Warp Room', 'PoD Stalfos Basement', 'PoD Basement Ledge',
|
|
'PoD Big Key Landing', 'PoD Falling Bridge', 'PoD Dark Maze', 'PoD Big Chest Balcony', 'PoD Compass Room',
|
|
'PoD Dark Basement', 'PoD Harmless Hellway', 'PoD Mimics 2', 'PoD Bow Statue', 'PoD Dark Pegs', 'PoD Lonely Turtle',
|
|
'PoD Turtle Party', 'PoD Dark Alley', 'PoD Callback', 'PoD Boss'
|
|
]
|
|
|
|
swamp_regions = [
|
|
'Swamp Lobby', 'Swamp Entrance', 'Swamp Pot Row', 'Swamp Map Ledge', 'Swamp Trench 1 Approach',
|
|
'Swamp Trench 1 Nexus', 'Swamp Trench 1 Alcove', 'Swamp Trench 1 Key Ledge', 'Swamp Trench 1 Departure',
|
|
'Swamp Hammer Switch', 'Swamp Hub', 'Swamp Hub Dead Ledge', 'Swamp Hub North Ledge', 'Swamp Donut Top',
|
|
'Swamp Donut Bottom', 'Swamp Compass Donut', 'Swamp Crystal Switch', 'Swamp Shortcut', 'Swamp Trench 2 Pots',
|
|
'Swamp Trench 2 Blocks', 'Swamp Trench 2 Alcove', 'Swamp Trench 2 Departure', 'Swamp Big Key Ledge',
|
|
'Swamp West Shallows', 'Swamp West Block Path', 'Swamp West Ledge', 'Swamp Barrier Ledge', 'Swamp Barrier',
|
|
'Swamp Attic', 'Swamp Push Statue', 'Swamp Shooters', 'Swamp Left Elbow', 'Swamp Right Elbow', 'Swamp Drain Left',
|
|
'Swamp Drain Right', 'Swamp Flooded Room', 'Swamp Flooded Spot', 'Swamp Basement Shallows', 'Swamp Waterfall Room',
|
|
'Swamp Refill', 'Swamp Behind Waterfall', 'Swamp C', 'Swamp Waterway', 'Swamp I', 'Swamp T', 'Swamp Boss'
|
|
]
|
|
|
|
skull_regions = [
|
|
'Skull 1 Lobby', 'Skull Map Room', 'Skull Pot Circle', 'Skull Pull Switch', 'Skull Big Chest', 'Skull Pinball',
|
|
'Skull Pot Prison', 'Skull Compass Room', 'Skull Left Drop', 'Skull 2 East Lobby', 'Skull Big Key',
|
|
'Skull Lone Pot', 'Skull Small Hall', 'Skull Back Drop', 'Skull 2 West Lobby', 'Skull X Room', 'Skull 3 Lobby',
|
|
'Skull East Bridge', 'Skull West Bridge Nook', 'Skull Star Pits', 'Skull Torch Room', 'Skull Vines',
|
|
'Skull Spike Corner', 'Skull Final Drop', 'Skull Boss'
|
|
]
|
|
|
|
thieves_regions = [
|
|
'Thieves Lobby', 'Thieves Ambush', 'Thieves BK Corner', 'Thieves Compass Room', 'Thieves Big Chest Nook',
|
|
'Thieves Hallway', 'Thieves Boss', 'Thieves Pot Alcove Mid', 'Thieves Pot Alcove Bottom', 'Thieves Pot Alcove Top',
|
|
'Thieves Conveyor Maze', 'Thieves Spike Track', 'Thieves Hellway', 'Thieves Hellway N Crystal',
|
|
'Thieves Hellway S Crystal', 'Thieves Triple Bypass', 'Thieves Spike Switch', 'Thieves Attic',
|
|
'Thieves Cricket Hall Left', 'Thieves Cricket Hall Right', 'Thieves Attic Window', 'Thieves Basement Block',
|
|
'Thieves Blocked Entry', 'Thieves Lonely Zazak', 'Thieves Blind\'s Cell', 'Thieves Conveyor Bridge',
|
|
'Thieves Conveyor Block', 'Thieves Big Chest Room', 'Thieves Trap'
|
|
]
|
|
|
|
|
|
dungeon_regions = {
|
|
'Hyrule Castle': hyrule_castle_regions,
|
|
'Eastern Palace': eastern_regions,
|
|
'Desert Palace': desert_regions,
|
|
'Tower of Hera': hera_regions,
|
|
'Agahnims Tower': tower_regions,
|
|
'Palace of Darkness': pod_regions,
|
|
'Swamp Palace': swamp_regions,
|
|
'Skull Woods': skull_regions,
|
|
'Thieves Town': thieves_regions,
|
|
# 'Ice':
|
|
# 'Mire':
|
|
# 'TR':
|
|
# 'GT':
|
|
}
|
|
|
|
region_starts = {
|
|
'Hyrule Castle': ['Hyrule Castle Lobby', 'Hyrule Castle West Lobby', 'Hyrule Castle East Lobby', 'Sewers Secret Room', 'Sanctuary'],
|
|
'Eastern Palace': ['Eastern Lobby'],
|
|
'Desert Palace': ['Desert Back Lobby', 'Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'],
|
|
'Tower of Hera': ['Hera Lobby'],
|
|
'Agahnims Tower': ['Tower Lobby'],
|
|
'Palace of Darkness': ['PoD Lobby'],
|
|
'Swamp Palace': ['Swamp Lobby'],
|
|
'Skull Woods': ['Skull 1 Lobby', 'Skull 2 East Lobby', 'Skull 2 West Lobby', 'Skull 3 Lobby', 'Skull Pot Circle',
|
|
'Skull Pinball', 'Skull Left Drop', 'Skull Back Drop'],
|
|
'Thieves Town': ['Thieves Lobby'],
|
|
# ['Ice Lobby'],
|
|
# ['Mire Lobby'],
|
|
# ['TR Main Lobby', 'TR Eye Trap', 'TR Big Chest', 'TR Laser Bridge'],
|
|
# ['GT Lobby']
|
|
}
|
|
|
|
split_region_starts = {
|
|
'Desert Palace': [
|
|
['Desert Back Lobby'],
|
|
['Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby']
|
|
],
|
|
'Skull Woods': [
|
|
['Skull 1 Lobby', 'Skull Pot Circle'],
|
|
['Skull 2 West Lobby', 'Skull 2 East Lobby', 'Skull Back Drop'],
|
|
['Skull 3 Lobby']
|
|
]
|
|
}
|
|
|
|
dungeon_keys = {
|
|
'Hyrule Castle': 'Small Key (Escape)',
|
|
'Eastern Palace': 'Small Key (Eastern Palace)',
|
|
'Desert Palace': 'Small Key (Desert Palace)',
|
|
'Tower of Hera': 'Small Key (Tower of Hera)',
|
|
'Agahnims Tower': 'Small Key (Agahnims Tower)',
|
|
'Palace of Darkness': 'Small Key (Palace of Darkness)',
|
|
'Swamp Palace': 'Small Key (Swamp Palace)',
|
|
'Skull Woods': 'Small Key (Skull Woods)',
|
|
'Thieves Town': 'Small Key (Thieves Town)'
|
|
}
|
|
|
|
dungeon_bigs = {
|
|
'Hyrule Castle': 'Big Key (Escape)',
|
|
'Eastern Palace': 'Big Key (Eastern Palace)',
|
|
'Desert Palace': 'Big Key (Desert Palace)',
|
|
'Tower of Hera': 'Big Key (Tower of Hera)',
|
|
'Agahnims Tower': 'Big Key (Agahnims Tower)',
|
|
'Palace of Darkness': 'Big Key (Palace of Darkness)',
|
|
'Swamp Palace': 'Big Key (Swamp Palace)',
|
|
'Skull Woods': 'Big Key (Skull Woods)',
|
|
'Thieves Town': 'Big Key (Thieves Town)'
|
|
}
|
|
|