# Instructions on use of this script
# - To change the letter-by-letter mode, use:
# \l[CHAR_AMOUNT, FRAMES]
# CHAR_AMOUNT - How many chars to add to the string every time it updates
# note - Use 0 for word-by-word or any negative number for no letter-by-letter
# FRAMES - How often to add CHAR_AMOUNT characters to the string
# - To create animated text, use:
# \a[TYPE]
# TYPE - Which type of animation the text should have
# 0 - Turn off Animation
# 1 - Grow
# 2 - Rock
# 3 - Shrink
# 4 - Shake
# 5 - Float
# 6 - Color Rotate
# 7 - Bounce
# 8 - Fade
# 9 - Letter Grow (one at a time)
# 10 - Letter Grow (two at a time)
# 11 - Letter Swivel
# 12 - Letter Colorize
# 13 - Letter Fade (one at a time)
# 14 - Letter Fade (two at a time)
# 15 - Letter Shrink (one at a time)
# 16 - Letter Shrink (two at a time)
# 17 - Letter Bounce
# 18 - Letter Float
# note - you can use simply \a to turn off the animation
# - Formatting Stuff
# Bold - <b></b>
# Italic - <i></i>
# Underline - <u></u>
# Overline - <o></o>
# Strikethrough - <s></s>
# - To create gradient text, use:
# <grad=COLOR1:COLOR2></grad>
# COLOR1 - The left color.
# COLOR2 - The right color.
# note - colors can be specified either as RED, GREEN, BLUE or as COLOR_ID
# or as #RRGGBB (hexadecimal)
# - The \c[COLOR] command now allows you to specify colors as either RED, GREEN,
# BLUE or as COLOR_ID or as #RRGGBB (hexadecimal)
# - To make the letter-by-letter feature wait for a certain length at a some
# point in the message, use:
# \w[DURATION]
# DURATION - How long to delay. Use 0 to wait for the accept button to
# be pressed.
# note - You can also use simply \w to wait for the accept button to be
# pressed.
class Window_Message
# text mode:
# 0 - Normal
# 1 - Letter-by-Letter
# 2 - Word-by-Word
DEFAULT_MODE = 1
# default amount of characters at a time
DEFAULT_CHARS = 1
# default number of frames to characters
DEFAULT_FRAMES = 5
def get_text
text = $game_temp.message_text
@wait_points = []
@wait_count = nil
if text.gsub!(/\\l(?:\[([\-\d]+)(?:\s*\,\s*([\-\d]+))?\])?/, '') != nil
@l_l = true
@l_amnt = $1.nil? ? Window_Message::DEFAULT_CHARS : $1.to_i
@l_frames = $2.nil? ? Window_Message::DEFAULT_FRAMES : $2.to_i
@frames = 0
@length = 0
if @l_amnt < 0
@l_l = false
end
else
case Window_Message::DEFAULT_MODE
when 0:
@l_l = false
when 1:
@l_l = true
@l_amnt = Window_Message::DEFAULT_CHARS
@l_frames = Window_Message::DEFAULT_FRAMES
@frames = 0
@length = 0
when 2:
@l_l = true
@l_amnt = 0
@l_frames = Window_Message::DEFAULT_FRAMES
@frames = 0
@length = 0
end
end
@text = ""
begin
last_text = text.clone
text.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
end until text == last_text
text.gsub!(/\\[Nn]\[([0-9]+)\]/) do
$game_actors[$1.to_i] != nil ? $game_actors[$1.to_i].name : ""
end
# Change "\\\\" to "\000" for convenience
text.gsub!(/\\\\/) { "\000" }
unformatted = text.clone
unformatted.gsub!(/\\[Cc]\[((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\]/, "")
unformatted.gsub!(/\\[Aa]\[(\d+)\]/, "")
unformatted.gsub!(/\<\/?[a-z]+\>/, '')
unformatted.gsub!(/\<\/?grad\=((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\:((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\>/, '')
unformatted.gsub!(/\\[Gg]/, '')
# Change "\\C" to "\001"
text.gsub!(/\\[Cc]\[((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\]/) { "\001[#{$1}]" }
if text.gsub!(/\\[Gg]/, '') != nil and @l_l
@gold_window = Window_Gold.new
@gold_window.x = 560 - @gold_window.width
if $game_temp.in_battle
@gold_window.y = 192
else
@gold_window.y = self.y >= 128 ? 32 : 384
end
@gold_window.opacity = self.opacity
@gold_window.back_opacity = self.back_opacity
end
tmp = unformatted.gsub(/[\n\r]/, '')
while !(ind=tmp.index(/\\[Ww](?:\[(\d+)\])?/)).nil?
unformatted.sub!(/\\[Ww](?:\[(\d+)\])?/, "")
tmp.sub!(/\\[Ww](?:\[(\d+)\])?/, "")
text.sub!(/\\[Ww](?:\[(\d+)\])?/, "")
@wait_points.push([ind, ($1.nil? ? 0 : $1.to_i)])
end
x, y = 0, 0
gradients = []
@gradients = []
# Get 1 text character in c (loop until unable to get text)
while ((c = text.slice!(/./m)) != nil)
@text += c
if c == "\001" or c == "\002"
next
end
if c == "<"
if text.index(/grad\=((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\:((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\>/) == 0
gradient = [$1, $2, 4 + x, 32 * y, 0, 32]
gradients.push(gradient)
@text = @text.split('')
@text = (@text.length == 1 ? "" : @text[0..@text.length - 2].join(''))
text.sub!(/(grad\=((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\:((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\>)/, '')
next
elsif text.index('/grad>') == 0
unless gradients.length == 0 or gradients.last[0].nil?
gradient = gradients.pop()
w = [gradient[4], x + 4 - gradient[2]].max
h = [gradient[5], y * 32 - gradient[3]].max
rect = Rect.new(gradient[2], gradient[3], w, h)
@gradients.push([gradient[0], gradient[1], rect])
end
@text = @text.split('')
@text = @text[0..@text.length - 2].join('')
text.sub!(/(\/?[a-z]+\>)/, '')
next
end
if text.index(/\/?[a-z]+\>/) == 0
text.sub!(/(\/?[a-z]+\>)/, '')
@text += $1
end
end
if c == "\n"
unless gradients.length == 0 or gradients.last[0].nil?
gradients[-1][4] = [gradients[-1][3], x + 4 - gradients[-1][1]].max
gradients[-1][5] += 32
end
x = 0
y += 32
if y >= $game_temp.choice_start
x = 8
end
end
x += self.contents.text_size(c).width
end
unless gradients.length == 0 or gradients.last[0].nil?
gradient = gradients.pop()
w = [gradient[4], x + 4 - gradient[2]].max
h = [gradient[5], y * 32 - gradient[3]].max
rect = Rect.new(gradient[2], gradient[3], w, h)
@gradients.push([gradient[0], gradient[1], rect])
end
@unformatted = unformatted.clone
@length = unformatted.length unless @l_l
end
alias tdks_message_refresh refresh
def refresh
if !$game_temp.message_text.nil?
get_text
@animations.each { |ani| ani.bitmap.dispose;ani.dispose } unless @animations.nil?
@letter_animations.each { |ani| ani.dispose } unless @letter_animations.nil?
end
@animations = []
@letter_animations = []
self.contents.clear
self.contents.font.color = normal_color
x = y = 0
@cursor_width = 0
# Indent if choice
if $game_temp.choice_start == 0
x = 8
end
# If waiting for a message to be displayed
if @text != nil
self.contents.font = Font.new
self.contents.font.underline = false
self.contents.font.overline = false
self.contents.font.strikethrough = false
text = @text.clone
real_index = 0
index = 1
animation = [0, []]
lanimation = [0, []]
p_bold = p_italic = p_underline = p_overline = p_strikethrough = []
# Control text processing
begin
last_text = text.clone
text.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
end until text == last_text
text.gsub!(/\\[Nn]\[([0-9]+)\]/) do
$game_actors[$1.to_i] != nil ? $game_actors[$1.to_i].name : ""
end
# Change "\\\\" to "\000" for convenience
text.gsub!(/\\\\/) { "\000" }
if @length == @text.length
text.gsub!(/\\[Aa]/) { "\002" }
else
text.gsub!(/\\[Aa](?:\[(\d+)\])?/, "")
end
# Get 1 text character in c (loop until unable to get text)
while ((c = text.slice!(/./m)) != nil)
break if @length == 0
real_index += 1
# If \\
if c == "\000"
# Return to original text
c = "\\"
end
# If \C[n]
if c == "\001"
# Change text color
text.sub!(/\[((?:\d+(?:\s*\,\s*\d+)*)|(?:\#[\da-f]{6}))\]/, "")
self.contents.font.color = get_color($1)
# go to next text
next
end
if c == "\002" and @length == @text.length
if animation[0] != 0
animation[1][-1].width = x + 4 - animation[1][-1].x
@animations.push(animation)
elsif lanimation[0] != 0
@letter_animations.push(lanimation)
end
animation = [0, []]
lanimation = [0, []]
if text.index(/\[(\d+)\]/) == 0
text.sub!(/\[(\d+)\]/, "")
type = $1.to_i
if type == 0
animation[1] = []
elsif type <= 8
animation[0] = $1.to_i
animation[1].push(Rect.new(4 + x, 32 * y, 0, 32))
else
lanimation[0] = $1.to_i - 8
end
else
animation[0] = 0
lanimation[0] = 0
end
next
end
if c == "<"
if text.index('b>') == 0
p_bold.push(self.contents.font.bold)
self.contents.font.bold = true
elsif text.index('i>') == 0
p_italic.push(self.contents.font.italic)
self.contents.font.italic = true
elsif text.index('u>') == 0
p_underline.push(self.contents.font.underline)
self.contents.font.underline = true
elsif text.index('o>') == 0
p_overline.push(self.contents.font.overline)
self.contents.font.overline = true
elsif text.index('s>') == 0
p_strikethrough.push(self.contents.font.strikethrough)
self.contents.font.strikethrough = true
end
if text.index('/b>') == 0
self.contents.font.bold = p_bold.pop
elsif text.index('/i>') == 0
self.contents.font.italic = p_italic.pop
elsif text.index('/u>') == 0
self.contents.font.underline = p_underline.pop
elsif text.index('/o>') == 0
self.contents.font.overline = p_overline.pop
elsif text.index('/s>') == 0
self.contents.font.strikethrough = p_strikethrough.pop
end
font = self.contents.font
if text.index(/\/?[a-z]+\>/) == 0
text.sub!(/\/?[a-z]+\>/, '')
next
end
end
# If new line text
if c == "\n"
# Update cursor width if choice
if y >= $game_temp.choice_start
@cursor_width = [@cursor_width, x].max
end
if animation[0] != 0
animation[1][-1].width = x + 4 - animation[1][-1].x
end
# Add 1 to y
y += 1
x = 0
# Indent if choice
if y >= $game_temp.choice_start
x = 8
end
if animation[0] != 0
animation[1].push(Rect.new(x + 4, y * 32, 0, 32))
end
# go to next text
next
end
# Draw text
self.contents.draw_text(4 + x, 32 * y, 40, 32, c)
# Add x to drawn text width
size = self.contents.text_size(c)
if lanimation[0] != 0
lanimation[1].push(Rect.new(x + 4, y * 32, size.width, 32))
end
x += size.width
index += 1
break if index > @length
end
if animation[0] != 0
animation[1][-1].width = x + 4 - animation[1][-1].x
@animations.push(animation)
elsif lanimation[0] != 0
@letter_animations.push(lanimation)
end
end
# If choice
if $game_temp.choice_max > 0
@item_max = $game_temp.choice_max
self.active = true
self.index = 0
end
# If number input
if $game_temp.num_input_variable_id > 0
digits_max = $game_temp.num_input_digits_max
number = $game_variables[$game_temp.num_input_variable_id]
@input_number_window = Window_InputNumber.new(digits_max)
@input_number_window.number = number
@input_number_window.x = self.x + 8
@input_number_window.y = self.y + $game_temp.num_input_start * 32
end
$game_temp.message_text = nil
overlay_grad = Win32API.new('overlay_grad.dll', 'overlay_grad', 'liiiiiiiiii', 'b')
@gradients.reverse.each { |i|
c1 = get_color(i[0])
c2 = get_color(i[1])
overlay_grad.call(self.contents.__id__, i[2].x, i[2].y, i[2].width, i[2].height, c1.red, c1.green, c1.blue, c2.red, c2.green, c2.blue)
}
if @length == @text.length
@animations = @animations.map { |ani| AnimationSprite.new(ani[0], self.x + 16, self.y + 16, self.z + 1, ani[1], self.contents) }
@letter_animations = @letter_animations.map { |ani| AnimationLetters.new(ani[0], self.x + 16, self.y + 16, self.z + 1, ani[1], self.contents) }
@animations.each { |i| i.opacity = (@fade_in ? 0 : 255) }
@letter_animations.each { |i| i.opacity = (@fade_in ? 0 : 255) }
end
end
def get_color(str)
if !str.index(',').nil?
return Color.new(*str.split(/\s*\,\s*/))
elsif str[0..0] == '#'
return Color.new(str[1..2].hex, str[3..4].hex, str[5..6].hex)
else
return text_color(str.to_i)
end
end
alias tdks_message_update update
def update
super
if !@wait_count.nil?
if @wait_count > 0
@wait_count -= 1
@wait_count = nil if @wait_count == 0
else
self.pause = true if !self.pause
@wait_count = nil if Input.trigger?(Input::C)
end
return
end
# If letter-by-letter
if !(@fade_in or (@fade_out == false and $game_temp.message_text != nil)) and @l_l and self.contents_opacity == 255
@frames += 1
if Input.trigger?(Input::C)
@length = @text.length
end
return unless @frames % @l_frames == 0
prev_len = @length
unless @l_amnt == 0
@length = [@length + @l_amnt, @text.length].min
else
s_text = @unformatted[0...@length]
e_text = @unformatted[@length...@unformatted.length].clone
e_text.gsub!(/\A[\n\r]+/, '')
if e_text.index(/\w+/) == 0
e_text.sub(/(\w+)/, '')
@length += $1.length
e_text = @unformatted[@length...@unformatted.length]
if e_text.index(/[^\w]+/) == 0
e_text.sub(/([^\w]+)/, '')
tmp = $1.gsub(/[\n\r]/, '')
@length += tmp.length
end
elsif e_text.index(/[^\w]+/) == 0
e_text.sub(/([^\w]+)/, '')
tmp = $1.gsub(/[\n\r]/, '')
@length += tmp.length
e_text = @unformatted[@length...@unformatted.length]
if e_text.index(/\w+/) == 0
e_text.sub(/(\w+)/, '')
@length += $1.length
end
end
end
unless Input.trigger?(Input::C)
if (wait = @wait_points.detect { |i| i[0].between?(prev_len, @length) }) != nil
frames = wait[1]
@wait_points.delete(wait)
@wait_count = frames
@length = wait[0]
end
end
len = @unformatted.gsub(/[\n\r]/, '').length
if @length >= len
@length = @text.length
@l_l = false
end
refresh
return
end
@animations.each { |ani| ani.update } unless @animations.nil? or @animations.empty? or @fade_out
@letter_animations.each { |ani| ani.update } unless @letter_animations.nil? or @fade_out
# If fade in
if @fade_in
self.contents_opacity += 24
@animations.each { |i| i.opacity = self.contents_opacity } unless @animations.nil?
@letter_animations.each { |i| i.opacity = self.contents_opacity } unless @letter_animations.nil?
if @input_number_window != nil
@input_number_window.contents_opacity += 24
end
if self.contents_opacity == 255
@fade_in = false
end
return
end
# If inputting number
if @input_number_window != nil
@input_number_window.update
# Confirm
if Input.trigger?(Input::C)
$game_system.se_play($data_system.decision_se)
$game_variables[$game_temp.num_input_variable_id] =
@input_number_window.number
$game_map.need_refresh = true
# Dispose of number input window
@input_number_window.dispose
@input_number_window = nil
terminate_message
end
return
end
# If message is being displayed
if @contents_showing
# If choice isn't being displayed, show pause sign
if $game_temp.choice_max == 0
self.pause = true
end
# Cancel
if Input.trigger?(Input::B)
if $game_temp.choice_max > 0 and $game_temp.choice_cancel_type > 0
$game_system.se_play($data_system.cancel_se)
$game_temp.choice_proc.call($game_temp.choice_cancel_type - 1)
terminate_message
end
end
# Confirm
if Input.trigger?(Input::C)
if $game_temp.choice_max > 0
$game_system.se_play($data_system.decision_se)
$game_temp.choice_proc.call(self.index)
end
terminate_message
end
return
end
# If display wait message or choice exists when not fading out
if @fade_out == false and $game_temp.message_text != nil
@contents_showing = true
$game_temp.message_window_showing = true
reset_window
@fade_in = true
refresh
Graphics.frame_reset
self.visible = true
self.contents_opacity = 0
if @input_number_window != nil
@input_number_window.contents_opacity = 0
end
return
end
# If message which should be displayed is not shown, but window is visible
if self.visible
@fade_out = true
self.opacity -= 48
@animations.each { |i| i.opacity = self.opacity } unless @animations.nil?
@letter_animations.each { |i| i.opacity = self.opacity } unless @letter_animations.nil?
if self.opacity == 0
self.visible = false
@animations.each { |i| i.bitmap.dispose;i.dispose }
@letter_animations.each { |i| i.dispose }
@fade_out = false
$game_temp.message_window_showing = false
end
return
end
end
end
class Font
attr_accessor :underline, :overline, :strikethrough
attr_accessor :outline, :outline_color, :outline_distance
attr_accessor :shadow, :shadow_color, :shadow_ox, :shadow_oy
alias tdks_message_init initialize
def initialize(*args)
tdks_message_init(*args)
@underline = false
@overline = false
@strikethrough = false
@outline, @outline_color, @outline_distance = false, Color.new(0, 0, 0), 0
@shadow, @shadow_color, @shadow_ox, @shadow_oy = false, Color.new(127, 127, 127, 170), 2, 2
end
end
class Bitmap
alias tdks_message_draw_text draw_text
def draw_text(*args)
unless args[0].is_a?(Rect)
args[0..3] = Rect.new(*args[0..3])
end
args[2] = 0 if args[2].nil?
args[3] = 1 if args[3].nil?
case args[3]
when 0
args[0].height = text_size(args[1]).height
when 1
h = text_size(args[1]).height
args[0].y += (args[0].height - h) / 2
args[0].height = h
when 2
h = text_size(args[1]).height
args[0].y += args[0].height
args[0].height = h
end
text = args[1].clone
text = text.split(/[\n\r]/)
rect = args[0].clone
case args[3]
when 1
amnt = (text.length / 2.0).floor
text[0...amnt].each { |ln| rect.y -= text_size(ln).height } if amnt > 0
rect.y += text_size(text[0]).height / 2 if amnt % 2 == 1
when 2
text.each { |ln| rect.y -= text_size(ln).height }
end
text.each { |ln|
orig_x = rect.x
size = text_size(ln)
case args[2]
when 1
rect.x += (rect.width - size.width) / 2
when 2
rect.x += rect.width - size.width
end
if font.shadow
prev_color = font.color.clone
font.color = font.shadow_color
tdks_message_draw_text(rect.x + font.shadow_ox, rect.y + font.shadow_oy, rect.width, rect.height, ln)
font.color = prev_color
end
if font.outline
prev_color = font.color.clone
font.color = font.outline_color
(-font.outline_distance..font.outline_distance).each { |ox|
(-font.outline_distance..font.outline_distance).each { |oy|
next if ox == 0 and oy == 0
tdks_message_draw_text(rect.x + ox, rect.y + oy, rect.width, rect.height, ln)
}
}
font.color = prev_color
end
tdks_message_draw_text(rect, ln)
if font.overline
fill_rect(rect.x, rect.y + (size.height / 15.0).ceil, size.width, (size.height / 15.0).ceil, font.color)
end
if font.strikethrough
fill_rect(rect.x, rect.y + size.height / 2, size.width, (size.height / 15.0).ceil, font.color)
end
rect.y += size.height
if font.underline
fill_rect(rect.x, rect.y - (2 * size.height / 15.0).ceil, size.width, (size.height / 15.0).ceil, font.color)
end
rect.x = orig_x
}
end
def draw_gradient_text(c1, c2, *args)
unless args[0].is_a?(Rect)
args[0..3] = Rect.new(*args[0..3])
end
rect = args[0]
tmp = Bitmap.new(rect.width, rect.height)
tmp.draw_text(tmp.rect, *args[1...args.length])
overlay_grad = Win32API.new('overlay_grad.dll', 'overlay_grad', 'liiiiiiiiii', 'b')
overlay_grad.call(tmp.__id__, args[0].x, args[0].y, args[0].width, args[0].height, c1.red, c1.green, c1.blue, c2.red, c2.green, c2.blue)
blt(rect.x, rect.y, tmp, tmp.rect)
end
end
class AnimationSprite < Sprite
def initialize(type, x, y, z, rects, src_bitmap)
super()
@type = type
rects.delete_if { |rect| rect.width == 0 or rect.height == 0 }
ry = rects.min { |i, e| i.y <=> e.y }.y
rx = rects.min { |i, e| i.x <=> e.x }.x
h = rects.max { |i, e| i.y + i.height <=> e.y + e.height }
h = h.y + h.height - ry
w = rects.max { |i, e| i.x + i.width <=> e.x + e.width }
w = w.x + w.width - rx
self.x, self.y, self.z = x + rx, y + ry, z
self.ox, self.oy = w / 2, h / 2
self.x += ox
self.y += oy
self.bitmap = Bitmap.new(w, h)
rects.each { |rect|
bitmap.blt(rect.x - rx, rect.y - ry, src_bitmap, rect)
src_bitmap.fill_rect(rect, Color.new(0, 0, 0, 0))
}
@frames = 0
@fplus = 1
case @type
when 4:
@shake = [0, 0]
@shaked = 1
when 6:
@frames = -40
when 7:
@frames = 2
end
end
def update
return if self.disposed?
@frames += @fplus
case @type
when 1:
z = 1.0 + @frames * 0.1 / 20
@fplus = -1 if @frames == 20
@fplus = 1 if @frames == 0
self.zoom_x = z
self.zoom_y = z
when 2:
a = @frames * 5.0 / 12
@fplus = -1 if @frames == 12
@fplus = 1 if @frames == -12
self.angle = a
when 3:
z = 1.0 - @frames * 0.1 / 20
@fplus = -1 if @frames == 20
@fplus = 1 if @frames == 0
self.zoom_x = z
self.zoom_y = z
when 4:
shake_power = 1
shake_speed = 10
delta = (shake_power * shake_speed * @fplus) / 15.0 + rand(3) - 1
@shake[0] += delta
if @shake[0] > shake_power
@fplus = -1
end
if @shake[0] < - shake_power
@fplus = 1
end
delta = (shake_power * shake_speed * @shaked) / 15.0 + rand(3) - 1
@shake[1] += delta
if @shake[1] > shake_power
@shaked = -1
end
if @shake[1] < - shake_power
@shaked = 1
end
self.ox = self.bitmap.width / 2 + @shake[0]
self.oy = self.bitmap.height / 2 + @shake[1]
when 5:
amnt = 5
amnt *= Math.sin(Math::PI * @frames / 30.0)
self.oy = self.bitmap.height / 2 + amnt
when 6:
if @frames < 0
a = 255 + @frames * 255 / 40
self.color.set(255, 0, 0, a)
return
end
r = g = b = 0
tmp = (@frames % 360) * 255 / 360
while tmp < 0
tmp += 255
end
if tmp < 85
g = tmp * 3
r = (85 - tmp) * 3
elsif tmp < 170
b = (tmp - 85) * 3
g = (170 - tmp) * 3
else
r = (tmp - 170) * 3
b = (255 - tmp) * 3
end
self.color.set(r, g, b)
when 7:
amnt = 10
amnt *= Math.sin(Math::PI * @frames / 30.0).abs
self.oy = self.bitmap.height / 2 + amnt - 5
when 8:
self.opacity = 255 - 170 * @frames / 20
@fplus = -1 if @frames == 20
@fplus = 1 if @frames == 0
end
end
end
class AnimationLetters
def initialize(type, x, y, z, rects, src_bitmap)
@type = type
@sprites = []
@data = []
tmp_data = get_tmp_data(type, rects.length)
rects.each { |rect|
sprite = Sprite.new
sprite.x, sprite.y, sprite.z = x + rect.x, y + rect.y, z
sprite.bitmap = Bitmap.new(rect.width, rect.height)
sprite.bitmap.blt(0, 0, src_bitmap, rect)
sprite.ox, sprite.oy = rect.width / 2, rect.height / 2
sprite.x += sprite.ox
sprite.y += sprite.oy
src_bitmap.fill_rect(rect, Color.new(0, 0, 0, 0))
@sprites.push(sprite)
@data.push(get_data(type, tmp_data))
}
case @type
when 4:
@frames = -40
else
@frames = 0
end
@fplus = 1
end
def get_tmp_data(type, length)
case type
when 1, 5, 7:
data = Array.new(length) { |i| i }
@duration = length * 31
@no_end = true
when 2, 6, 8:
len = (length / 2.0).floor
data = Array.new(len) { |i| i }
data = data.concat(data.clone)
if len % 2 == 1
data.push(rand(len))
end
@duration = len * 31
@no_end = true
when 9, 10:
data = Array.new(length) { |i| i }
when 11, 12:
tmp = Array.new(length) { |i| i }
data = []
length.times {
ind = rand(tmp.length)
data.push(tmp[ind])
tmp.delete_at(ind)
}
else
data = []
end
data
end
def get_data(type, tmp_data)
data = {}
case type
when 1, 2, 5, 6, 7, 8:
tmp = rand(tmp_data.length)
data[:start] = tmp_data[tmp] * 31 + rand(11) - 5
data[:middle] = data[:start] + 15
while data[:start] < 0
data[:start] += @duration
end
data[:end] = (data[:middle] + 15) % @duration
tmp_data.delete_at(tmp)
when 4:
data[:hue] = rand(255)
data[:mod] = rand(5) - 2
while data[:mod] == 0
data[:mod] = rand(5) - 2
end
when 9, 10, 11, 12:
data[:end] = false
len = tmp_data.length
ind = tmp_data.shift
len += ind
data[:offset] = -ind * Math::PI / len
end
data
end
def update
return if @sprites.any? { |i| i.disposed? }
@frames += @fplus
case @type
when 1, 2:
@frames %= @duration
@sprites.each_with_index { |sprite, i|
data = @data[i]
cur_frames = @frames
start = data[:start]
middle = data[:middle]
endf = data[:end]
while endf < start
endf += @duration
end
while middle < start
middle += @duration
end
while cur_frames < start
cur_frames += @duration
end
while cur_frames > endf
cur_frames -= @duration
end
while (cur_frames - start) > @duration
cur_frames -= @duration
end
while (start - cur_frames) > @duration
cur_frames += @duration
end
if cur_frames.between?(start, middle)
@no_end = false
z = 1.0 + (cur_frames - start) * 0.5 / (middle - start)
sprite.zoom_x = sprite.zoom_y = z
elsif cur_frames.between?(middle, endf) and !@no_end
z = 1.0 + (endf - cur_frames) * 0.5 / (endf - middle)
sprite.zoom_x = sprite.zoom_y = z
else
sprite.zoom_x = sprite.zoom_y = 1.0
end
mod = rand(5) - 2
@data[i][:start] += mod
@data[i][:middle] += mod
@data[i][:end] += mod
}
when 3:
a = @frames * 10.0 / 12
@fplus = -1 if @frames == 30
@fplus = 1 if @frames == -30
@sprites.each { |i| i.angle = a }
when 4:
if @frames < 0
a = 255 + @frames * 255 / 40
@sprites.each_with_index { |sprite, i|
@data[i][:hue] += @data[i][:mod]
color = get_color(@data[i][:hue])
color.alpha = a
sprite.color = color
}
return
end
@sprites.each_with_index { |sprite, i|
@data[i][:hue] += @data[i][:mod]
color = get_color(@data[i][:hue])
sprite.color = color
}
when 5, 6:
@frames %= @duration
@sprites.each_with_index { |sprite, i|
data = @data[i]
cur_frames = @frames
start = data[:start]
middle = data[:middle]
endf = data[:end]
while endf < start
endf += @duration
end
while middle < start
middle += @duration
end
while cur_frames < start
cur_frames += @duration
end
while cur_frames > endf
cur_frames -= @duration
end
while (cur_frames - start) > @duration
cur_frames -= @duration
end
while (start - cur_frames) > @duration
cur_frames += @duration
end
if cur_frames.between?(start, middle)
@no_end = false
sprite.opacity = 255 - (cur_frames - start) * 170 / (middle - start)
elsif cur_frames.between?(middle, endf) and !@no_end
sprite.opacity = 255 - (endf - cur_frames) * 170 / (endf - middle)
else
sprite.opacity = 255
end
mod = rand(5) - 2
@data[i][:start] += mod
@data[i][:middle] += mod
@data[i][:end] += mod
}
when 7, 8:
@frames %= @duration
@sprites.each_with_index { |sprite, i|
data = @data[i]
cur_frames = @frames
start = data[:start]
middle = data[:middle]
endf = data[:end]
while endf < start
endf += @duration
end
while middle < start
middle += @duration
end
while cur_frames < start
cur_frames += @duration
end
while cur_frames > endf
cur_frames -= @duration
end
while (cur_frames - start) > @duration
cur_frames -= @duration
end
while (start - cur_frames) > @duration
cur_frames += @duration
end
if cur_frames.between?(start, middle)
@no_end = false
z = 1.0 - (cur_frames - start) * 0.5 / (middle - start)
sprite.zoom_x = sprite.zoom_y = z
elsif cur_frames.between?(middle, endf) and !@no_end
z = 1.0 - (endf - cur_frames) * 0.5 / (endf - middle)
sprite.zoom_x = sprite.zoom_y = z
else
sprite.zoom_x = sprite.zoom_y = 1.0
end
mod = rand(5) - 2
@data[i][:start] += mod
@data[i][:middle] += mod
@data[i][:end] += mod
}
when 9, 11:
@sprites.each_with_index { |sprite, i|
data = @data[i]
mod = 10 * Math.sin(Math::PI * @frames / 45.0 + data[:offset]).abs - 5
mod2 = 10 * Math.sin(Math::PI * (@frames + 1) / 45.0 + data[:offset]).abs - 5
if mod > 0 and mod <= 10 * Math.sin(Math::PI * 6 / 30.0).abs - 5 and mod2 > 0
@data[i][:end] = true
else
next unless @data[i][:end]
end
sprite.oy = sprite.bitmap.height / 2 + mod
}
when 10, 12:
@sprites.each_with_index { |sprite, i|
data = @data[i]
mod = 5 * Math.sin(Math::PI * @frames / 30.0 + data[:offset])
mod2 = 5 * Math.sin(Math::PI * (@frames + 1) / 30.0 + data[:offset])
#p 10 * Math.sin(Math::PI * 2 * 3 / 30.0) - 5
#p mod
if mod > 0 and mod <= 5 * Math.sin(Math::PI * 6 / 30.0) and mod2 > 0
@data[i][:end] = true
else
next unless @data[i][:end]
end
sprite.oy = sprite.bitmap.height / 2 + mod
}
end
end
def get_color(hue)
r = g = b = 0
tmp = hue % 255
while tmp < 0
tmp += 255
end
if tmp < 85
g = tmp * 3
r = (85 - tmp) * 3
elsif tmp < 170
b = (tmp - 85) * 3
g = (170 - tmp) * 3
else
r = (tmp - 170) * 3
b = (255 - tmp) * 3
end
return Color.new(r, g, b)
end
def opacity=(val)
@sprites.each { |i| i.opacity = val }
end
def dispose
@sprites.each { |i| i.bitmap.dispose;i.dispose }
end
end