Advanced Message Window v1.0
 
  
 
Предисловие:
Данный скрипт, расширяющий доступные методы вывода сообщения в RPG Maker XP, как и все, что вышло из под моей клавиатуры, является сырым и некачественным, изобилующим глюками и недоработками. Однако, оные звери достаточно успешно прячутся от моего взора, а потому обо всех найденных экземплярах следует немедленно сообщать - буду истреблять.
Описание:
Данный скрипт представляет собой новый класс для вывода текстовых сообщений. Умеет показывать лица любых размеров, как из файла, так и из набора лиц, а так же выводить имя говорящего. Кроме того самостоятельно переносит не помещающиеся строки и оборудован прокруткой содержимого окна, так что в теории вы можете запихнуть в него текста на 65535 пикселей по высоте. Теоретически, потому что используется мой кривенький метод переноса из библиотеки EKLib, который все еще не научился быстро работать с большими объемами текста. Поэтому строго рекомендуется не выводить с помощью данного скрипта сообщения, длина которых превышает пять стандартных - будут заметные задержки. Ну, а если вы попытаетесь впихнуть сюда Войну и Мир, то игра благополучно закроется через десять секунд простоя. Кроме того, даже если в последствии скрипты будут модернизированы и задержки не будет, все же не рекомендуется собирать через чур длинные сообщения - это плохо скажется на динамичности игры.
Теперь о грустном. Пока не реализована система замен и управления текстом (вернее, замены на каком то этапе, вдруг, перестали работать). А так же еще часть мелких, нужных в хозяйстве деталей. Все это обязательно появится, как только появится свободное время.
Особенности:
В следствии довольно сложных настроек данного скрипта, которых в будущем станет еще больше, пришлось написать отдельную программу, генерирующую код для вставки в Script... события. Программа не требует установки и проста в управлении. Умеет запоминать настройки, в неограниченном количестве, так что в целом использовать ее должно быть удобно. Любые предложения, как по скрипту, так и по проге будут рассмотрены и, возможно, реализованы (для особо внимательных: да, скриншоты от разных версий, но снимать заново было лень ^^).
В следующих версиях планирую:
- Исправить замену.
- Доработать окно вывода имени.
- Прикрутить методы управления текстом.
Требования:
- Наличие EKLib v2.1
- Наличие EKLib Addon - Window Double v1.0
Работоспособность с более поздними версиями не гарантируется.
Установка:
В редакторе скриптов:
- Создайте чистую страницу над "Main" и скопируйте туда данный скрипт.
- В классе Scene_Map, в начале метода main вставить строку:
 
	Код: $advance_message_window = Window_Dialogue_Advance.new 
 В конце метода:
 
	Код: $advance_message_window.dispose 
 Пример:
 
	Код: #----------------------------------------------------------------------------
  def main
    @spriteset = Spriteset_Map.new
    #-----
    $advance_message_window = Window_Dialogue_Advance.new
    #-----
    @message_window = Window_Message.new
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      if $scene != self
        break
      end
    end
    Graphics.freeze
    @spriteset.dispose
    #-----
    $advance_message_window.dispose
    #-----
    @message_window.dispose
    if $scene.is_a?(Scene_Title)
      Graphics.transition
      Graphics.freeze
    end
  end
#----------------------------------------------------------------------------
 
- В методе update, после цикла (loop):
 
	Код: $advance_message_window.update if $advance_message_window.visible 
 Пример:
 
	Код: #----------------------------------------------------------------------------
  def update
    loop do
      $game_map.update
      $game_system.map_interpreter.update
      $game_player.update
      $game_system.update
      $game_screen.update
      unless $game_temp.player_transferring
        break
      end
      transfer_player
      if $game_temp.transition_processing
        break
      end
    end
    @spriteset.update
    #-----
    $advance_message_window.update if $advance_message_window.visible
    #-----
    @message_window.update
    if $game_temp.gameover
      $scene = Scene_Gameover.new
      return
    end
    if $game_temp.to_title
      $scene = Scene_Title.new
      return
    end
    if $game_temp.transition_processing
      $game_temp.transition_processing = false
      if $game_temp.transition_name == ""
        Graphics.transition(20)
      else
        Graphics.transition(40, "Graphics/Transitions/" +
          $game_temp.transition_name)
      end
    end
    if $game_temp.message_window_showing
      return
    end
    if $game_player.encounter_count == 0 and $game_map.encounter_list != []
      unless $game_system.map_interpreter.running? or
             $game_system.encounter_disabled
        n = rand($game_map.encounter_list.size)
        troop_id = $game_map.encounter_list[n]
        if $data_troops[troop_id] != nil
          $game_temp.battle_calling = true
          $game_temp.battle_troop_id = troop_id
          $game_temp.battle_can_escape = true
          $game_temp.battle_can_lose = false
          $game_temp.battle_proc = nil
        end
      end
    end
    if Input.trigger?(Input::B)
      unless $game_system.map_interpreter.running? or
             $game_system.menu_disabled
        $game_temp.menu_calling = true
        $game_temp.menu_beep = true
      end
    end
    if $DEBUG and Input.press?(Input::F9)
      $game_temp.debug_calling = true
    end
    unless $game_player.moving?
      if $game_temp.battle_calling
        call_battle
      elsif $game_temp.shop_calling
        call_shop
      elsif $game_temp.name_calling
        call_name
      elsif $game_temp.menu_calling
        call_menu
      elsif $game_temp.save_calling
        call_save
      elsif $game_temp.debug_calling
        call_debug
      end
    end
  end
