Skip to content

Instantly share code, notes, and snippets.

@masked-rpgmaker
Last active December 5, 2020 18:12
Show Gist options
  • Save masked-rpgmaker/ac7f09c5f383cc87d493b5141220703b to your computer and use it in GitHub Desktop.
Save masked-rpgmaker/ac7f09c5f383cc87d493b5141220703b to your computer and use it in GitHub Desktop.
Script para justificar texto nas janelas de mensagem do RPG Maker VX Ace.
#==============================================================================
# Text Justification | v1.0.1 | por Brandt
#
# para RPG Maker VX Ace
#------------------------------------------------------------------------------
# Altera a janela de mensagem do jogo para justificar o texto, preenchendo o
# máximo de espaço possível na janela.
# O script tem efeito automaticamente quando adicionado ao projeto e não
# necessita de configuração.
#==============================================================================
#==============================================================================
# ** Justification
#------------------------------------------------------------------------------
# Módulo para justificação de texto.
#==============================================================================
module Justification
#--------------------------------------------------------------------------
# * Justifica um texto de forma ótima em um bitmap
# text : o texto
# bitmap : o bitmap
#--------------------------------------------------------------------------
def justify(text, bitmap)
page_width = bitmap.width
wrapped = word_wrap(text, bitmap)
r = wrapped.map do |word_widths|
next if word_widths.empty?
next [0] if word_widths.size == 1
space_width = even_spacing(page_width, word_widths)
spaced_x_coords(space_width, word_widths)
end.compact
r
end
private
#--------------------------------------------------------------------------
# * Calcula a largura para os espaços entre as palavras de uma linha
# page_width : largura da área de desenho
# word_widths : lista de tamanhos de palavras
#--------------------------------------------------------------------------
def even_spacing(page_width, word_widths)
(page_width - word_widths.inject(&:+)) / (word_widths.size - 1).to_f
end
#--------------------------------------------------------------------------
# * Calcula as posições de cada palavra com espaçamento igual
# space_width : largura do espaçamento
# word_widths : lista de tamanhos de palavras
#--------------------------------------------------------------------------
def spaced_x_coords(space_width, word_widths)
word_widths[0...-1].inject([]) do |r, word_width|
r + [(r.last || 0) + space_width + word_width]
end.map(&:to_i)
end
#--------------------------------------------------------------------------
# * Quebra linhas em um texto de forma ótima em um bitmap
# text : o texto
# bitmap : o bitmap
#--------------------------------------------------------------------------
def word_wrap(text, bitmap)
page_width = bitmap.width
words = text.split(/\s+/).reject(&:empty?)
space_width = bitmap.text_size(' ').width
word_widths = calc_word_widths(words, bitmap)
optimal = optimize_word_wrapping(word_widths, page_width, space_width)
build_word_wrapped(word_widths, optimal)
end
#--------------------------------------------------------------------------
# * Otimiza as quebras de linha
# word_widths : larguras das palavras
# page_width : tamanho da área de desenho
# space_width : largura (mínima) dos espaços
#--------------------------------------------------------------------------
def optimize_word_wrapping(word_widths, page_width, space_width)
dp = [0] * (word_widths.size + 1)
pp = dp.dup
for i in (word_widths.size - 1).downto 0
dp[i] = 1 / 0.0
total_width = 0
for j in (i + 1)..word_widths.size
total_width += word_widths[j - 1]
v_ij = badness(page_width, total_width) + dp[j]
total_width += space_width
next if v_ij >= dp[i]
dp[i] = v_ij
pp[i] = j
end
end
pp
end
#--------------------------------------------------------------------------
# * Calcula a largura das palavras em uma lista em um bitmap
# words : as palavras
# bitmap : o bitmap
#--------------------------------------------------------------------------
def calc_word_widths(words, bitmap)
original_font_size = bitmap.font.size
word_widths = words.map do |word|
w = 0
a = word
word = word.chars.to_a
until word.empty?
c = word.shift
if c == "\e" || c == "\\"
next unless word.join =~ /^(\w)(?:\[\d+\])?/i
code = Regexp.last_match[1].upcase
case code
when 'I'
w += 24
when '{'
bitmap.font.size += 8 if contents.font.size <= 64
when '}'
bitmap.font.size -= 8 if contents.font.size >= 16
end
word = word[Regexp.last_match[0].size..-1] || []
else
w += bitmap.text_size(c).width
end
end
next if w.zero?
w + 2
end
bitmap.font.size = original_font_size
word_widths.compact
end
#--------------------------------------------------------------------------
# * Constroi uma lista de tamanhos de palavra por linha a partir de uma DP
# word_widths : larguras das palavras
# pp : ponteiros parentais da DP
#--------------------------------------------------------------------------
def build_word_wrapped(word_widths, pp)
result = []
line = []
i = 0
parent = pp[i]
while parent != word_widths.size
if i == parent
result << line.dup
line.clear
parent = pp[i]
end
line << word_widths[i]
i += 1 if parent != word_widths.size
end
rest = i..-1
result << word_widths[rest]
result
end
#--------------------------------------------------------------------------
# * Valor negativo para um arranjo de texto.
# page_width : tamanho da página.
# total_width : soma das larguras das palavras.
#--------------------------------------------------------------------------
def badness(page_width, total_width)
return 1 / 0.0 if total_width > page_width
(page_width - total_width)**3
end
end
#==============================================================================
# ** JustifiedWindow
#------------------------------------------------------------------------------
# Módulo para janelas com texto justificado.
#==============================================================================
module JustifiedWindow
include Justification
#--------------------------------------------------------------------------
# * Procedimento de mixin do módulo
# window_class : class incluindo o módulo
#--------------------------------------------------------------------------
def self.append_features(window_class)
window_class.send(:alias_method, :pc_unjustified, :process_character)
super
end
#--------------------------------------------------------------------------
# * Configuração da justificação do texto
# text : texto
#--------------------------------------------------------------------------
def setup_justification(text)
@justification = justify(text, self.contents)
@justification_line = @justification.shift
end
#--------------------------------------------------------------------------
# * Processamento de caracteres
# c : caractere
# text : texto a ser desenhado
# pos : posição de desenho {:x, :y, :new_x, :height}
#--------------------------------------------------------------------------
def process_character(c, text, pos)
if !@justification_line.nil? and c =~ /\s/
if @justification_line.empty?
@justification_line = @justification.shift
process_new_line(text, pos) unless @justification_line.nil?
else
pos[:x] = @justification_line.shift
end
text.sub!(/^\s+/, '')
else
pc_unjustified(c, text, pos)
end
end
end
#==============================================================================
# ** Window_Message
#------------------------------------------------------------------------------
# Esta janela de mensagem é usada para exibir textos.
#==============================================================================
class Window_Message < Window_Base
include JustifiedWindow
#--------------------------------------------------------------------------
# * Definição de quebra de página
# text : texto
# pos : posição
#--------------------------------------------------------------------------
alias np_unjustified new_page
def new_page(text, pos)
setup_justification(text)
np_unjustified(text, pos)
end
end
#==============================================================================
# ** Window_ScrollText
#------------------------------------------------------------------------------
# Esta janela é usada para exibir o texto rolante. Não exibe o quadro da
# janela, é tratado como uma janela por conveniência.
#==============================================================================
class Window_ScrollText < Window_Base
include JustifiedWindow
#--------------------------------------------------------------------------
# * Atualização da altura necessária para o desenho do texto completo
#--------------------------------------------------------------------------
def update_all_text_height
@all_text_height = 1
words = convert_escape_characters(@text).split(/\s+/)
line = words.shift
setup_justification(@text)
([@justification_line] + @justification).each do |justified_line|
justified_line.size.times do
line << words.shift
end
@all_text_height += calc_line_height(line, false)
line = words.shift
end
reset_font_settings
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment