Last active
December 5, 2020 18:12
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#============================================================================== | |
# 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