#----------------------------------------------------------------------------
 
Настройка окна сообщений:
В Script... события вставить следующий код (генерируется с помощью "Dialogue Builder.exe"):
	Код:
	$advance_message_window.set(ширина_окна, высота_окна, отступ_от_края, горизонтальное_положение, вертикальное_положение, высота_строк, непрозрачность_фона, массив_параметров_шрифта, имя_говорящего_или_индекс_персонажа, лицо_говорящего_или_индекс_в_пакете_лиц)
 (строго не рекомендуется вбивать руками)
Вывод окна сообщений:
В Script... события вставить следующий код (генерируется с помощью "Dialogue Builder.exe"):
	Код:
	$advance_message_window.open (массив_абзацев)
 (так же не рекомендуется вбивать руками)
Внимание: В случае, если данное сообщение, идет в событии последним, что бы его закрытие не спровоцировало повторное обращение к событию, обязательно добавьте после вызова скрипта что-нибудь еще. К примеру, ожидание в течении одного кадра (wait 1).
Связанные ссылки:
Dialogue Bilder v1.3:
Демоверсия:
EKLib v2.1
EKLib(Addons) - Double Window v.1.0
Скрипт:
	Код:
	class Window_Dialogue_Advance < Window_Base
  #----------------------------------------------------------------------------
  attr_accessor :text
  #----------------------------------------------------------------------------
  def initialize
    super(20, 460 - 20, 600, 20)
    self.z = 9998
    self.back_opacity = 200
    @align = 1
    @v_align = 2
    @width = 600
    @height = 240
    @string_height = 2
    @font = Font.new
    @font.change (24, false, true, Color.new(255, 255, 255), ["Times New Roman", "Arial"])
    @name = ""
    @face = nil
    @number = nil
    @choice = nil
    @speaker_name = Window_Double.new(0, 0, 300, 32, 8, 4)
    @speaker_face = Sprite.new
    @speaker_name.visible = false
    @speaker_face.visible = false
    self.visible = false
    self.active = false
  end
  #----------------------------------------------------------------------------
  def dispose
    @speaker_name.dispose
    @speaker_face.dispose
    super
  end
  #----------------------------------------------------------------------------
  def set (width = 600, height = 240, space = 20, align = 1, v_align = 2,
    s_height = 20, back_opacity = 200,
    font = [24, false, true, Color.new(255, 255, 255), ["Times New Roman", "Arial"]],
    name = "", face = nil, number = nil, choice = nil)
    
    self.width = width                 # Ширина окна
    self.back_opacity = back_opacity   # Непрозрачность
    @align = align                     # Горизонтальное положение окна
    @v_align = v_align                 # Вертикальное положение окна
    @height = height                   # Высота окна
    @string_height = s_height          # Высота строк
    @font = Font.new                   # Шрифт
    @font.change (font[0], font[1], font[2], font[3], font[4])
    @number = number                   # Ввод номера
    @choice = choice                   # Выбор
    case @align                        # Горизонтальное положение окна
    when 0                             # Слева
      self.x = space
    when 1                             # Посередине
      self.x = 320 - self.width / 2
    when 2                             # Справа
      self.x = 640 - self.width - space
    end
    case @v_align                      # Вертикальное положение окна
    when 0                             # Сверху
      self.y = space
    when 1                             # Посередине
      self.y = 240 - @height / 2
    when 2                             # Снизу
      self.y = 480 - @height - space
    end
    if name.is_a?(Integer)             # Имя по неомеру
      @name = $game_actors[name].name
    elsif name.is_a?(String)
      @name = name                     # Имя по строке
    end
    if face.is_a?(Integer)             # Лицо из пакета лиц по номеру
      temp = []
      temp.push_image_fragments ("Graphics/Faces/faces.png", face, 100, 100)
      @face = temp[0]
    elsif face.is_a?(String)           # Лицо по названию файла
      @face = face != "" ? Bitmap.new("Graphics/Faces/" + face) : ""
    end
  end
  #----------------------------------------------------------------------------
  def open (text, hyphen = true)
    self.pause = true
    @text = text
    replace
    $game_temp.message_window_showing = true
    if hyphen
      new_y = self.y
      new_text = []
      temp = Bitmap.new(@width - 32, 460 - 32)
      temp.font = @font
      for string in @text
        hyphen_calc = temp.hyphen_draw_text (string, @width - 32, 0, 0, -1, true)
        new_y += hyphen_calc[1]
        for i in 0...hyphen_calc[0].size
          new_text.push(hyphen_calc[0][i])
        end
      end
      if @string_height < @font.size / 2 then @string_height = hyphen_calc[2] end
      @text = new_text
    end
    clear    
    draw_text
    self.visible = true
    while self.height < @height
      self.height += 10
      Graphics.update
    end
    if @name
      @speaker_name.contents.clear
      @speaker_name.contents.font = @font
      @speaker_name.width = @speaker_name.contents.text_size(@name).width + @speaker_name.x_space * 2
      @speaker_name.height = @speaker_name.contents.text_size(@name).height + @speaker_name.y_space * 2
      @speaker_name.x = @align != 2 ? self.x : self.x + self.width - @speaker_name.width
      @speaker_name.y = @v_align != 0 ? self.y - @speaker_name.height : self.y + self.height
      @speaker_name.back_opacity = self.back_opacity
      @speaker_name.contents.draw_text(0, 0, @speaker_name.contents.width, @speaker_name.contents.height, @name)
      @speaker_name.update
      @speaker_name.visible = true
    end
    if @face
      @speaker_face.bitmap = @face
      @speaker_face.x = @align != 2 ? self.x : self.x + self.width - @speaker_face.bitmap.width
      @speaker_face.mirror = @align != 2 ? false : true
      @speaker_face.y = @v_align != 0 ? self.y - @speaker_face.bitmap.height : self.y + self.height
      @speaker_face.y -= @speaker_name.height if @speaker_name.visible && @v_align != 0
      @speaker_face.y += @speaker_name.height if @speaker_name.visible && @v_align == 0
      @speaker_face.visible = true
    end
    self.active = true
    update
  end
  #----------------------------------------------------------------------------
  def close
    @speaker_name.visible = false
    @speaker_face.visible = false
    self.active = false
    self.pause = false
    y = self.y
    while self.height > 32
      self.height -= 10
      self.y += 10
      Graphics.update
    end
    self.visible = false
    self.y = y
    self.ox = 0
    self.oy = 0
    $game_temp.message_window_showing = false
  end
  #----------------------------------------------------------------------------
  def replace
    for string in @text
      string.gsub!(/\\[Nn]\[([0-9]+)\]/) do
        $game_actors[$1.to_i] != nil ? $game_actors[$1.to_i].name : ""
      end
      string.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
      string.gsub!(/\\[Ee]\[([0-9]+)\]/) do
        $data_enemies[$1.to_i] != nil ? $data_enemies[$1.to_i].name : ""
      end
      string.gsub!(/\\[Qq]\[([0-9]+)\]/) do
        $data_classes[$data_actors[$1.to_i].class_id] != nil ?
        $data_classes[$data_actors[$1.to_i].class_id].name : ""
      end
      string.gsub!(/\\[Uu]/) do
        $game_map.name != nil ? $game_map.name : ""
      end
    end
  end
  #----------------------------------------------------------------------------
  def clear
    @text.delete("\260")
    @text.delete("\n")
  end
  #----------------------------------------------------------------------------
  def draw_text
    self.contents = Bitmap.new(self.width - 32,  @string_height * @text.size)
    self.contents.font = @font
    for i in 0...@text.size
      if @string_height < (@font.size.to_f / 1.2).to_f
        @string_height = self.contents.text_size(@text[i]).height
      end
      self.contents.draw_text (0, 0 + @string_height * i, 600, @string_height, @text[i])
    end
  end
  #----------------------------------------------------------------------------
  def update
    return unless $game_temp.message_window_showing
    loop do
      Graphics.update
      Input.update
      super
      if Input.trigger?(Input::C)
        close
        break
      elsif Input.repeat?(Input::DOWN)
        if self.oy < (@string_height * @text.size - self.height / 1.2)
          self.oy += @string_height
        end
      elsif Input.repeat?(Input::UP)
        if self.oy > 0
          self.oy -= @string_height
        end
      end
    end
  end
  #----------------------------------------------------------------------------
end
 P.S.Прикрепленная "демоверсия", с которой были сняты скриншоты, являлась местом разработки скрипта, притензии по ней не принимаются(к примеру, невозможность войти в меню[исправлено]). Кстати, она является тем самым примером "как не надо делать", и показывает - что будет, если впихнуть слишком длинное сообщение.
P.P.S. Со следующей версией скрипт переоформлю в своем традиционном стиле, с подробными комментариями, etc.
P.P.P.S. Идеи, пожелания, багрепорты приветствуются.
						
					
Социальные закладки