Sound Test

################################################################
# RETCON Library
# In Game Sound Test Version 1.3
# Author: Matt
# Script is free for usage, but please give credit where credit 
# is due. :)
################################################################
# PURPOSE
# This script allows users to have an in-game sound test, where
# players may listen to all the songs in the game. 
#
# There are two ways to use this script:
# Jukebox style:
# Define an event in the game world to run this script. Syntax is:
# SceneManager.call(Scene_SoundTest)
# This will run the script as-is.
#
# Title Screen style:
# The other usage is to run it from your title screen. Turning on the
# appropriate boolean variable will add it to the the title screen.
#
# Running Jukebox Style allows for discovery mode. Users can customize the
# script so that songs in the sound test are only revealed when they are
# first encountered in the game.
################################################################
# UPDATE HISTORY
# 1.3 - Now part of a library called RETCON.
# 1.2 - Hey cool, Matt figured out aliases! No more overwrites! Should now
#        play nicely with other scripts!
# 1.1 - Added method to escape with the cancel key.
#     - Fixed issue wherein song progress would not be saved after shutdown.
# 1.0 - First draft
################################################################
# METHODOLOGY
# Two new window classes are created:
#
# Window_SoundTest -- Derived from Window_Command
# Creates the actual sound test command window. Lists all the songs out
# with their titles.
#
# Window_SoundTestDesc - Derived from Window_Selectable
# Puts the currently selected song's description in its own window line.
#
# One new scene class is created:
#
# Scene_SoundTest -- Derived from Scene_MenuBase
# Puts the entire Soundtest in a new "scene".
#
# Four classes are overwritten to accommodate the sound test:
#
# The most important is: RPG::BGM, which added a line to turn
# the song in the hash listing to true when it gets activated.
#
# The Game_Party class is modified so that progress in unlocking
# songs is saved in the global $game_party class.
#
# Classes Window_TitleCommand and Scene_Title also get overwritten
# to accommodate accessing the sound test from the title screen.
################################################################
# CUSTOMIZATION
# In the module here, you will define each song in the matrix
# that you want in the sound test. First is the file name, (sans extension)
# then the song name, then the song description.
#
# All songs must be written as they are in your game database. Make sure to
# increment the MusicLibrary array for each new song you use.
#
# Example: 
# MusicLibrary[0] = ["002-Battle02", "Battle of the Dancers", "The default battle music"]
# MusicLibrary[1] = ["037-Dungeon03", "Mysteries Within", "Tower exploration music"]
# MusicLibrary[2] = ["Field4-2k", "Song of Adventures Past", "Third world map music"]
# etc.

module RETCON
  module SoundTest
      MusicLibrary = Array.new

      #edit here, dawg
      MusicLibrary[0] = ["002-Battle02", "Battle of the Dancers", "The default battle music"]
      MusicLibrary[1] = ["037-Dungeon03", "Mysteries Within", "Tower exploration music"]
      MusicLibrary[2] = ["Field4-2k", "Song of Adventures Past", "Third world map music"]

  #This adjusts the width of the box, default size is 300
      WindowWidth = 300

  #Number of menu items to display at once
      NumOfLines = 5

  #Offset for the song menu. Set to 0 to align at the bottom
      Offset = 75

  #Volume of the songs to be played at in the soundtest.
      Volume = 50

  #Size of the descriptor window. This size is added onto the size of the 
  #window menu to make it wider
      DescWindowSize = 75

  #Descriptor window offset. Set to 0 to align at the top
      DescOffSet = 75

  #Locked song on menu text. Value must be a string.
      LockedDisp = "???"

  #Description for locked song. Value must also be a string.
      LockedDesc = "Song Currently Locked!"

  #Name in the song menu to exit out of the sound test
      ExitDisp = "Exit"

  #Description for when the exit command is highlighted.
      ExitDesc = " "

  #Variable on making songs locked when the game first starts.
  #If set to true, then songs will be locked until they are first
  #played in the game. Set to false, all the songs will be made
  #available. Value must be a boolean.
  #NOTE: If this value is set to true, then set TitleScreenDisplay to false!
      MakeTheHash = true

  #Enables the sound test to be accessed from the title screen
  #NOTE: MakeTheHash --must-- be set to false! Otherwise you'll
  #get a bunch of locked songs! Value also must be a boolean.
      TitleScreenDisplay = false

  #Name of the command in the title menu. Value must be a string.
      TitleScreenName = "Sound Test"

################################################################
#Customization ends here!
#You shouldn't really edit below here, but if you know what
#you're doing, it won't be a big deal. Edit at your own risk and
#all that jazz.
################################################################
  end
end

#################
#CLASS ORIGINALS#
#################

