#==============================================================================
# Special Codes Formatter (Addon for Paragraph Formatter 2.0)
# Version: 1.0
# Author: modern algebra (rmrk.net)
# Date: September 15, 2009
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Description:
#
# This is a formatter and artist combo that interprets and accounts for
# various special codes:
#
# \n - line break to next paragraph (Note the single \, NOT \\)
# \\v[x] - Shows the value located in the variable x
# \\n[x] - Shows the name of the Actor with ID x
# \\c[x] - Changes the colour of the text to x. x can be 0 - 31
# \\c[#hex] - Changes the colour of text to the hex value
# \\ - \
# \\pid[x] - Shows Actor ID of Party Member in position X (0-3)
# \\nc[x]- Shows the name of class with ID x
# \\np[x]- Shows the name of the Party Member with index x
# \\ne[x]- Shows the name of Event with ID x on the map
# \\nm[x]- Shows the name of Monster with ID x
# \\ni[x]- Shows the name of Item with ID x
# \\nw[x]- Shows the name of Weapon with ID x
# \\na[x]- Shows the name of Armour with ID x
# \\pi[x]- Shows the price of Item with ID x
# \\pw[x]- Shows the price of Weapon with ID x
# \\pa[x]- Shows the price of Armour with ID x
# \\iicon[x] - Shows the Icon of Item with ID x
# \\wicon[x] - Shows the Icon of Weapon with ID x
# \\aicon[x] - Shows the Icon of Armour with ID x
# \\icon[x] - Shows the Icon with ID x
# \\vocab[value] - prints vocab for that item type. Suitable values are:
# level, level_a, hp, hp_a, mp, mp_a, atk, def, spi,
# agi, weapon, armor1, armor2, armor3, armor4, weapon1,
# weapon2, attack, skill, guard, item, equip, status, save,
# game_end, fight, escape, new_game, shutdown, to_title,
# continue, cancel, gold
# \\f[key] - Show Filter phrase attached to key
# \\b - Bold ON
# \/b - Bold OFF
# \\i - Italic ON
# \/i - Italic OFF
# \\u - Underline ON
# \/u - Underline OFF
# \\s - Shadow ON
# \/s - Shadow OFF
# \\hl[x] - Highlights with color x. \\hl toggles off
# \\ac[x]- Shows class of actor with ID x
# \\a...[x] - Shows the ... of Actor X. ... can be any of the following:
# hp, maxhp, mp, maxmp, atk, def, spi, agi, exp_s, next_exp_s,
# next_rest_exp_s, level, weapon_id, armor1_id, armor2_id,
# armor3_id, armor4_id - and any other methods from Game_Actor.
# \\c - Centres text
# \\r - Sets right alignment to text
#
# It otherwise functions the same as the default Formatter and Artist combo.
# The names of the classes are:
#
# Formatter_SpecialCodes
# Artist_SpecialCodes
#==============================================================================
module Paragrapher
#============================================================================
# ** FILTERS
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# FILTERS allows you to set a filter and replace any \F[x] code with it's
# corresponding Entry in the Hash. Leave the FILTERS = {} line alone and
# below it, you can set all of the codes you will want to be able to put
# as an argument in the \F code.
#============================================================================
FILTERS = {}
FILTERS['PF3'] = '\c[1]Paragraph Formatter\c[0], Version 2.0: Formatter_SpecialCodes'
FILTERS[0] = 'Numbered filters work too'
#============================================================================
# ** Formatter 3
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This class converts a string into a formatted text object, but also
# recognizes special message codes.
#============================================================================
class Formatter_SpecialCodes < Formatter
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Format
# string : the string to convert into paragraphs
# specs : the specification, either maximum width or a bitmap
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def format (string, specs)
string = convert_special_characters (string)
@code_argument = false
@line_width = 0
@word_width = 0
@word_letter_count = 0
@line_letter_count = 0
# Run Original Method
return super (string, specs)
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Format Character
# i : index of character to format, or the character
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def format_character (i)
character = @string[i, 1]
if args_codes.include? (character)
extract_code (character)
@code_argument = true
elsif @code_argument
@code_argument = false if character == ">"
elsif no_args_codes.include? (character)
extract_code (character)
elsif character == " "
char_width = @format_text.bitmap.text_size (character).width
if @line_width + char_width + @word_width > @max_width
if @line_width == 0 # Really long word!
@last_word = i
@line_width = @word_width
end
next_line (@last_word)
else
@line_width += char_width
@line_letter_count += 1
end
@line_width += @word_width
@line_letter_count += @word_letter_count
@word_width = 0
@word_letter_count = 0
@last_word = i
elsif character == "\n" # Line break
char_width = @format_text.bitmap.text_size (" ").width
next_line (@last_word) if @line_width + char_width + @word_width > @max_width
@line_width += @word_width
@line_letter_count += @word_letter_count
next_line (i)
# Add in \n independent of system
@format_text.lines[-1].push (character)
@format_text.blank_width[-1] = 0
@word_width = 0
@last_word = i
else # Regular Character
@word_width += @format_text.bitmap.text_size(character).width
@word_letter_count += 1
if i == @string.size - 1
next_line (@last_word) if @line_width + @word_width > @max_width
end
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Proceed to Next Line
# last_word : the index of the beginning of the previous word
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def next_line (last_word)
line = @string[@line_break, last_word - @line_break]
# Adds current line to f.lines
@format_text.lines.push ( line.scan (/./) )
# Calculates the blank space left to cover in the line
line_blank = @max_width - @line_width
@format_text.blank_width.push (line_blank.to_f / (@line_letter_count.to_f) )
# Keeps track of the position in the array of each line
@line_break = last_word + 1
@line_width = 0
@line_letter_count = 0
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Convert Special Characters
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def convert_special_characters (text = @string)
return "" if text == nil
text = perform_substitution (text)
# Get substitutions
text.gsub! (/\\C\[(\d+)\]/i) { "\x01<#{$1.to_i}>" } # Palette Color
text.gsub! (/\\C\[#([\dABCDEF]+)\]/i) { "\x01<##{$1.to_s}>" } # Hex Color
text.gsub! (/\\IIC?O?N?\[(\d+)\]/i) { $1.to_i > 0 ? "\x02<#{$data_items[$1.to_i].icon_index}>" : ""} # Item Icon
text.gsub! (/\\WIC?O?N?\[(\d+)\]/i) { $1.to_i > 0 ? "\x02<#{$data_weapons[$1.to_i].icon_index}>" : ""} # Weapon Icon
text.gsub! (/\\AIC?O?N?\[(\d+)\]/i) { $1.to_i > 0 ? "\x02<#{$data_armors[$1.to_i].icon_index}>" : ""} # Armor Icon
text.gsub! (/\\IC?O?N?\[(\d+)\]/i) { "\x02<#{$1.to_s}>" } # Icon
text.gsub! (/\\B/i) { "\x03" } # Bold ON
text.gsub! (/\\I/i) { "\x04" } # Italic ON
text.gsub! (/\\S/i) { "\x05" } # Shadow ON
text.gsub! (/\\U/i) { "\x06" } # Underline ON
text.gsub! (/\/B/i) { "\x07" } # Bold OFF
text.gsub! (/\/S/i) { "\x09" } # Shadow OFF
text.gsub! (/\/I/i) { "\x08" } # Italic OFF
text.gsub! (/\/U/i) { "\x10" } # Underline OFF
text.gsub! (/\\HL\[(-*\d+)\]/i) { "\x11<#{$1.to_s}>" } # HighLight
text.gsub! (/\\HL/i) { "\x11<-1>" }
text.gsub! (/\\C/i) { "\x12<1>" } # Align Centre
text.gsub! (/\\CENTRE/i) { "\x12<1>" } # Align Centre
text.gsub! (/\\RI?G?H?T?/i) { "\x12<2>" } # Align Right
return text
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Perform Substitution
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def perform_substitution (text = @string)
text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } # Variable
# FILTERS
text.gsub!(/\\F\[["'](.+?)["']\]/i) { FILTERS[$1.to_s] }
text.gsub!(/\\F\[(.+?)\]/i) { FILTERS[$1.to_i] }
# Party ID to Actor ID
while text[/\\PID\[(\d+)\]/i] != nil
x = $1.to_i < $game_party.members.size ? $game_party.members[$1.to_i].id : 0
text.sub! (/\\PID\[(\d+)\]/i) { x.to_s }
end
# Old Codes
text.gsub!(/\\N\[([0-9]+)\]/i) { $1.to_i > 0 ? $game_actors[$1.to_i].name : ""} # Actor Name
text.gsub!(/\\\\/) { "\\" }
# New Codes
begin
text.gsub! (/\\VOCAB\[(\w+)\]/i) { Vocab.send ($1.downcase) } # Vocab
rescue
end
text.gsub! (/\\AC\[(\d+)\]/i) { $game_actors[$1.to_i].class.name } # Actor Class
# Actor Stats
begin
text.gsub! (/\\A([^\[]+?)\[(\d+)\]/i) { $game_actors[$2.to_i].send ($1.to_s.downcase) }
rescue
end
text.gsub! (/\\NC\[(\d+)\]/i) { $1.to_i > 0 ? $data_classes[$1.to_i].name : "" } # Class Name
text.gsub! (/\\NE\[(\d+)\]/i) { $1.to_i > 0 ? $game_map.events[$1.to_i].name : "" } # Event Name
text.gsub! (/\\NM\[(\d+)\]/i) { $1.to_i > 0 ? $data_enemies[$1.to_i].name : "" } # Monster Name
text.gsub! (/\\NI\[(\d+)\]/i) { $1.to_i > 0 ? $data_items[$1.to_i].name : "" } # Item Name
text.gsub! (/\\NW\[(\d+)\]/i) { $1.to_i > 0 ? $data_weapons[$1.to_i].name : "" } # Weapon Name
text.gsub! (/\\NA\[(\d+)\]/i) { $1.to_i > 0 ? $data_armors[$1.to_i].name : "" } # Armor Name
text.gsub! (/\\PI\[(\d+)\]/i) { $1.to_i > 0 ? $data_items[$1.to_i].price.to_s : "" } # Item Price
text.gsub! (/\\PW\[(\d+)\]/i) { $1.to_i > 0 ? $data_weapons[$1.to_i].price.to_s : "" } # Weapon Price
text.gsub! (/\\PA\[(\d+)\]/i) { $1.to_i > 0 ? $data_armors[$1.to_i].price.to_s : "" } # Armor Price
text.gsub! (/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } # Variable
return text
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Extract Code
# code : the code to extract
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def extract_code (code)
case code
when "\x02"
@word_letter_count += 1
@word_width += 24
when "\x03" then @format_text.bitmap.font.bold = true # Bold
when "\x04" then @format_text.bitmap.font.italic = true # Italic
when "\x05" then @format_text.bitmap.font.shadow = true # Shadow
when "\x07" then @format_text.bitmap.font.bold = false # Bold
when "\x08" then @format_text.bitmap.font.italic = false # Italic
when "\x09" then @format_text.bitmap.font.shadow = false # Shadow
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Argument Codes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def no_args_codes
return ["\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x10"]
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Argument Codes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def args_codes
return ["\x01", "\x02", "\x11", "\x12"]
end
end
#============================================================================
# ** Artist 2
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# This is an artist class designed to recognize some special message codes.
#============================================================================
class Artist_SpecialCodes
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Draw
# f : Formatted Text Object
# justify_text : boolean value on whether to justify text
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def draw (f, justify_text = true)
@f = f
@justify_text = justify_text
@highlight = -1
@underline = false
# Calculates the necessary distance between lines
line_distance = @f.bitmap.height.to_f / @f.lines.size.to_f
@line_distance = [@f.bitmap.font.size + 4, line_distance].min
# For all lines in the lines array
for i in 0...@f.lines.size
# Compose line into a single string
@text = ""
@f.lines[i].each { |char| @text += char }
@blank_space = @f.blank_width[i]
@centre = @text[/\x12<1>/] != nil
@right = @text[/\x12<2>/] != nil && !@centre
total_blank = 0
if @centre || @right
@real_bitmap = @f.bitmap.dup
@f.bitmap = Bitmap.new (@real_bitmap.width, @line_distance)
@f.bitmap.font = @real_bitmap.font.dup
@y = 0
else
@y = i*@line_distance
end
@x = 0
# For all indices of the line array
loop do
c = @text.slice!(/./m)
break if c.nil?
interpret_string (c)
end
# Align Text
if @centre || @right
blank = (@real_bitmap.width - @x)
blank /= 2 if @centre
rect = Rect.new (0, 0, @real_bitmap.width, @line_distance)
@real_bitmap.blt (blank, i*@line_distance, @f.bitmap, rect)
@real_bitmap.font = @f.bitmap.font.dup
@f.bitmap.dispose
@f.bitmap = @real_bitmap
end
end
return @f.bitmap
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Get Text Color
# n : Text color number (0-31)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def text_color(n)
x = 64 + (n % 8) * 8
y = 96 + (n / 8) * 8
windowskin = Cache.system ("Window")
return windowskin.get_pixel(x, y)
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Draw Icon
# icon_index : Icon number
# x,y : draw spot coordinates
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def draw_icon(icon_index, x, y)
bitmap = Cache.system("Iconset")
rect = Rect.new(icon_index % 16 * 24, icon_index / 16 * 24, 24, 24)
@f.bitmap.blt(x, y, bitmap, rect)
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Interpret Character
# char : the char to decode
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def interpret_string (char)
case char
when "\x01" # Colour
@text.slice! (/<(#?[\dABCDEF]+)>/i)
if $1.include? ("#")
r, g, b = $1[1, 2].to_i (16), $1[3, 2].to_i (16), $1[5, 2].to_i (16)
@f.bitmap.font.color = Color.new (r, g, b)
else
@f.bitmap.font.color = text_color ($1.to_i)
end
when "\x02" # Icon
@text.slice! (/<(\d+)>/)
draw_icon ($1.to_i, @x, @y)
@x += 24
@x += @justify_text && !@centre && !@right ? @blank_space : 0
when "\x03" then @f.bitmap.font.bold = true # Bold ON
when "\x04" then @f.bitmap.font.italic = true # Italic ON
when "\x05" then @f.bitmap.font.shadow = true # Shadow ON
when "\x06" then @underline = true # Underline ON
when "\x07" then @f.bitmap.font.bold = false # Bold OFF
when "\x08" then @f.bitmap.font.italic = false # Italic OFF
when "\x09" then @f.bitmap.font.shadow = false # Shadow OFF
when "\x10" then @underline = false # Underline OFF
when "\x11" # Highlight
@text.slice! (/<(-?\d+)>/)
@highlight = $1.to_i
when "\x12" # Centre or Right
@text.slice! (/<\d>/)
when "\n" # Draw nothing when blank space
else
draw_character (char)
end
end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# * Draw Character
# string : the string to draw
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def draw_character (string)
tw = @f.bitmap.text_size (string).width
ls = @justify_text && !@centre && !@right ? @blank_space : 0
hl_rect = Rect.new (@x, @y, tw + ls, @line_distance)
# Draw Highlight
if @highlight.between? (0, 31)
colour = text_color (@highlight)
colour.alpha = 120
contents.fill_rect (hl_rect, colour)
end
# Draw Underline
if @underline
y = @y + @line_distance - 2
@f.bitmap.fill_rect (@x, y, hl_rect.width, 2, @f.bitmap.font.color)
end
# Draws the string located at each index
@f.bitmap.draw_text (@x, @y, tw, @line_distance, string)
# Keeps track of the position we are in in pixels
@x += tw + ls
end
end
end