Sound Emitting Areas/Events
Version: 2.0
Author: modern algebra
Date: August 9, 2008
Version History
- <Version 2.0> - Allows you to set sound emission from an event as well - August 9, 2008
- <Version 1.1> - Now fully compatible with Advanced Areas and will turn the sound off the moment an area is deactivated - July 31, 2008
- <Version 1.0b> - A slight oversight in the calculations fixed - July 29, 2008
- <Version 1.0> - Original Release - July 26, 2008
Description
This script allows you to set a bgm, bgs, se, or me to areas or events and it dynamically calculates the volume depending on how far the player is from the area or event, creating the impression that the sound is emitting from that area or event.
Features
- Can set sound emission to either an area or an event
- Can attach a different sound or no sound to each individual page of an event.
- Can set a bgm, bgs, se, or me
- Smooth volume transition
- Allows you to set SE repetition by frames and with variance
- Lots of options for configuring each sound
- Compatible with Advanced Areas, allowing you to turn off Areas that emit sound
Screenshots
Not applicable for this script. See the Demo for a better understanding of the script.
Instructions
See inside the script.
Script
#==============================================================================
# Dynamic Sound Emitting Areas/Events (VX)
# Version 2.0
# Author: modern algebra (rmrk.net)
# Date: August 9, 2008
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Description:
# This script allows you to set a bgm, bgs, se, and me to areas or events and
# it dynamically adjusts the volume depending on how far the player is from
# the area or event, thus creating the impression that the sound is emitting
# from that area or event.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Instructions:
#
# For setting up an event, all you need to do is place a comment in the
# first lines of a page with any number of these codes:
#
# \SNDEMIT[stat = value]
#
# The possible stats to set are:
#
# bgm_name = 'Name of BGM you wish to emit' (Default = '')
# bgm_pitch = the pitch of the BGM, from 50 to 150 (Default = 100)
# bgm_radius = the radius, in squares, of BGM range. (Default = 10)
# bgm_max_volume = The maximum volume of the BGM (Default = 100)
# bgs_name = 'Name of BGS you wish to emit' (Default = '')
# bgs_pitch = the pitch of the BGS, from 50 to 150 (Default = 100)
# bgs_radius = the radius, in squares, of BGS range. (Default = 10)
# bgs_max_volume = The maximum volume of the BGS (Default = 100)
# se_name = 'Name of SE you wish this area to emit' (Default = '')
# se_pitch = the pitch of the SE, from 50 to 150 (Default = 100)
# se_radius = the radius, in squares, of the SE range (Default = 10)
# se_max_volume = the maximum volume of the SE (Default = 100)
# se_frames = the number of frames between playing the SE (Default = 20)
# se_frame_variance = the variance off se_frames (Default = 0)
# me_name = 'Name of ME you wish this area to emit' (Default = '')
# me_pitch = the pitch of the ME, from 50 to 150 (Default = 100)
# me_radius = the radius, in squares, of the ME range (Default = 10)
# me_max_volume = the maximum volume of the ME (Default = 100)
# me_frames = the number of frames between playing the ME (Default = 20)
# me_frame_variance = the variance off me_frames (Default = 0)
#
# EXAMPLE:
# Set this in a comment of an event:
#
# \sndemit[se_name = 'Chicken']
# \SndEmit[se_max_volume = 80]
# \sNdeMit[se_frames = 440]
# \SNDEMIT[se_frame_variance = 60]
#
# And the event will play the sound effect 'Chicken' at a max volume of 80
# with a range of 10. It will repeat this SE every 380 - 500 frames
#==============================================================================
#==============================================================================
# ** RPG::Area
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Summary of Changes:
# new instance variables - se_frames, se_frame_variance, me_frames,
# me_frame_variance
# new methods - setup_sound_emissions, bgm, bgs, me, se, bgm?, bgs?, se?,
# me?, volume, update_se, update_me
#==============================================================================
class RPG::Area
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Public Instance Variables
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
attr_reader :sound_emission
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Setup Sound Emissions
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def setup_sound_emissions
s = @sound_emission = RPG::Sound_Emission.new
case @id
#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
# !*!*! CONFIGURABLE REGION
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set this region up in this way:
#
# when area_id
# s.stat = value
#
# The stats and possible values are recorded in the initial header.
# You can set as many of them as you like.
#
# EXAMPLE:
# when 1 # Waterfall
# # BGS
# s.bgs_name = 'River'
# s.bgs_radius = 15
# s.bgs_max_volume = 110
#
# Will make it so that Area 1 will emit the BGS 'River' at a max volume
# of 110% within a radius of 15 squares
#||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
when 1 # Area 1
when 4 # Area 4
#||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# !*!*! END CONFIGURABLE REGION
#////////////////////////////////////////////////////////////////////////
end
@sound_emission.rect = self.rect
@sound_emission.initialize_frame_counts
end
end
#==============================================================================
# ** RPG::Sound_Emission
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# This class holds data relating to a sound emitting area
#==============================================================================
class RPG::Sound_Emission
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Public Instance Variables
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
attr_accessor :rect
attr_accessor :bgs_name
attr_accessor :bgs_pitch
attr_accessor :bgs_radius
attr_accessor :bgs_max_volume
attr_accessor :bgm_name
attr_accessor :bgm_pitch
attr_accessor :bgm_radius
attr_accessor :bgm_max_volume
attr_accessor :se_name
attr_accessor :se_pitch
attr_accessor :se_radius
attr_accessor :se_max_volume
attr_accessor :se_frames
attr_accessor :se_frame_variance
attr_accessor :me_name
attr_accessor :me_pitch
attr_accessor :me_radius
attr_accessor :me_max_volume
attr_accessor :me_frames
attr_accessor :me_frame_variance
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Setup Sound Emissions
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def initialize
# Set Default Values
@rect = Rect.new (0, 0, 0, 0)
# Default values
@bgs_name, @bgs_pitch, @bgs_radius, @bgs_max_volume, @bgm_name, @bgm_pitch,
@bgm_radius, @bgm_max_volume, @se_name, @se_pitch, @se_radius,
@se_max_volume, @me_name, @me_pitch, @me_radius, @me_max_volume,
@se_frames, @se_frame_variance, @me_frames, @me_frame_variance = '', 100,
10, 100, '', 100, 10, 100, '', 100, 10, 100 , '', 100, 10, 100, 20, 0, 20, 0
initialize_frame_counts
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Initialize Frame Counts
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def initialize_frame_counts
@se_frame_count = @se_frames + rand (2*@se_frame_variance).floor - @se_frame_variance
@me_frame_count = @me_frames + rand (2*@me_frame_variance).floor - @me_frame_variance
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Update Sound
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def update
@stopped = false
bgm.play if @bgm_name != ''
bgs.play if @bgs_name != ''
update_se if @se_name != ''
update_me if @me_name != ''
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Stop Sound
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def stop
return if @stopped
RPG::BGM.stop if @bgm_name != ''
RPG::BGS.stop if @bgs_name != ''
@stopped = true
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * BGM
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def bgm
@bgm = RPG::BGM.new (@bgm_name, 0, @bgm_pitch) if @bgm == nil
@bgm.volume = volume (@bgm_radius, @bgm_max_volume)
return @bgm
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * BGS
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def bgs
@bgs = RPG::BGS.new (@bgs_name, 0, @bgs_pitch) if @bgs == nil
@bgs.volume = volume (@bgs_radius, @bgs_max_volume)
return @bgs
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * SE
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def se
@se = RPG::SE.new (@se_name, 0, @se_pitch) if @se == nil
@se.volume = volume (@se_radius, @se_max_volume)
return @se
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * SE Update
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def update_se
if @se_frame_count == 0
se.play
@se_frame_count = @se_frames + rand (2*@se_frame_variance).floor - @se_frame_variance
else
@se_frame_count -= 1
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * ME
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def me
@me = RPG::ME.new (@me_name, 0, @me_pitch) if @me == nil
@me.volume = volume (@me_radius, @me_max_volume)
return @me
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * ME Update
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def update_me
if @me_frame_count == 0
me.play
@me_frame_count = @me_frames + rand (2*@me_frame_variance).floor - @me_frame_variance
else
@me_frame_count -= 1
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Volume
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def volume (radius, max_volume)
x, y = $game_player.x, $game_player.y
# Determine distance between position and the sound emitting object
xd, yd = x - @rect.x, y - @rect.y
# Evaluate X distance
xd > 0 ? xd = x.between? (@rect.x, @rect.x + @rect.width) ? 0 : xd - @rect.width : xd *= -1
# Evaluate Y distance
yd > 0 ? yd = y.between? (@rect.y, @rect.y + @rect.height) ? 0 :yd - @rect.height : yd *= -1
# Calculate the total distance
total_distance = Math.sqrt(xd*xd + yd*yd).ceil.to_i
# Get the percentage of max volume
percent = (total_distance.to_f / radius.to_f)*100
percent = (100 - [percent, 100].min).to_f / 100.0
return (percent*max_volume.to_f).to_i
end
end
#==============================================================================
# ** Game_Event
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Summary of Changes:
# aliased method - setup, update
#==============================================================================
class Game_Event
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Setup
# page : the new page
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
alias ma_sound_emit_obj_stp_event_pg_85nd setup
def setup (new_page)
# Run Original Method
ma_sound_emit_obj_stp_event_pg_85nd (new_page)
@sound_emission.stop unless @sound_emission.nil?
# If page is legitimate
unless @page == nil
s = @sound_emission = RPG::Sound_Emission.new
@sound_emission.rect = Rect.new (@x, @y, 1, 1)
# Evaluate comments
comments = []
@page.list.each { |i| i.code == 108 || i.code == 408 ? comments.push (i) : break }
# Evaluate comments for \SNDEMIT codes
comments.each { |i|
text = i.parameters[0].dup
while text.sub! (/\\SNDEMIT\[(.+)\]/i) { '' } != nil
eval ("@sound_emission." + $1.to_s)
end
}
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Frame Update
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
alias modalg_snd_emssn_script_upd_evnt_4n2 update
def update
# Run Original Event
modalg_snd_emssn_script_upd_evnt_4n2
return if @sound_emission.nil?
@sound_emission.rect.x, @sound_emission.rect.y = @x, @y
@sound_emission.update
end
end
#==============================================================================
# ** Game_Map
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Summary of Changes:
# aliased method - update, setup
#==============================================================================
class Game_Map
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Setup
# map_id : the ID of the map
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
alias modalg_dynamic_snd_emit_stup_rn4 setup
def setup(map_id)
@areas.each { |area| area.sound_emission.stop } unless @areas.nil?
# Run Original Method
modalg_dynamic_snd_emit_stup_rn4 (map_id)
# Get all areas that belong to this map
@areas = []
$data_areas.values.each { |area| @areas.push (area) if map_id == area.map_id }
# Ensure Area Sound Effects are setup
@areas.each { |i| i.setup_sound_emissions if i.sound_emission == nil }
@advanced_areas = false
begin
# Test for exception thrown on .active?
$data_areas[1].active?
@advanced_areas = true
rescue
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Update
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
alias modalg_dyn_sound_emitting_objects_upd_4h3 update
def update
# Run Original Map
modalg_dyn_sound_emitting_objects_upd_4h3
# For all area
@areas.each { |area|
@advanced_areas && !area.active? ? area.sound_emission.stop : area.sound_emission.update
}
end
end
Credit
Support
Please post here for swiftest support.
Demo
See attached.
Author's Notes
This script is based off of the version I wrote for RMXP with a number of significant alterations. This script is completely compatible with my
Advanced Areas script, and I recommend it if you do not want the sounds playing all the time, as the Advanced Areas script includes a way to turn the area off by a switch and this script will recognize that command as well.
This script by
modern algebra is licensed under a
Creative Commons Attribution-Non-Commercial-Share Alike 2.5 Canada License.