Archived

This topic is now archived and is closed to further replies.

ThallionDarkshine

Window Message Mod

3 posts in this topic

Window Message Mod

Authors: ThallionDarkshine

Version: 1.0

Type: Message Add-on

Key Term: Message Add-on


Introduction

This is a small Window_Message mod I made a while ago to allow letter-by-letter text. It now also includes a way to create text animations such as growing, shrinking, rotating, or shaking text. You can also format text with things like bold, underline, etc.

New feature! You can now create text gradients!

Text Animations:

  • Grow
  • Rotate (rock back and forth)
  • Shrink
  • Shake
  • Float
  • Hue Rotate
  • Bounce

Formatting Properties

  • Bold
  • Italic
  • Underline
  • Overline (pretty much useless but I made it anyways)
  • Strikethrough


Features

  • Specify how many letters are added at a time, and at what interval they are added.
  • Specify word-by-word text
  • Message shortcut to change letter-by-letter oions from default.
  • Create animated text!
  • Format text, making it bold, italic, etc.


Screenshots

I'll put some up if requested, but all this does is allow letter-by-letter text.


Demo

None yet.


Script


# Instructions on use of this scri
# - 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
# - Formatting Stuff
# Bold -
# Italic -
# Underline -
# Overline - <o></o>
# Strikethrough -
# - To create gradient text, use:
# <grad=COLOR1:COLOR2></grad>
# COLOR1 - The color id of the left side color of the text.
# COLOR2 - The color id of the right side color of the text.

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 = 2

def get_text
text = $game_temp.message_text
@wait_points = []
@wait_count = 0
if text.gsub!(/\\l(?:\[([\-\d]+)(?:\,([\-\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]\[([0-9]+)\]/, "")
unformatted.gsub!(/\\[Aa]\[(\d+)\]/, "")
unformatted.gsub!(/\<\/?[a-z]+\>/, '')
unformatted.gsub!(/\<\/?grad\=\d+\:\d+\>/, '')
unformatted.gsub!(/\\[Gg]/, '')
# Change "\\C" to "\001"
text.gsub!(/\\[Cc]\[([0-9]+)\]/) { "\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
while !(ind=unformatted.index(/\\[Ww]\[(\d+)\]/)).nil?
unformatted.sub!(/\\[Ww]\[(\d+)\]/, "")
text.sub!(/\\[Ww]\[(\d+)\]/, "")
@wait_points.push([ind, $1.to_i])
end
x, y = 0, 0
gradient = [nil, nil, 0, 0, 0, 0]
@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+)\:(\d+)\>/) == 0
gradient = [$1.to_i, $2.to_i, 4 + x, 32 * y, 0, 32]
@text = @text.split('')
@text = (@text.length == 1 ? "" : @text[0..@text.length - 2].join(''))
text.sub!(/(grad\=(\d+)\:(\d+)\>)/, '')
elsif text.index('/grad>') == 0
unless gradient[0].nil?
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])
gradient[0] = gradient[1] = nil
end
@text = @text.split('')
@text = @text[0..@text.length - 2].join('')
text.sub!(/(\/?[a-z]+\>)/, '')
end
if text.index(/\/?[a-z]+\>/) == 0
text.sub!(/(\/?[a-z]+\>)/, '')
@text += $1
end
end
if c == "\n"
unless gradient[0].nil?
gradient[4] = [gradient[3], x + 4 - gradient[1]].max
gradient[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 gradient[0].nil?
w = [animation[4], x + 4 - animation[2]].max
h = [animation[5], y * 32 - animation[3]].max
rect = Rect.new(animation[2], animation[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
end
@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
index = real_index = 0
animation = [0, 0, 0, 0, 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" }
# Change "\\C" to "\001" and "\\G" to "\002"
text.gsub!(/\\[Cc]\[([0-9]+)\]/) { "\001[#{$1}]" }
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!(/\[([0-9]+)\]/, "")
color = $1.to_i
if color >= 0 and color <= 7
self.contents.font.color = text_color(color)
end
# go to next text
next
end
if c == "\002" and @length == @text.length
if animation[0] != 0
w = [animation[3], x + 4 - animation[1]].max
h = [animation[4], y * 32 - animation[2]].max
rect = Rect.new(animation[1], animation[2], w, h)
@animations.push([animation[0], rect])
end
animation = [0, 4 + x, 32 * y, 0, 32]
if text.index(/\[(\d+)\]/) == 0
text.sub!(/\[(\d+)\]/, "")
animation[0] = $1.to_i
else
animation[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[3] = [animation[3], x + 4 - animation[1]].max
animation[4] += 32
end
# Add 1 to y
y += 1
x = 0
# Indent if choice
if y >= $game_temp.choice_start
x = 8
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
x += self.contents.text_size(c).width
index += 1
break if index > @length
end
if animation[0] != 0
w = [animation[3], x + 4 - animation[1]].max
h = [animation[4], y * 32 - animation[2]].max
rect = Rect.new(animation[1], animation[2], w, h)
@animations.push([animation[0], rect])
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.each { |i|
c1 = text_color(i[0])
c2 = text_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) }
@animations.each { |i| i.opacity = (@fade_in ? 0 : 255) }
end
end

alias tdks_message_update update
def update
if !@wait_count.nil? and @wait_count > 0
@wait_count -= 1
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 = @text[0...@length]
e_text = @text[@length...@text.length]
if e_text.index(/\w+/) == 0
e_text.sub(/(\w+)/, '')
@length += $1.length
end
e_text = @text[@length...@text.length]
if e_text.index(/[^\w]+/) == 0
e_text.sub(/([^\w]+)/, '')
@length += $1.length
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] - 1 if frames > 0
end
end
if @length >= @unformatted.length
@length = @text.length
@l_l = false
end
refresh
return
end
@animations.each { |ani| ani.update } unless @animations.nil? or @animations.emy? or @fade_out
super
# If fade in
if @fade_in
self.contents_opacity += 24
@animations.each { |i| i.opacity = self.contents_opacity } unless @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?
if self.opacity == 0
self.visible = false
@animations.each { |i| i.bitmap.dispose;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, rect, src_bitmap)
super()
@type = type
self.x, self.y, self.z = x + rect.x, y + rect.y, z
self.ox, self.oy = rect.width / 2, rect.height / 2
self.x += ox
self.y += oy
self.bitmap = Bitmap.new(rect.width, rect.height)
self.bitmap.blt(0, 0, 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
end
end
end


Instructions

You can configure default message oions. Instructions on how to configure are in the scri.

Instructions on the different message tags you can use are also in the scri.

A dll is now required for the gradient text feature. It is found here.


Compatibility

Probably won't work with any other custom message scris, but if you like, I'll try to tweak it to work with that specific scri.


Credits and Thanks

  • ThallionDarkshine


Author's Notes

A dll is now required for the gradient text feature. It is found here.

Archeia and ShinGamix like this

Share this post


Link to post
Share on other sites

Sorry for the late reply. That link you posted didn't work for me. Can you post the actual script?

Share this post


Link to post
Share on other sites

  • Recently Browsing   0 members

    No registered users viewing this page.