HiddenPlayList XP
#1
HiddenPlayList XP

by Kyonides

Introduction

Well, this one is quite easy to explain: it's a simple jukebox script. Grinning

Setup

Create 1 or more playlists, and name it "playlist1.txt" or something the like depending on the number of available playlists.
The file's contents should always follow this format:

Playlist Title
Custom Song Name > Filename
etc.

Here's an example:

Code:
ACE OGG + XP MIDI
Our Airship > Airship
Blood > 04_blood
Theme #4 > 015-Theme04
Battle #1 > 001-Battle01
Field #1 > 018-Field01
Battle #2 > 002-Battle02
Field #2 > 019-Field02
Battle #3 > 003-Battle03
Field #3 > 020-Field03
Battle #4 > 004-Battle04
Theme #6 > 017-Theme06

NOTE: Always leave an empty line at the end of the file!

Script Call

Code:
$scene = HiddenPlay::Scene.new

The Script

Code:
# * HiddenPlayList XP * #
#   Scripter : Kyonides Arkanthes
#   2026-06-30

# * REQUIRES HiddenChest v1.2.12 or later * #

# This scriptlet allows you to play a list of songs one after another.

# * Script Call * #

# $scene = HiddenPlay::Scene.new

module HiddenPlay
  @menu_bgm = ["024-Town02", 50]
  MAIN_BGM_CHANNEL = 3
  LIST_BGM_CHANNEL = 1
  class Song < RPG::AudioFile
    DIR = "Audio/BGM/"
    def play
      Audio.bgms_play(@channel, DIR + @name, @volume, @pitch)
      @seconds ||= Audio.bgms_seconds(@channel)
      @playing = true
    end

    def pause
      Audio.bgms_pause(@channel)
      @playing = false
    end

    def resume
      Audio.bgms_resume(@channel)
      @playing = true
    end

    def toggle!
      @playing ? pause : resume
    end
    attr_accessor :title, :channel
    attr_reader :seconds
  end

  class List
    def initialize
      @name = "Playlist"
      @files = []
    end
    attr_accessor :name, :files
  end

  extend self
  attr_reader :menu_bgm

  class BGMWindow < Window_Base
    def initialize(wx, wy, ww, wh)
      super
      @width = ww - 32
      @height = wh - 32
      self.contents = Bitmap.new(@width, @height)
      @name_rect = Rect.new(0, 0, @width, 32)
      @time_rect = Rect.new(0, 40, @width, 32)
    end

    def calc_time(sec)
      @bar.set_progress(sec)
      @seconds = sec % 60
      @minutes = sec / 60
      self.contents.clear_rect(@time_rect)
    end

    def set(file)
      @channel = file.channel
      @name = file.title
      @minutes = 0
      @seconds = Audio.bgms_pos(@channel).round
      total_seconds = file.seconds.floor
      @sec = total_seconds % 60
      @min = total_seconds / 60
      self.contents.clear
      self.contents.draw_text(@name_rect, @name, 1)
      @total_time = sprintf("%02d:%02d", @min, @sec)
      refresh
    end

    def refresh
      self.contents.clear_rect(@time_rect)
      text = sprintf("%02d:%02d", @minutes, @seconds)
      self.contents.draw_text(@time_rect, text)
      self.contents.draw_text(@time_rect, @total_time, 2)
    end

    def update
      sec = Audio.bgms_pos(@channel).round
      if @seconds != sec
        calc_time(sec)
        refresh
      end
    end
    attr_writer :bar
  end

  class BarSprite < Sprite
    BLACK = Color.new(0, 0, 0)
    LIGHT = Color.new(192, 224, 255, 255)
    def initialize(sx, sy, sw, sh)
      super(nil)
      self.x = sx
      self.y = sy
      @width = sw
      @height = sh
      reset
    end

    def reset
      self.bitmap = Bitmap.new(@width, @height)
      self.bitmap.fill_rect(:rect, BLACK)
    end

    def total=(sec)
      self.visible = true
      @total = sec
      reset
    end

    def set_progress(sec)
      rect = self.bitmap.rect.dup
      percent = sec * 100 / @total
      percent = 100 if percent == 0
      rect.width = percent * @width / 100
      self.bitmap.fill_rect(rect, LIGHT)
    end
  end

  class Scene
    SELECT_LIST = "Select a Playlist"
    EMPTY_LIST = "Empty List"
    MENU_BGM = Song.new(*HiddenPlay.menu_bgm)
    MENU_BGM.channel = MAIN_BGM_CHANNEL
    VOLUME = 40
    def initialize
      @loop_states = Audio.bgms_loop_all.dup
      Audio.bgms_loop_set(1, false)
      Audio.bgms_loop_set(2, false)
      Audio.bgms_loop_set(3, true)
      3.times {|n| Audio.bgms_fade(n + 1, 60) }
      MENU_BGM.play
      @font_outline = Font.default_outline
      Font.default_outline = true
      @lists = []
      @files = Dir["playlist*.txt"].sort
      @files.each do |file|
        lines = File.readlines(file)
        list = List.new
        list.name = lines.shift.chomp
        lines.each do |line|
          texts = line.split(" > ")
          audio = Song.new
          audio.title = texts.shift
          audio.name = texts.shift.chomp
          audio.volume = VOLUME
          audio.channel = LIST_BGM_CHANNEL
          list.files << audio
        end
        @lists << list
      end
      @commands = @lists.map(&:name) || [EMPTY_LIST]
      @playlist_empty = @lists.empty?
      @list_index = @song_index = @timer = 0
      @stop = true
      @stage = :main
    end

    def main
      start
      Graphics.transition
      while @stage
        Graphics.update
        Input.update
        update
      end
      Graphics.freeze
      terminate
    end

    def start
      @help_window = Window_Help.new
      @help_window.set_text(SELECT_LIST, 1)
      @list_window = Window_Command.new(240, @commands)
      @list_window.y = 64
      ox = @list_window.width
      ww = Graphics.width - ox
      @bgm_window = BGMWindow.new(ox, 64, ww, 100)
      @playtime_bar = BarSprite.new(ox + 16, 112, ww - 32, 4)
      @playtime_bar.visible = false
      @playtime_bar.z = 100
      @bgm_window.bar = @playtime_bar
    end

    def update
      case @stage
      when :main
        update_main
      when :list
        update_list
      when :next
        update_next
      end
    end

    def update_main
      @list_window.update
      if Input.trigger?(:B)
        $game_system.se_play($data_system.cancel_se)
        Audio.bgms_stop_all
        $scene = Scene_Map.new
        return @stage = nil
      elsif Input.trigger?(:C)
        if @playlist_empty
          $game_system.se_play($data_system.buzzer_se)
          return
        end
        MENU_BGM.pause
        n = @list_window.index
        @list = @lists[n]
        @files = @list.files
        if @files.empty?
          $game_system.se_play($data_system.buzzer_se)
          @list = nil
          return @files = nil
        end
        $game_system.se_play($data_system.decision_se)
        @song_index = 0 if @list_index != n
        @list_index = n
        @help_window.set_text(@list.name, 1)
        @list_window.active = false
        @list_window.visible = false
        titles = @files.map(&:title)
        @song_window = Window_Command.new(240, titles)
        @song_window.y = 64
        @file_max = @files.size
        play_file
      end
    end

    def play_file
      @song_window.index = @song_index
      @file = @files[@song_index]
      @file.play
      @bgm_window.set(@file)
      @playtime_bar.total = @file.seconds
      @stage = :list
    end

    def update_next
      @song_index = (@song_index + 1) % @file_max
      play_file
      @play_next = nil
    end

    def update_list
      if Audio.bgms_stopped?(LIST_BGM_CHANNEL)
        return @stage = :next
      end
      @bgm_window.update
      @song_window.update
      if Input.trigger?(:B)
        $game_system.se_play($data_system.cancel_se)
        Audio.bgms_stop(LIST_BGM_CHANNEL)
        MENU_BGM.resume
        @help_window.set_text(SELECT_LIST, 1)
        @playtime_bar.visible = false
        @bgm_window.contents.clear
        @song_window.dispose
        @list_window.active = true
        @list_window.visible = true
        return @stage = :main
      elsif Input.trigger?(:C)
        $game_system.se_play($data_system.decision_se)
        if @song_window.index == @song_index
          @file.toggle!
          return
        end
        Audio.bgms_stop(LIST_BGM_CHANNEL)
        @song_index = @song_window.index - 1
        @stage = :next
      end
    end

    def terminate
      @loop_states.each {|n, state| Audio.bgms_loop_set(n, state) }
      Font.default_outline = @font_outline
      @playtime_bar.dispose
      @bgm_window.dispose
      @list_window.dispose
      @help_window.dispose
      $game_map.autoplay
    end
  end
