事件脚本扩展
# @taroxd metadata 1.0
# @display 事件脚本扩展
# @require taroxd_core
# @id event_helper
# @help 偷懒用的事件脚本。
#    添加了以下方法:
#
#    Game_Interpreter
#      this_event: 获取本事件。如果事件不在当前地图上,返回 nil。
#      add_battlelog(text): 追加战斗信息。
#      shake_for(power = 5, speed = 5) { block }:
#        震动画面直到 block 执行完毕。没有 block 时,画面会无限震动下去。
#        不要在 block 中 return。
#        如果一定需要的话,记得加上 stop_shake 来停止震动。
#      stop_shake: 停止画面震动。
#      self_switch
#      self_switch(event_id)
#      self_switch(event_id, map_id):
#        返回对应事件的 SelfSwitch 对象。
#      fade_for(duration = 30) { block }:
#        淡出画面,执行 block 后淡入画面。
#
#    SelfSwitch
#      由 Game_Interpreter#self_switch 获取。
#      方法:
#      self[letter]:获取对应独立开关的值。letter: 'A'、'B'、'C'、'D' 之一。
#      self[letter] = value:设置对应独立开关的值。
#      属性 a, b, c, d:分别代表对应的独立开关。
#
#    Game_Switches/Game_Variables/Game_SelfSwitches
#       clear / reset: 清空数据
#
#    Game_CharacterBase
#       zoom_x, zoom_y, angle, mirror, opacity, ox, oy 属性: 控制对应 Sprite 的属性。
#       zoom=: 同时设置 zoom_x 与 zoom_y。
#       force_pattern(pattern):
#         将行走图强制更改为对应的 pattern。
#         pattern 从左到右分别为 0, 1, 2。
#         使用此功能时,建议勾选固定朝向,并且取消步行动画。
#       force_bush_depth(depth = nil):
#         将人物的 bush_depth 属性固定为 depth,不受地形的影响。
#         depth 为 nil 时取消固定
#       lineto(x, y)
#         沿直线移动到 (x, y)。可用 moving? 判断是否正在移动中。
#
#    Game_Character
#       jump_to / jumpto(x, y): 跳跃至 x, y
#
#    Game_Player
#       waiting 属性:设为真值时,禁止玩家移动
#       disable_scroll 属性:设为真值时,禁止地图卷动
#
#    Game_Party
#       +(gold), -(gold): 增加/减少金钱,并返回 self。
#       <<(actor), <<(actor_id): 加入指定队员,并返回 self。

module Taroxd::EventHelper

  # 定义了清除数据的方法
  module ClearData

    Game_Switches.send     :include, self
    Game_Variables.send    :include, self
    Game_SelfSwitches.send :include, self

    def clear
      @data.clear
      on_change
      self
    end

    alias_method :reset, :clear
  end

  # 代表独立开关的对象
  SelfSwitch = Struct.new(:map_id, :event_id) do
    def [](letter)
      $game_self_switches[[map_id, event_id, letter]]
    end

    def []=(letter, value)
      $game_self_switches[[map_id, event_id, letter]] = value
    end

    def a; self['A']; end
    def b; self['B']; end
    def c; self['C']; end
    def d; self['D']; end

    def a=(v); self['A'] = v; end
    def b=(v); self['B'] = v; end
    def c=(v); self['C'] = v; end
    def d=(v); self['D'] = v; end
  end
end


class Game_Interpreter

  include Taroxd::EventHelper

  def this_event
    $game_map.events[@event_id] if same_map?
  end

  def add_battlelog(text)
    if SceneManager.scene_is?(Scene_Battle)
      SceneManager.scene.add_battlelog(text)
    end
  end

  def self_switch(event_id = @event_id, map_id = @map_id)
    SelfSwitch.new(map_id, event_id)
  end

  def stop_shake
    screen.start_shake(0, 0, 0)
  end

  # 为了在事件解释器的 fiber 中使用,因此没有 ensure。
  def shake_for(power = 5, speed = 5)
    screen.start_shake(power, speed, Float::INFINITY)
    return unless block_given?
    yield
    stop_shake
  end

  def fade_for(duration = 30)
    Fiber.yield while $game_message.visible
    screen.start_fadeout(duration)
    wait(duration)
    yield if block_given?
    Fiber.yield while $game_message.visible
    screen.start_fadein(duration)
    wait(duration)
  end
end