#Initializes the Music Library into a window with appropriate key
class Window_SoundTest < Window_Command
  def initialize
    super(0, 0)
    update_placement
    refresh
    self.openness = 0
    open
  end

  def visible_line_number
     return RETCON::SoundTest::NumOfLines
  end

  def window_width
    return RETCON::SoundTest::WindowWidth
  end

  #places the location of the sound test menu
  def update_placement
    self.x = (Graphics.width - RETCON::SoundTest::WindowWidth) / 2
    self.y = (Graphics.height - height) - RETCON::SoundTest::Offset
  end

  #creates the command list for playing songs
  def make_command_list
    i = 0
    while i < RETCON::SoundTest::MusicLibrary.size
      if $game_party.music_hash[RETCON::SoundTest::MusicLibrary[i][0]] == false
        add_command(RETCON::SoundTest::LockedDisp, :soundtestblank)
      else
        add_command(RETCON::SoundTest::MusicLibrary[i][1], :soundtestitem)
      end
      i += 1
    end
    #adds the exit option to the menu
    add_command(RETCON::SoundTest::ExitDisp, :exit)
  end
end

#Description window class
class Window_SoundTestDesc < Window_Selectable
  def initialize
    super(0, 0, RETCON::SoundTest::WindowWidth + RETCON::SoundTest::DescWindowSize, fitting_height(1))
    update_placement
    refresh
  end

  def update_placement
    self.x = (Graphics.width - width) / 2
    self.y += RETCON::SoundTest::DescOffSet
  end

  def refresh
    super
    update_text(@songindex)
  end

  #updates the descrption window when changing selection
  def update_text(songindex)
    @songindex = songindex
    contents.clear
    draw_text(0, 0, width, line_height, @songindex)
  end  
end

#Sets objects in the window to play them in a new scene
class Scene_SoundTest < Scene_MenuBase
  def initialize
    super
    create_background
    create_soundtest
  end

  #creates both windows
  def create_soundtest
    @stest = Window_SoundTest.new
    @stestdesc = Window_SoundTestDesc.new
    i = 0
    while i < RETCON::SoundTest::MusicLibrary.size
      @stest.set_handler(:soundtestitem, method(:playsong))
      @stest.set_handler(:soundtestblank, method(:empty))
      i += 1
    end
      @stest.set_handler(:exit, method(:backout))
      @stest.set_handler(:cancel, method(:return_scene))
  end

  #function that calls a song play
  def playsong
    @stest.active = true
    Audio.bgm_play('Audio/BGM/' + RETCON::SoundTest::MusicLibrary[@stest.index][0], RETCON::SoundTest::Volume, 100)
  end

  #Should a player decide to try and a play a locked song, this acts as 
  #a dummy function
  def empty
    @stest.active = true
  end

  def backout
    @stest.close
    SceneManager.return
  end

  #updates the decsription window
  def update
    super
    if @stest.index < RETCON::SoundTest::MusicLibrary.size
      if $game_party.music_hash[RETCON::SoundTest::MusicLibrary[@stest.index][0]] == true
        @stestdesc.update_text(RETCON::SoundTest::MusicLibrary[@stest.index][2])
      else
        @stestdesc.update_text(RETCON::SoundTest::LockedDesc)
      end
    else
      @stestdesc.update_text(RETCON::SoundTest::ExitDesc)
    end
  end
end

###############
#CLASS ADDENDA#
###############

#Modify BGM class to change hash values to true when song plays for the
#first time, thus unlocking them in the menu.
class RPG::BGM < RPG::AudioFile
  alias st_play_function play
  def play(pos = 0)
    st_play_function
    $game_party.song_played(@name)
  end
end

#Initalizes/saves the hash in the Game_Party class, and can be accessed
#via $game_party.music_hash
class Game_Party < Game_Unit
  attr_accessor   :music_hash

  alias st_retain_previous initialize

  def initialize
    st_retain_previous
    @music_hash = Hash.new
    make_the_hash
  end

  #initalizes the song hash. true means songs are locked. false means
  # they're all available.
  def make_the_hash
    i = 0
    while i < RETCON::SoundTest::MusicLibrary.size
      if RETCON::SoundTest::MakeTheHash == true
        @music_hash.merge! RETCON::SoundTest::MusicLibrary[i][0] => false
      else
        @music_hash.merge! RETCON::SoundTest::MusicLibrary[i][0] => true
      end
      i += 1
    end
  end

  #updates the hash when a song is unlocked.
  def song_played(nameofsong)
    @music_hash[nameofsong] = true
  end
end

#Adds function to Title Screen window class to add soundtest option to menu.
class Window_TitleCommand < Window_Command

  alias st_command_list make_command_list
  def make_command_list
    st_command_list
    if RETCON::SoundTest::TitleScreenDisplay == true
    add_command(RETCON::SoundTest::TitleScreenName, :soundtest)
    end
  end
end

#Adds soundtest option to Scene_Title and displays it.
class Scene_Title < Scene_Base

  alias st_command_window create_command_window
  def create_command_window
    st_command_window
    @command_window.set_handler(:soundtest, method(:command_soundtest))
  end

  def command_soundtest
      close_command_window
      SceneManager.call(Scene_SoundTest)
  end
end