end

class Game_System
  def bgms_play(n, bgm)
    @playing_bgms ||= {}
    @playing_bgms[n] = bgm
    if bgm != nil and bgm.name != ""
      Audio.bgms_play(n, "Audio/BGM/" + bgm.name, bgm.volume, bgm.pitch)
    else
      Audio.bgms_stop(n)
    end
    Graphics.frame_reset
  end

  def bgms_stop(n)
    Audio.bgms_stop(n)
  end

  def bgms_fade(n, time)
    @playing_bgms ||= {}
    @playing_bgms[n] = nil
    Audio.bgms_fade(n, time * 1000)
  end

  def bgms_memorize(n)
    @memorized_bgms ||= {}
    @memorized_bgms[n] = @playing_bgm
  end

  def bgms_restore(n)
    bgms_play(n, @memorized_bgm)
  end
end

Terms & Conditions

Under MIT License.
That's it! Tongue sticking out
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9

Maranatha!

The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.

[Image: SP1-Scripter.png]
[Image: SP1-Writer.png]
[Image: SP1-Poet.png]
[Image: SP1-PixelArtist.png]
[Image: SP1-Reporter.png]

My Original Stories (available in English and Spanish)

List of Compiled Binary Executables I have published...
HiddenChest & Roole

Give me a free copy of your completed game if you include at least 3 of my scripts! Laughing + Tongue sticking out

Just some scripts I've already published on the board...
KyoGemBoost XP VX & ACE, RandomEnkounters XP, KSkillShop XP, Kolloseum States XP, KEvents XP, KScenario XP & Gosu, KyoPrizeShop XP Mangostan, Kuests XP, KyoDiscounts XP VX, ACE & MV, KChest XP VX & ACE 2016, KTelePort XP, KSkillMax XP & VX & ACE, Gem Roulette XP VX & VX Ace, KRespawnPoint XP, VX & VX Ace, GiveAway XP VX & ACE, Klearance XP VX & ACE, KUnits XP VX, ACE & Gosu 2017, KLevel XP, KRumors XP & ACE, KMonsterPals XP VX & ACE, KStatsRefill XP VX & ACE, KLotto XP VX & ACE, KItemDesc XP & VX, KPocket XP & VX, OpenChest XP VX & ACE
Reply


Messages In This Thread
HiddenPlayList XP - by kyonides - 06-22-2026, 02:44 AM
RE: HiddenPlayList XP - by kyonides - 06-29-2026, 09:08 AM



Users browsing this thread: 1 Guest(s)