class Game_CharacterBase

  attr_accessor :zoom_x, :zoom_y, :angle, :mirror, :opacity, :ox, :oy

  def zoom=(zoom)
    @zoom_x = @zoom_y = zoom
  end

  def force_pattern(pattern)
    @original_pattern = @pattern = pattern
  end

  def force_bush_depth(depth = nil)
    @force_bush_depth = depth
    @bush_depth = depth if depth
  end

  def lineto(tx, ty)
    theta = Math.atan2(ty - y, tx - x)
    d = distance_per_frame
    @x = tx
    @y = ty
    # distance per frame
    @lineto_dpf = Taroxd::Point.new(d * Math.cos(theta), d * Math.sin(theta))
    straighten
  end

  def update_lineto
    @real_x = [@real_x - @lineto_dpf.x, @x].max if @x < @real_x
    @real_x = [@real_x + @lineto_dpf.x, @x].min if @x > @real_x
    @real_y = [@real_y - @lineto_dpf.y, @y].max if @y < @real_y
    @real_y = [@real_y + @lineto_dpf.y, @y].min if @y > @real_y
    if !moving?
      @lineto_dpf = nil
      update_bush_depth
    end
  end

  def_unless(:update_bush_depth) { @force_bush_depth }
  def_after(:update_move) { update_lineto if @lineto_dpf }
end

class Game_Character
  def jumpto(tx, ty)
    jump(tx - x, ty - y)
  end

  alias_method :jump_to, :jumpto
end


class Game_Player < Game_Character

  attr_accessor :waiting, :disable_scroll

  def_unless :movable?, :waiting
  def_unless(:update_scroll) { |_, _| @disable_scroll }
end

class Game_Party < Game_Unit

  def +(gold)
    gain_gold(gold)
    self
  end

  def -(gold)
    lose_gold(gold)
    self
  end

  def <<(actor)
    add_actor(actor.id)
    self
  end
end

class Sprite_Character < Sprite_Base

  # 更新对应属性
  def_after :update_other do
    self.ox     = @character.ox     if @character.ox
    self.oy     = @character.oy     if @character.oy
    self.zoom_x = @character.zoom_x if @character.zoom_x
    self.zoom_y = @character.zoom_y if @character.zoom_y
    self.angle  = @character.angle  if @character.angle
    self.mirror = @character.mirror unless @character.mirror.nil?
  end
end

class Scene_Battle < Scene_Base

  def add_battlelog(text)
    @log_window.add_text(text)
  end
end
事件寻路
# @taroxd metadata 1.0
# @id event_astar
# @require taroxd_core
# @require astar
# @display 事件寻路
Taroxd::EventAStar = true

class Game_Character < Game_CharacterBase
  def find_path_toward(x, y)
    return @find_path if @find_path_xy == [x, y, @x, @y]
    @find_path = Taroxd::AStar.path(self, x, y)
    @find_path_xy = x, y, @x, @y
    @find_path
  end

  # 保留原方法,以备需要的时候使用。
  alias_method :move_toward_character_directly, :move_toward_character

  def move_toward_character(character)
    dir = find_path_toward(character.x, character.y).shift
    return move_toward_character_directly(character) unless dir
    move_straight(dir)
    @find_path_xy[2, 2] = @x, @y if @move_succeed
  end

  # 使用此方法 require 坐标类
  def move_toward_point(x, y)
    move_toward_character Taroxd::Point[x, y]
  end
end

class Game_Event < Game_Character
  alias_method :move_type_toward_player, :move_toward_player
end
脚本快捷方式
# @taroxd metadata 1.0
# @require taroxd_core
# @id eval
# @display 脚本快捷方式
# @deprecated 
module Taroxd::Eval

  Game_Character.send   :include, self
  Game_Interpreter.send :include, self
  # 脚本中的简称列表
  SCRIPT_ABBR_LIST = {
    'V' => '$game_variables',
    'S' => '$game_switches',
    'N' => '$game_actors',
    'A' => '$game_actors',
    'P' => '$game_party',
    'G' => '$game_party.gold',
    'E' => '$game_troop'
  }
  # 处理脚本用的正则表达式
  words = SCRIPT_ABBR_LIST.keys.join('|')
  SCRIPT_ABBR_RE = /(?<!::|['"\\\.])\b(?:#{words})\b(?! *[(@$\w'"])/


  module_function

  def process_script(script)
    script.gsub(SCRIPT_ABBR_RE, SCRIPT_ABBR_LIST)
  end

  def eval(script, *args)
    v = $game_variables
    s = $game_switches
    n = $game_actors
    a = $game_actors
    p = $game_party
    g = $game_party.gold
    e = $game_troop
    script = process_script(script)
    if args.empty?
      instance_eval(script, __FILE__, __LINE__)
    else
      Kernel.eval(script, *args)
    end
  end
end

class RPG::UsableItem::Damage
  def eval(a, b, v)
    value = Taroxd::Eval.eval(@formula, b.formula_binding(a, b, v))
    value > 0 ? value * sign : 0
  end
end

class Game_BattlerBase
  def formula_binding(a, b, v)
    s = $game_switches
    n = $game_actors
    p = $game_party
    g = $game_party.gold
    e = $game_troop
    binding
  end
end

class Window_Base < Window
  # 对 #{} 的处理
  process_expression = Proc.new do |old|
    old.gsub(/\e?#(?<brace>\{([^{}]|\g<brace>)*\})/) do |code|
      next code if code.slice!(0) == "\e"
      Taroxd::Eval.eval code[1..-2]
    end
  end
  def_with :convert_escape_characters, process_expression
end