得失物品提示
# @taroxd metadata 1.0
# @id gain_message
# @require taroxd_core
# @display 得失物品提示
module Taroxd::GainMessage

  # 信息格式

  # 转义符:
  # \name    代表物品名称 / 金钱单位
  # \value   代表获得 / 失去的物品 / 金钱数量
  # \icon    绘制物品 / 金钱的图标
  # \action  代表“获得”或者“失去”。可在下面修改。
  # 支持“显示文字”中的所有转义符。
  ITEM_FORMAT  = '\action了 \name * \value'
  GOLD_FORMAT  = '\action了 \value \name'
  ACTION_GAIN  = '获得'
  ACTION_LOSE  = '失去'
  GOLD_ICON_INDEX = 361           # 金钱图标的索引

  BACKGROUND   = 1                # 窗口背景(0/1/2)
  POSITION     = 1                # 显示位置(0/1/2)

  # 音效(不需要的话可以直接删去对应的行)
  GAIN_GOLD_SE = 'Shop'           # 获得金钱
  LOSE_GOLD_SE = 'Blow2'          # 失去金钱
  GAIN_ITEM_SE = 'Item1'          # 获得物品
  LOSE_ITEM_SE = LOSE_GOLD_SE     # 失去物品

  # 功能是否启用。
  def self.enabled?
    true
  end

  # 显示提示信息。获得金钱时将 item 设为 nil。
  def self.show(value, item)
    @item = item
    @value = value
    $game_message.background = BACKGROUND
    $game_message.position = POSITION
    $game_message.add(message)
    play_se
  end

  private

  # 获取提示的消息
  def self.message
    if @item
      format = ITEM_FORMAT
      icon_index = @item.icon_index
      name = @item.name
    else
      format = GOLD_FORMAT
      icon_index = GOLD_ICON_INDEX
      name = Vocab.currency_unit
    end

    gsub = {
      '\action' => @value > 0 ? ACTION_GAIN : ACTION_LOSE,
      '\value'  => @value.abs,
      '\icon'   => "\\I[#{icon_index}]",
      '\name'   => name
    }

    format.gsub(Regexp.union(gsub.keys), gsub)
  end

  def self.play_se
    const = :"#{@value > 0 ? 'GAIN' : 'LOSE'}_#{@item ? 'ITEM' : 'GOLD'}_SE"
    se = const_defined?(const) && const_get(const)
    Audio.se_play('Audio/SE/' + se) if se
  end
end

class Game_Party < Game_Unit
  # 获取道具总数(包括装备)
  def item_number_with_equip(item)
    members.inject(item_number(item)) { |a, e| a + e.equips.count(item) }
  end
end

class Game_Interpreter

  GainMessage = Taroxd::GainMessage

  # 显示提示窗口
  def show_gain_message(value, item = nil)
    return if value.zero?
    GainMessage.show(value, item)
    wait_for_message
  end

  # 增减金钱
  def_chain :command_125 do |old|
    return old.call unless GainMessage.enabled?
    last_gold = $game_party.gold
    old.call
    show_gain_message($game_party.gold - last_gold)
  end

  # 增减物品
  def_chain :command_126 do |old|
    return old.call unless GainMessage.enabled?
    item = $data_items[@params[0]]
    last_num = $game_party.item_number(item)
    old.call
    show_gain_message($game_party.item_number(item) - last_num, item)
  end

  # 增减武器
  def_chain :command_127 do |old|
    return old.call unless GainMessage.enabled?
    item = $data_weapons[@params[0]]
    last_num = $game_party.item_number_with_equip(item)
    old.call
    value = $game_party.item_number_with_equip(item) - last_num
    show_gain_message(value, item)
  end

  # 增减护甲
  def_chain :command_128 do |old|
    return old.call unless GainMessage.enabled?
    item = $data_armors[@params[0]]
    last_num = $game_party.item_number_with_equip(item)
    old.call
    value = $game_party.item_number_with_equip(item) - last_num
    show_gain_message(value, item)
  end
end

