# SETTINGS BEGIN
# Text that will appear if a song is locked.
LOCKED_NAME = "???"
# Sort order. Possible values:
# ASC = name, ascending (A-Z)
# DESC = name, descending (Z-A).
# APP = by appearance.
# MANUAL = manually specified.
# Any other values will be regarded as ASC.
SORT_ORDER = "APP"
# If using MANUAL sort order, fill in the order here.
# You SHOULD specify all song names here, but in case there is
# any songs in your Audio/BGM folder that you forgot to enlist,
# they will be appended to the end of this list at ascending order.
# Include file extensions (it's too risky to omit file extensions,
# since you might have two files with the same name but different type).
# Case insensitive (am I generous, not? ;)).
# Separate each entry by a comma.
# Be careful not to enter one song more than once, or your player
# will never have 100% unlocks.
# See example:
MANUAL_SORT =
[
"002-Battle02.mid",
"043-Positive01.mid",
"001-Battle01.mid",
"064-Slow07.mid",
]
# Show numbering?
SHOW_NUMBER = true
# Show unlock status?
# If set to true, a help window will show how many songs are (un)locked.
# More settings for status window are available.
SHOW_STATUS = true
# Settings below would not take effect if SHOW_STATUS is set to false.
# --------------------------------------------------------------------
# Status type
# Possible values:
# NORMAL: shows numbers of unlocked songs. Default.
# e.g. Unlocked songs: 3
# REMAINING: shows numbers of locked songs.
# e.g. Locked songs remaining: 7
# Any other values will be regarded as NORMAL.
# Can also include total song (see SHOW_TOTAL_SONGS).
STATUS_TYPE = "NORMAL"
# Use percentage instead?
USE_PERCENT = false
# How many decimal digits will be displayed? Default is 2.
# Does not have effect if USE_PERCENT is set to false
PERCENT_DEC_DIGIT = 2
# Decimal sign, in case you're not using English numbering (".")
# Does not have effect if USE_PERCENT is set to false
DECIMAL_SIGN = "."
# Define the status texts as you wish
NORMAL_TEXT = "Unlocked songs: "
REMAINING_TEXT = "Locked songs remaining: "
# Show total songs?
# Does not have effect if USE_PERCENT is set to true
SHOW_TOTAL_SONGS = true
# SETTINGS END
=begin
*******************
Notes on percentage
*******************
As you can see below, I modified Float class to be able to convert itself
into a percentage string. For example:
(2.1).to_percent => 210%
There are four optional parameters (you can specify or omit them):
1. decimal_digit = 0
Specifies how many digit after the decimal sign will be taken.
For example:
(0.98765).to_percent(2) will result in 98.76%
(or 98.77%, depending on next parameters).
Default is 0 (no decimal digit will be taken).
2. round = true
If true, rounding will be performed (see example).
Otherwise, pick only needed decimal digits and discard the rest (truncate).
Example:
(0.98765).to_percent(2, false) => 98.76%
(0.98765).to_percent(2, true) => 98.77%
(0.98764).to_percent(2) => 98.76%
Default is true (perform rounding).
3. include_percent_sign = true
If by any chance you don't want to include percent sign (%), maybe to
be processed furthermore, set this parameter to false.
Example:
(0.98765).to_percent(2, false, true) => 98.76%
(0.98765).to_percent(2, false, false) => 98.76
Remember that the result is still in string, so you may need to convert
before processing.
Default is true (include percent sign).
4. decimal_sign = "."
Very useful if you don't use English number formatting. Some language
use "," instead of ".". For example:
(0.98765).to_percent(2, false, ",") => 98,76%
Default is ".".
=end
# This class holds song data
class Game_Songs
attr_reader :name # song name
attr_reader :unlocked # song state
# initialization
def initialize(filename)
# Strip extension from filename
@name = filename[0, filename.length - 4]
# Lock this song
@unlocked = false
end
# unlock the song
def unlock
@unlocked = true
end
# unlocked?
def unlocked?
return @unlocked
end
end
class Game_System
attr_reader :songs # list of all songs
attr_reader :unlocks # only used when SORT_ORDER is APP or MANUAL
# also contains the same song object as @songs
# but in different order
alias song_initialize initialize
def initialize
song_initialize
# Make song lists
get_song_list
end
# get the latest song list
def get_song_list
# First, get the current songs from Audio/BGM folder
list = Dir.entries(File.expand_path("Audio/BGM"))
list.delete_at 0
list.delete_at 0
# Update flag
update_flag = false
# If not starting a new game
unless @songs == nil
# Reserve old ones
old_songs = @songs
old_unlocks = @unlocks
# Pretended as updating, although the list remains the same
update_flag = true
end
# Prepare new lists
@songs = []
# List unlocks when necessary
@unlocks = [] if SORT_ORDER == "APP" or SORT_ORDER == "MANUAL"
# Sort by name, ascending
list.sort!
# Sort in which order?
case SORT_ORDER
when "DESC" # name, descending
list.reverse!
when "MANUAL" # manually specified
# Temporary list
list_temp = []
# Check manually from the current list
for manual_song in MANUAL_SORT
# Iterate at manual list...
for song in list
# Name equal?
if song.downcase == manual_song.downcase
# Add into song list
list_temp.push(song)
break
end
end
end
# Is there by any chance you forgot some songs?
if list_temp.size < list.size
# Reiterate the current list
for song in list
# If not included in temporary list, add
unless list_temp.include?(song)
list_temp.push(song)
end
end
end
# Swap back
list = list_temp
end
# Now add the newest songs to the list
# Depending on sort order...
case SORT_ORDER
when "APP", "MANUAL"
# Immediately add the old unlocks if updating
@unlocks = old_unlocks if update_flag
end
# Iterate through latest list
for music in list
current_song = Game_Songs.new(music)
# If updating
if update_flag
# Check if it's already unlocked by previous games
for song in old_songs
if song.name == music[0, music.length - 4]
if song.unlocked?
# Already unlocked previously, unlock again
current_song.unlock
end
end
end
end
# Add to latest list
@songs.push(current_song)
end
# Automatically unlock title BGM
# (since New Game command will unexpectedly remake $game_system object)
# UNLESS you're updating
unless update_flag
for song in @songs
if song.name == $data_system.title_bgm.name
song.unlock
@unlocks.push(song) if SORT_ORDER == "APP" or SORT_ORDER == "MANUAL"
break
end
end
end
end
#--------------------------------------------------------------------------
# * Play Background Music and unlocks them
# bgm : background music to be played
#--------------------------------------------------------------------------
def bgm_play(bgm)
@playing_bgm = bgm
if bgm != nil and bgm.name != ""
Audio.bgm_play("Audio/BGM/" + bgm.name, bgm.volume, bgm.pitch)
# Find the BGM in song list and unlock
for song in @songs
if song.name == bgm.name
unless song.unlocked?
song.unlock
@unlocks.push(song) if SORT_ORDER == "APP" or SORT_ORDER == "MANUAL"
end
break
end
end
else
Audio.bgm_stop
end
Graphics.frame_reset
end
end
# This class draws a list of songs in a window
class Window_Songs < Window_Selectable
# initialization
def initialize(x, y, width, height)
super(x, y, width, height)
@item_max = $game_system.songs.size
@column_max = 1
self.contents = Bitmap.new(width - 32, @item_max * 32)
@index = 0
refresh
end
def refresh
self.contents.clear
# Depending on sorting mode, take the appropriate list
case SORT_ORDER
when "APP"
song_list = $game_system.unlocks
else
song_list = $game_system.songs
end
for i in 0 ... song_list.size
song = song_list[i]
# Show numbering?
if SHOW_NUMBER
name = "#{i + 1}. "
else
name = ""
end
# If unlocked, draw song name
if song.unlocked?
name += song.name
color = normal_color
else
name += LOCKED_NAME
color = disabled_color
end
self.contents.font.color = color
self.contents.draw_text(4, i * 32, 640, 32, name)
end
# In APP mode, enlist any other songs as locked
if SORT_ORDER == "APP"
offset = i + 1
total_song = $game_system.songs.size
for j in offset .. total_song
name = "#{j + 1}. #{LOCKED_NAME}"
color = disabled_color
self.contents.font.color = color
self.contents.draw_text(4, j * 32, 640, 32, name)
end
end
end
# update window help
def update_help
@help_window.update
end
end
# This class performs scene for song list.
class Scene_Songs
# initialization
def main
y = (SHOW_STATUS ? 64 : 0)
@song_window = Window_Songs.new(0, y, 640, 480 - y)
# Show status if necessary
if SHOW_STATUS
@help_window = Window_Help.new
unlocked = 0
total = $game_system.songs.size
for song in $game_system.songs
unlocked += 1 if song.unlocked?
end
# Set help window text based on settings
case STATUS_TYPE
when "NORMAL"
text = NORMAL_TEXT
# Use percent style?
if USE_PERCENT
percent = (unlocked.to_f / total.to_f).to_percent(PERCENT_DEC_DIGIT)
text += percent
else
text += unlocked.to_s + (SHOW_TOTAL_SONGS ? "/#{total}" : "")
end
when "REMAINING"
locked = total - unlocked
text = REMAINING_TEXT
# Use percent style?
if USE_PERCENT
percent = (locked.to_f / total.to_f).to_percent(PERCENT_DEC_DIGIT)
text += percent
else
text += locked.to_s + (SHOW_TOTAL_SONGS ? "/#{total}" : "")
end
end
@help_window.set_text(text)
@song_window.help_window = @help_window
end
# Remember BGM and BGS so we can restore it later
@last_bgm = $game_system.playing_bgm.name
$game_system.bgm_memorize
$game_system.bgs_memorize
Graphics.transition
# start scene
loop do
Graphics.update
Input.update
update
if $scene != self
break
end
end
Graphics.freeze
# Disposal of windows
@song_window.dispose
@help_window.dispose unless @help_window == nil
# Restore BGM and BGS
$game_system.bgm_restore
$game_system.bgs_restore
end
def update
@song_window.update
# If C button is pressed
if Input.trigger?(Input::C)
# If songs is locked...
# Depending on sort order, pick the right song
case SORT_ORDER
when "APP"
song = $game_system.unlocks[@song_window.index]
else
song = $game_system.songs[@song_window.index]
end
# ONLY IF song is found...
if song == nil
# song still locked, play buzzer
$game_system.se_play($data_system.buzzer_se)
else
if song.unlocked?
# If last BGM is different than current
if @last_bgm != song.name
@last_bgm = song.name
# Fade out current BGM and play the selected one
Audio.bgm_fade(100)
Audio.bgm_play("Audio/BGM/" + song.name)
end
else
# song still locked, play buzzer
$game_system.se_play($data_system.buzzer_se)
end
end
return
end
# If B button is pressed
if Input.trigger?(Input::B)
# Play cancel SE
$game_system.se_play($data_system.cancel_se)
# Switch to map screen
$scene = Scene_Map.new
return
end
end
end
# Rewrites to Ruby's Float class to accomodate conversion into percentage string
class Float < Numeric
# Convert to percentage (string)
# Returns string (self is not modified)
def to_percent(decimal_digit = 0, round = true, include_percent_sign = true,
decimal_sign = ".")
# Error checking
decimal_digit = 0 if decimal_digit < 0
decimal_sign = "." unless decimal_sign.is_a?(String)
# Modify number so the first decimal digit is the significant digit
# we want to round
percent = self * 100 * (10 ** decimal_digit)
# Perform round if necessary
if round
percent = percent.round
end
# Revert back to floating number (already in percentage)
percent = percent.to_f / (10 ** decimal_digit).to_f
# Convert to string
percent = percent.to_s
# Get integer digits
leading = percent[/(\d)*./]
# Remove decimal sign
leading = leading[0, leading.size - 1]
# Get decimal digits
digit = percent[/\D(\d)*/]
# Strip off decimal sign
digit = digit[1, digit.size - 1]
# If by any case, after rounding, decimal digit length is less than desired,
# add trailing zeroes
if digit.length < decimal_digit
digit += "0" * (decimal_digit - digit.length)
# Or if rounding wasn't performed and decimal digit length is
# more than desired, redefine decimal digit
elsif digit.length > decimal_digit and truncate
digit = digit[0, decimal_digit]
end
percent = leading + decimal_sign + digit
# Include percent sign (%)?
percent = percent + "%" if include_percent_sign
return percent
end
end
# refresh song list (in case it is different from the last save)
class Scene_Load < Scene_File
alias song_on_decision on_decision
def on_decision(filename)
# Calls original loading data on decision
song_on_decision(filename)
# Update song list
$game_system.get_song_list
end
end