2017-12-17 05:25:46 +00:00
import random
2017-10-15 16:16:07 +00:00
from BaseClasses import Dungeon
2017-10-15 19:35:45 +00:00
from Fill import fill_restrictive
2017-12-17 05:25:46 +00:00
from Items import ItemFactory
2017-05-15 18:28:04 +00:00
2017-10-15 16:16:07 +00:00
def create_dungeons ( world ) :
def make_dungeon ( name , dungeon_regions , big_key , small_keys , dungeon_items ) :
dungeon = Dungeon ( name , dungeon_regions , big_key , small_keys , dungeon_items )
for region in dungeon . regions :
world . get_region ( region ) . dungeon = dungeon
return dungeon
ES = make_dungeon ( ' Hyrule Castle ' , [ ' Hyrule Castle ' , ' Sewers ' , ' 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 ' , ' 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 ) , [ ] )
2017-11-12 00:03:42 +00:00
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) ' ] ) )
2017-10-15 16:16:07 +00:00
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) ' ] ) )
2017-12-13 14:51:53 +00:00
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) ' ] ) )
2017-10-15 16:16:07 +00:00
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) ' ] ) )
2017-11-12 00:03:42 +00:00
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) ' ] ) )
2017-10-15 16:16:07 +00:00
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) ' ] ) )
world . dungeons = [ TR , ES , EP , DP , ToH , AT , PoD , TT , SW , IP , MM , GT , SP ]
2017-05-15 18:28:04 +00:00
2017-10-15 16:16:07 +00:00
def fill_dungeons ( world ) :
2017-10-29 03:42:35 +00:00
freebes = [ ' Ganons Tower - Map Chest ' , ' Palace of Darkness - Harmless Hellway ' , ' Palace of Darkness - Big Key Chest ' , ' Turtle Rock - Big Key Chest ' ]
2017-05-15 18:28:04 +00:00
2017-06-17 12:40:37 +00:00
all_state_base = world . get_all_state ( )
2017-10-29 03:42:35 +00:00
world . push_item ( world . get_location ( ' Skull Woods - Pinball Room ' ) , ItemFactory ( ' Small Key (Skull Woods) ' ) , False )
world . get_location ( ' Skull Woods - Pinball Room ' ) . event = True
2017-05-15 18:28:04 +00:00
2017-10-15 16:16:07 +00:00
dungeons = [ ( list ( dungeon . regions ) , dungeon . big_key , list ( dungeon . small_keys ) , list ( dungeon . dungeon_items ) ) for dungeon in world . dungeons ]
2017-07-17 20:26:15 +00:00
2017-08-05 15:51:38 +00:00
loopcnt = 0
while dungeons :
loopcnt + = 1
dungeon_regions , big_key , small_keys , dungeon_items = dungeons . pop ( 0 )
2017-05-15 18:28:04 +00:00
# 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 )
2017-06-17 12:40:37 +00:00
all_state = all_state_base . copy ( )
2017-05-15 18:28:04 +00:00
# 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 )
2017-06-17 12:40:37 +00:00
bk_location . event = True
2017-05-15 18:28:04 +00:00
dungeon_locations . remove ( bk_location )
2017-12-17 05:25:46 +00:00
all_state . clear_cached_unreachable ( )
2017-08-05 15:51:38 +00:00
big_key = None
2017-05-15 18:28:04 +00:00
# next place small keys
2017-08-05 15:51:38 +00:00
while small_keys :
small_key = small_keys . pop ( )
2017-06-17 12:40:37 +00:00
all_state . sweep_for_events ( )
2017-05-15 18:28:04 +00:00
sk_location = None
for location in dungeon_locations :
2017-07-17 20:26:15 +00:00
if location . name in freebes or ( location . can_reach ( all_state ) and location . item_rule ( small_key ) ) :
2017-05-15 18:28:04 +00:00
sk_location = location
break
if sk_location is None :
2017-08-05 15:51:38 +00:00
# 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 :
break
else :
raise RuntimeError ( ' No suitable location for %s ' % small_key )
2017-05-15 18:28:04 +00:00
world . push_item ( sk_location , small_key , False )
2017-06-17 12:40:37 +00:00
sk_location . event = True
2017-05-15 18:28:04 +00:00
dungeon_locations . remove ( sk_location )
2017-12-17 05:25:46 +00:00
all_state . clear_cached_unreachable ( )
2017-05-15 18:28:04 +00:00
2017-08-05 15:51:38 +00:00
if small_keys :
# key placement not finished, loop again
continue
2017-05-15 18:28:04 +00:00
# next place dungeon items
2017-05-20 12:05:15 +00:00
if world . place_dungeon_items :
2017-05-15 18:28:04 +00:00
for dungeon_item in dungeon_items :
di_location = dungeon_locations . pop ( )
world . push_item ( di_location , dungeon_item , False )
2017-12-17 05:25:46 +00:00
world . state . clear_cached_unreachable ( )
2017-05-25 15:47:15 +00:00
2018-01-03 01:01:16 +00:00
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 ]
2017-05-25 15:47:15 +00:00
2017-10-15 20:34:46 +00:00
def fill_dungeons_restrictive ( world , shuffled_locations ) :
2017-10-15 17:52:42 +00:00
all_state_base = world . get_all_state ( )
2017-10-29 03:42:35 +00:00
skull_woods_big_chest = world . get_location ( ' Skull Woods - Pinball Room ' )
2017-10-15 20:34:46 +00:00
world . push_item ( skull_woods_big_chest , ItemFactory ( ' Small Key (Skull Woods) ' ) , False )
skull_woods_big_chest . event = True
shuffled_locations . remove ( skull_woods_big_chest )
2017-10-15 19:35:45 +00:00
2018-01-03 01:01:16 +00:00
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 )
2017-10-15 19:35:45 +00:00
# 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 ) )
2017-10-15 17:52:42 +00:00
fill_restrictive ( world , all_state_base , shuffled_locations , dungeon_items )
2017-10-15 19:35:45 +00:00
2017-12-17 05:25:46 +00:00
world . state . clear_cached_unreachable ( )
2017-10-15 17:52:42 +00:00
2017-10-29 03:42:35 +00:00
dungeon_music_addresses = { ' Eastern Palace - Prize ' : [ 0x1559A ] ,
' Desert Palace - Prize ' : [ 0x1559B , 0x1559C , 0x1559D , 0x1559E ] ,
2017-11-09 00:23:21 +00:00
' Tower of Hera - Prize ' : [ 0x155C5 , 0x1107A , 0x10B8C ] ,
2017-10-29 03:42:35 +00:00
' 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 ] }