6969 'Nocturne of Shadow' ,
7070]
7171
72- # Song name: (rom index, warp, vanilla activation),
73- SONG_TABLE : dict [str , tuple [int , bool , str ]] = {
74- 'Zeldas Lullaby' : ( 8 , False , '<^><^>' ),
75- 'Eponas Song' : ( 7 , False , '^<>^<>' ),
76- 'Sarias Song' : ( 6 , False , 'v><v><' ),
77- 'Suns Song' : ( 9 , False , '>v^>v^' ),
78- 'Song of Time' : (10 , False , '>Av>Av' ),
79- 'Song of Storms' : (11 , False , 'Av^Av^' ),
80- 'Minuet of Forest' : ( 0 , True , 'A^<><>' ),
81- 'Bolero of Fire' : ( 1 , True , 'vAvA>v>v' ),
82- 'Serenade of Water' : ( 2 , True , 'Av>><' ),
83- 'Requiem of Spirit' : ( 3 , True , 'AvA>vA' ),
84- 'Nocturne of Shadow' : ( 4 , True , '<>>A<>v' ),
85- 'Prelude of Light' : ( 5 , True , '^>^><^' ),
72+ # Song name: (rom index, kind, vanilla activation),
73+ SONG_TABLE : dict [str , tuple [Optional [int ], str , str ]] = {
74+ 'Zeldas Lullaby' : ( 8 , 'frog' , '<^><^>' ),
75+ 'Eponas Song' : ( 7 , 'frog' , '^<>^<>' ),
76+ 'Sarias Song' : ( 6 , 'frog' , 'v><v><' ),
77+ 'Suns Song' : ( 9 , 'frog' , '>v^>v^' ),
78+ 'Song of Time' : ( 10 , 'frog' , '>Av>Av' ),
79+ 'Song of Storms' : ( 11 , 'frog' , 'Av^Av^' ),
80+ 'Minuet of Forest' : ( 0 , 'warp' , 'A^<><>' ),
81+ 'Bolero of Fire' : ( 1 , 'warp' , 'vAvA>v>v' ),
82+ 'Serenade of Water' : ( 2 , 'warp' , 'Av>><' ),
83+ 'Requiem of Spirit' : ( 3 , 'warp' , 'AvA>vA' ),
84+ 'Nocturne of Shadow' : ( 4 , 'warp' , '<>>A<>v' ),
85+ 'Prelude of Light' : ( 5 , 'warp' , '^>^><^' ),
86+ 'ZR Frogs Ocarina Game' : (None , 'frogs2' , 'A<>v<>vAvAv><A' ),
8687}
8788
8889
@@ -386,26 +387,32 @@ def get_random_song() -> Song:
386387
387388
388389# create a list of 12 songs, none of which are sub-strings of any other song
389- def generate_song_list (world : World , frog : bool , warp : bool ) -> dict [str , Song ]:
390+ def generate_song_list (world : World , frog : bool , warp : bool , frogs2 : bool ) -> dict [str , Song ]:
390391 fixed_songs = {}
391392 if not frog :
392- fixed_songs .update ({name : Song .from_str (notes ) for name , (_ , is_warp , notes ) in SONG_TABLE .items () if not is_warp })
393+ fixed_songs .update ({name : Song .from_str (notes ) for name , (_ , kind , notes ) in SONG_TABLE .items () if kind == 'frog' })
393394 if not warp :
394- fixed_songs .update ({name : Song .from_str (notes ) for name , (_ , is_warp , notes ) in SONG_TABLE .items () if is_warp })
395+ fixed_songs .update ({name : Song .from_str (notes ) for name , (_ , kind , notes ) in SONG_TABLE .items () if kind == 'warp' })
396+ if not frogs2 :
397+ fixed_songs .update ({name : Song .from_str (notes ) for name , (_ , kind , notes ) in SONG_TABLE .items () if kind == 'frogs2' })
395398 fixed_songs .update ({name : Song .from_str (notes ) for name , notes in world .distribution .configure_songs ().items ()})
396399 for name1 , song1 in fixed_songs .items ():
397400 if name1 not in SONG_TABLE :
398401 raise ValueError (f'Unknown song: { name1 !r} . Please use one of these: { ", " .join (SONG_TABLE )} ' )
399402 if not song1 .activation :
400403 raise ValueError (f'{ name1 } is empty' )
401- if len (song1 .activation ) > 8 :
402- raise ValueError (f'{ name1 } is too long (maximum is 8 notes)' )
404+ if name1 == 'ZR Frogs Ocarina Game' :
405+ if len (song1 .activation ) != 14 :
406+ raise ValueError (f'{ name1 } song must be exactly 14 notes' )
407+ else :
408+ if len (song1 .activation ) > 8 :
409+ raise ValueError (f'{ name1 } is too long (maximum is 8 notes)' )
403410 for name2 , song2 in fixed_songs .items ():
404411 if name1 != name2 and subsong (song1 , song2 ):
405412 raise ValueError (f'{ name2 } is unplayable because it contains { name1 } ' )
406413 random_songs = []
407414
408- for _ in range (12 - len ( fixed_songs )):
415+ for _ in range (12 - sum ( name != 'ZR Frogs Ocarina Game' for name in fixed_songs )):
409416 for _ in range (1000 ):
410417 # generate a completely random song
411418 song = get_random_song ()
@@ -428,6 +435,10 @@ def generate_song_list(world: World, frog: bool, warp: bool) -> dict[str, Song]:
428435 for name in DIFFICULTY_ORDER :
429436 if name not in fixed_songs :
430437 fixed_songs [name ] = random_songs .pop (0 )
438+
439+ if 'ZR Frogs Ocarina Game' not in fixed_songs :
440+ fixed_songs ['ZR Frogs Ocarina Game' ] = Song (activation = [random .randint (0 , 4 ) for _ in range (14 )])
441+
431442 return fixed_songs
432443
433444
@@ -437,6 +448,10 @@ def patch_songs(world: World, rom: Rom) -> None:
437448 if str (song ) == SONG_TABLE [name ][2 ]:
438449 continue # song activation is vanilla (possibly because this row wasn't randomized), don't randomize playback
439450
451+ if name == 'ZR Frogs Ocarina Game' :
452+ rom .write_bytes (0xB78AA0 , [note ['note' ] for note in song .playback ])
453+ continue
454+
440455 # fix the song of time
441456 if name == 'Song of Time' :
442457 song .increase_duration_to (260 )
0 commit comments