class Taroxd::EventTranscompiler
  def command_125
    value = operate_value(@params[1], @params[2], @params[3])
    "if GainMessage.enabled?
      @params = $game_party.item_number(item)
      $game_party.gain_gold(#{value})
      show_gain_message($game_party.gold - @params)
    else
      $game_party.gain_gold(#{value})
    end"
  end

  # database: :items, :weapons, :equips
  def show_message_gain_item(database)
    item_number = database == :item ? :item_number : :item_number_with_equip
    value = operate_value(@params[1], @params[2], @params[3])
    item = "$data_#{database}[#{@params[0]}]"
    "if GainMessage.enabled?
      @params = $game_party.#{item_number}(#{item})
      $game_party.gain_item(#{item}, #{value}, #{@params[4]})
      show_gain_message($game_party.#{item_number}(#{item}) - @params, #{item})
    else
      $game_party.gain_item(#{item}, #{value}, #{@params[4]})
    end"
  end

  def command_126
    show_message_gain_item(:items)
  end

  def command_127
    show_message_gain_item(:weapons)
  end

  def command_128
    show_message_gain_item(:armors)
  end
end if Taroxd.const_defined?(:EventTranscompiler)
快进对话
# @taroxd metadata 1.0
# @id fast_message
# @display 快进对话
module Taroxd
  module FastMessage
    KEY = :CTRL      # 按此键快进对话
    ENABLED = $TEST  # true: 启用; $TEST: 仅测试模式; false: 不启用
    SPEED = 3        # 文字快进速度。可以为小数,但不能小于 1。

    @counter = 0

    # 是否在输出一个字符后等待。show_fast: 是否快进
    def self.wait?(show_fast)
      !show_fast && !Input.press?(KEY) || (@counter += 1) % SPEED < 1
    end

    # 已经进入等待输入的情况下,是否继续等待输入
    def self.keep_pause?
      [:B, :C, KEY].none? { |k| Input.trigger?(k) }
    end

    # 尚未进入等待输入的情况下,是否跳过等待输入
    def self.skip_pause?
      Input.press?(KEY)
    end
  end
end

class Window_Message < Window_Base

  FastMessage = Taroxd::FastMessage

  def input_pause
    return if FastMessage.skip_pause?
    self.pause = true
    wait(10)
    Fiber.yield while FastMessage.keep_pause?
    Input.update
    self.pause = false
  end

  def wait_for_one_character
    update_show_fast
    Fiber.yield if FastMessage.wait?(@show_fast || @line_show_fast)
  end
end if Taroxd::FastMessage::ENABLED
快进游戏
# @taroxd metadata 1.0
# @id fast_forward
# @display 快进游戏
# @help 
#      跳过 frame 帧。keys 为这 frame 帧按下的按键。
#      每一帧都视为重新按下按键。
#
#    示例:
#      Taroxd::FastForward.call(999, :C)
#        跳过 999 帧。每帧都视为重新按下确定键。

module Taroxd

  dirs = {DOWN: 2, LEFT: 4, RIGHT: 6, UP: 8}

  # 获取 dir4, dir8。
  dir_4_8 = lambda do |keys|
    dir8 = dirs.inject(5) do |dir, (key, value)|
      keys.include?(key) ? dir + value - 5 : dir
    end

    return 0, 0 if dir8 == 5
    return dir8, dir8 if [2, 4, 6, 8].include?(dir8)
    keys.reverse_each { |key| return dirs[key], dir8 if dirs[key] }
    [0, 0] # 理论上不会执行
  end

  FastForward = lambda do |frame, *keys|
    # 保留原方法的哈希表
    # 方法名(Symbol)为键,method 对象为值
    graphics_methods = {}
    input_methods = {}

    # 重定义 Graphics 的方法
    define_graphics_method = lambda do |name, &block|
      graphics_methods[name] = Graphics.method(name)
      Graphics.define_singleton_method(name, block)
    end

    # 重定义 Input 的方法
    define_input_method = lambda do |name, &block|
      input_methods[name] = Input.method(name)
      Input.define_singleton_method(name, block)
    end

    # 将方法恢复到原先的状态
    restore = lambda do
      input_methods.each do |name, method|
        Input.define_singleton_method(name, method)
      end
      graphics_methods.each do |name, method|
        Graphics.define_singleton_method(name, method)
      end
    end

    # 重定义 dir4, dir8 方法。value:方法的返回值
    define_dir_method = lambda do |name, value|
      define_input_method.call(name) { value } unless value == 5
    end

    # 重定义持续一段时间的 Graphics 模块方法。effect:该方法的副作用
    define_duration_method = lambda do |name, &effect|
      define_graphics_method.call name do |*args|
        duration = args.first || 1
        if frame < duration
          restore.call
          send name, *args
        else
          frame -= duration
          effect.call(*args) if effect
          nil
        end
      end
    end

    unless keys.empty?
      [:trigger?, :press?, :repeat?].each do |name|
        define_input_method.call(name) { |key| keys.include?(key) }
      end
    end

    dir4, dir8 = dir_4_8.call(keys)
    define_dir_method.call(:dir4, dir4)
    define_dir_method.call(:dir8, dir8)
    define_graphics_method.call(:freeze) {}
    define_duration_method.call :update
    define_duration_method.call :wait
    define_duration_method.call(:fadeout) { self.brightness = 0 }
    define_duration_method.call(:fadein) { self.brightness = 255 }
    define_duration_method.call :transition do
      graphics_methods[:transition].call(0)
    end
  end
end