#===============================================================================
# 
# Yanfly Engine Melody - Skill Equip System
# Last Date Updated: 2010.06.27
# Level: Normal, Hard
# 
# Gameplay balance is at stake in games where characters can get an abundant
# amount of skills. This script requires the player to make decisions as to
# which skills to bring into battle for each character and what compositions
# of skills, too. There's limit types to dictate how many skills of a type that
# the player may carry so that available skillsets won't end up becoming too
# overpowering.
# 
# And with this script comes the ability for characters to temporarily copy the
# skills of another actor or enemy in battle. This will allow the player to
# replace the copy skill with something new and further expand upon the existing
# skill set possibilities.
# 
#===============================================================================
# Updates
# -----------------------------------------------------------------------------
# o 2010.06.27 - Multi-Limit Type notetag bugfix.
# o 2010.06.26 - Bugfix for changing max slots.
# o 2010.06.18 - Added switch enabling for equipping skills.
# o 2010.06.15 - Updated lag efficiency.
# o 2010.06.14 - Finished Script.
# o 2010.06.13 - Started Script.
#===============================================================================
# Instructions
# -----------------------------------------------------------------------------
# To install this script, open up your script editor and copy/paste this script
# to an open slot below ▼ Materials but above ▼ Main. Remember to save.
# 
# Note: This script requires Yanfly Engine Melody's Skill Overhaul to work.
# 
# -----------------------------------------------------------------------------
# Skill Tags - Insert the following into skill noteboxes.
# -----------------------------------------------------------------------------
# <limit type: type>
# The skill will require an empty slot for the entered "type" in order for it
# to be equipped. If the actor's slot types of that type are all filled up,
# then the actor cannot equip the skill.
# 
# <limit type: type, x>
# This will cause the skill to require x free slots of the entered "type" in
# order for the actor to equip this skill. If the actor's slot types of that
# type are all filled up, then the actor cannot equip the skill.
# 
# <equip stat: +x>  or  <equip stat: -x>
# By equipping the skill, the adjusted stat will increase or decrease by x.
# Replace "stat" with any of the following:
# maxhp, maxmp, atk, def, spi, res, dex, agi, hit, eva, cri, odds
# 
# <equip state: x>  or  <equip state: x, x>
# By equipping the skill, the state x will be automatically applied to the
# user until unequipped. Insert multiple of these tags to apply multiple states
# to be applied when the skill is equipped.
# 
# <skill type: phrase>
# This designates a unique type flag for the skill and is mostly used for
# identification purposes within the script. All skills have the "ALL" type
# associated with them.
# 
# <copy type: phrase>
# This will allow the skill to copy and replace itself in the battle with any
# of the skills of the "phrase" type within the skill's targets.
# 
# <cannot copy>
# This will prevent this particular skill from being able to be copied. Used
# to prevent players from taking boss skills.
# 
# -----------------------------------------------------------------------------
# Equip Tags - Insert the following tags into Weapon and Armour noteboxes.
# -----------------------------------------------------------------------------
# <skill slots: +x>  or  <skill slots: -x>
# Any weapon or armour with this tag will increase or decrease the number of
# available skill slots the actor has readily to equip skills in. This tag
# cannot bring the amount of available slots below 0.
# 
# <type slots: +x>  or  <type slots: -x>
# Replace "type" with one of the types found in the RESTRICTIONS hash in the
# module. This will increase or decrease the amount of slot types available to
# be worn for the player by x amount. This cannot bring the amount of available
# type slots below 0. When replacing "type" in the notetag, do note that it is
# case sensitive.
#===============================================================================

$imported = {} if $imported == nil
$imported["SkillEquipSystem"] = true

module YEM
  module SKILL_EQUIP
    
    #===========================================================================
    # Section I. Basic Settings
    # --------------------------------------------------------------------------
    # The following below will adjust the basic ruleset that the skill equip
    # system will use. Visual settings will also be adjusted here.
    #===========================================================================
    
    # This is the category title that appears for the skill equip option.
    TITLE = "Equip Skill"
    
    # This switch must be enabled in order for the Equip Skill command to appear
    # in the skill menu.
    EQUIP_SKILL_SWITCH = 43
    
    # These are the visual settings used when a skill isn't equipped.
    EMPTY_SKILL_HELP = "No skill is equipped in this slot."
    EMPTY_SKILL_TEXT = "<Empty Slot>"  # Text used for no skill equipped.
    EMPTY_SKILL_ICON = 98              # Icon used for no skill equipped.
    
    # This constant adjusts the default maximum amount of equipped skills that
    # an actor can have without modifications.
    DEFAULT_MAX_EQUIPS = 8
    
    #===========================================================================
    # Section II. Skill Equip Restrictions
    # --------------------------------------------------------------------------
    # Not every skill should be equippable with full freedom. Some skills are
    # more powerful than others and some skills can break the game when both
    # exist within a character's skill list. Use these restrictions to balance
    # out your game should you desire to use it.
    #===========================================================================
    
    # This hash adjusts the rules regarding each of the restrictions applied to
    # equippable skills. Here's what each of the settings mean:
    #   "Name" - The name of the category.
    #   Icon   - The icon used for the category.
    #   Max    - Maximum amount of skills of that type that can be equipped.
    #   Show?  - Show this category when listing skills?
    RESTRICTIONS ={
    # "Name"   => [Icon, Max, Show?]
      "Normal" => [  96,  99,  true],
      "Strong" => [  99,   3,  true],
      "Elite"  => [  85,   1,  true],
    } # Do not remove this.
    
    # To set the default restrictions for each skill, adjust this array.
    # This is case sensitive.
    DEFAULT_RESTRICTIONS = ["Normal"]
    
    # This is the restriction order shown visibly. This is case sensitive.
    RESTRICT_ORDER = ["Normal", "Strong", "Elite"]
    
    # This is the title used for the data window to display what restrictions
    # are held by the skill in question. You may also opt to show these
    # restrictions or not.
    RESTRICTION_TITLE = "Limitations"
    SHOW_RESTRICTIONS = true
    
    #===========================================================================
    # Section III. Copy Skill Settings
    # --------------------------------------------------------------------------
    # The Skill Equip System also contains the unique ability to copy skills
    # from opponents or allies in battle. These copied skills will replace the
    # skill that's being used to perform the copying. After battle, all copied
    # skills will return back to normal.
    #===========================================================================
    
    # This will adjust the coordinates of the copy skill window that appears in
    # battle to perform the skill copy.
    COPY_SKILL_WINDOW_X = 16
    COPY_SKILL_WINDOW_Y = 88
    
    # This is the text that appears in the description window that appears with
    # the copy skill window.
    COPY_SKILL_DESCRIPTION = "Select a skill to copy."
    
  end # SKILL_EQUIP
end # YEM

#===============================================================================
# Editting anything past this point may potentially result in causing computer
# damage, incontinence, explosion of user's head, coma, death, and/or halitosis.
# Therefore, edit at your own risk.
#===============================================================================

module YEM
  module REGEXP
  module BASEITEM
    
    SKILL_SLOTS = /<(?:SKILL_SLOTS|skill slots):[ ]*([\+\-]\d+)>/i
    TYPE_SLOTS  = /<(.*)[ ](?:SLOTS|slot):[ ]*([\+\-]\d+)>/i
    
  end # BASEITEM
  module SKILL
    
    LIMIT_TYPE1 = /<(?:LIMIT_TYPE|limit type):[ ](.*)>/i
    LIMIT_TYPE2 = /<(?:LIMIT_TYPE|limit type):[ ](.*),[ ](\d+)>/i
    
    EQUIP_STATS = /<(?:EQUIP|equipped)[ ](.*):[ ]*([\+\-]\d+)>/i
    EQUIP_STATE = /<(?:EQUIP_STATE|equip state):[ ]*(\d+(?:\s*,\s*\d+)*)>/i
    
    SKILL_TYPE  = /<(?:SKILL_TYPE|skill type):[ ](.*)>/i
    COPY_TYPE   = /<(?:COPY_TYPE|copy type):[ ](.*)>/i
    CANNOT_COPY = /<(?:CANNOT_COPY|cannot copy|cant copy)>/i
    
  end # SKILL
  end # REGEXP
end # YEM

#===============================================================================
# module Vocab
#===============================================================================

module Vocab
  
  #--------------------------------------------------------------------------
  # self.empty_skill
  #--------------------------------------------------------------------------
  def self.empty_skill; return YEM::SKILL_EQUIP::EMPTY_SKILL_TEXT; end
  
  #--------------------------------------------------------------------------
  # self.empty_skill_help
  #--------------------------------------------------------------------------
  def self.empty_skill_help; return YEM::SKILL_EQUIP::EMPTY_SKILL_HELP; end
  
end # Vocab

#===============================================================================
# module Icon
#===============================================================================

module Icon
  
  #--------------------------------------------------------------------------
  # self.empty_skill
  #--------------------------------------------------------------------------
  def self.empty_skill; return YEM::SKILL_EQUIP::EMPTY_SKILL_ICON; end
  
  #--------------------------------------------------------------------------
  # self.skill_limit
  #--------------------------------------------------------------------------
  def self.skill_limit(type)
    if YEM::SKILL_EQUIP::RESTRICTIONS
      return icon = YEM::SKILL_EQUIP::RESTRICTIONS[type][0]
    else
      return 0
    end
  end
  
end # Icon

#===============================================================================
# RPG::BaseItem
#===============================================================================

class RPG::BaseItem
  
  #--------------------------------------------------------------------------
  # public instance variables
  #--------------------------------------------------------------------------
  attr_accessor :skill_slots
  attr_accessor :type_slots
  
  #--------------------------------------------------------------------------
  # common cache: yem_cache_baseitem_ses
  #--------------------------------------------------------------------------
  def yem_cache_baseitem_ses
    return if @cached_baseitem_ses; @cached_baseitem_ses = true
    @skill_slots = 0
    @type_slots = {}
    #---
    self.note.split(/[\r\n]+/).each { |line|
      case line
      #---
      when YEM::REGEXP::BASEITEM::SKILL_SLOTS
        next if self.is_a?(RPG::Skill)
        @skill_slots = $1.to_i
      when YEM::REGEXP::BASEITEM::TYPE_SLOTS
        next if self.is_a?(RPG::Skill)
        next unless YEM::SKILL_EQUIP::RESTRICTIONS.include?($1.to_s)
        @type_slots[$1.to_s] = $2.to_i
      end
    } # self.note.split
  end # yem_cache_baseitem_ses
  
end # RPG::BaseItem
  
#===============================================================================
# RPG::Skill
#===============================================================================

class RPG::Skill < RPG::UsableItem
  
  #--------------------------------------------------------------------------
  # public instance variables
  #--------------------------------------------------------------------------
  attr_accessor :cannot_copy
  attr_accessor :copy_type
  attr_accessor :equip_bonuses
  attr_accessor :limit_type
  attr_accessor :skill_type
  
  #--------------------------------------------------------------------------
  # common cache: yem_cache_skill_ses
  #--------------------------------------------------------------------------
  def yem_cache_skill_ses
    return if @cached_skill_ses; @cached_skill_ses = true
    @cannot_copy = false
    @copy_type = []
    @skill_type = ["ALL"] if @skill_type == nil
    @limit_type = {} if @limit_type == nil
    @equip_bonuses = { :maxhp => 0, :maxmp => 0, :atk => 0, :def => 0, 
      :spi => 0, :res => 0, :dex => 0, :agi => 0, :hit => 0, :eva => 0, 
      :cri => 0, :odds => 0, :states => [] }
    #---
    self.note.split(/[\r\n]+/).each { |line|
      case line
      #---
      when YEM::REGEXP::SKILL::LIMIT_TYPE2
        next unless YEM::SKILL_EQUIP::RESTRICTIONS.include?($1.to_s)
        @limit_type[$1.to_s] = $2.to_i
        @skill_type.push($1.upcase)
      when YEM::REGEXP::SKILL::LIMIT_TYPE1
        next unless YEM::SKILL_EQUIP::RESTRICTIONS.include?($1.to_s)
        @limit_type[$1.to_s] = 1
        @skill_type.push($1.upcase)
      #---
      when YEM::REGEXP::SKILL::EQUIP_STATS
        case $1.upcase
        when "MAXHP", "HP"
          @equip_slot[:maxhp] = $2.to_i
        when "MAXMP", "MP", "MAXSP", "SP"
          @equip_bonuses[:maxmp] = $2.to_i
        when "ATK"
          @equip_bonuses[:atk] = $2.to_i
        when "DEF"
          @equip_bonuses[:def] = $2.to_i
        when "SPI"
          @equip_bonuses[:spi] = $2.to_i
        when "RES"
          @equip_bonuses[:res] = $2.to_i
        when "DEX"
          @equip_bonuses[:dex] = $2.to_i
        when "AGI"
          @equip_bonuses[:agi] = $2.to_i
        when "HIT"
          @equip_bonuses[:hit] = $2.to_i
        when "EVA"
          @equip_bonuses[:eva] = $2.to_i
        when "CRI"
          @equip_bonuses[:cri] = $2.to_i
        when "ODDS", "AGR"
          @equip_bonuses[:odds] = $2.to_i
        else; next
        end
      #---
      when YEM::REGEXP::SKILL::EQUIP_STATE
        $1.scan(/\d+/).each { |num| 
        @equip_bonuses[:states].push($data_states[num.to_i]) if num.to_i > 0 }
      #---
      when YEM::REGEXP::SKILL::SKILL_TYPE
        @skill_type.push($1.upcase)
      when YEM::REGEXP::SKILL::COPY_TYPE
        @copy_type.push($1.upcase)
      when YEM::REGEXP::SKILL::CANNOT_COPY
        @cannot_copy = true
      end
    } # self.note.split
    #---
    if @limit_type == {}
      for type in YEM::SKILL_EQUIP::DEFAULT_RESTRICTIONS
        @limit_type[type] = 1
      end
    end
  end # yem_cache_skill_ses
  
end # RPG::Skill

#===============================================================================
# Scene_Title
#===============================================================================

class Scene_Title < Scene_Base
  
  #--------------------------------------------------------------------------
  # alias method: load_bt_database
  #--------------------------------------------------------------------------
  alias load_bt_database_ses load_bt_database unless $@
  def load_bt_database
    load_bt_database_ses
    load_ses_cache
  end
  
  #--------------------------------------------------------------------------
  # alias method: load_database
  #--------------------------------------------------------------------------
  alias load_database_ses load_database unless $@
  def load_database
    load_database_ses
    load_ses_cache
  end
  
  #--------------------------------------------------------------------------
  # new method: load_ses_cache
  #--------------------------------------------------------------------------
  def load_ses_cache
    groups = [$data_skills, $data_weapons, $data_armors]
    for group in groups
      for obj in group
        next if obj == nil
        obj.yem_cache_baseitem_ses if obj.is_a?(RPG::BaseItem)
        obj.yem_cache_skill_ses if obj.is_a?(RPG::Skill)
      end
    end
  end
  
end # Scene_Title

#===============================================================================
# Game_Battler
#===============================================================================

class Game_Battler

  #--------------------------------------------------------------------------
  # alias method: states
  #--------------------------------------------------------------------------
  alias states_ses states unless $@
  def states
    result = states_ses
    if actor?
      for skill in battle_skills
        next if skill == nil
        result |= skill.equip_bonuses[:states]
      end
    end
    return result.uniq
  end
  
end # Game_Battler

#===============================================================================
# Game_Actor
#===============================================================================

class Game_Actor < Game_Battler
  
  #--------------------------------------------------------------------------
  # alias method: setup
  #--------------------------------------------------------------------------
  alias setup_ses setup unless $@
  def setup(actor_id)
    setup_ses(actor_id)
    create_initial_equipped_skills
  end

  #--------------------------------------------------------------------------
  # alias method: skills
  #--------------------------------------------------------------------------
  alias skills_ses skills unless $@
  def skills
    if $game_temp.in_battle
      return battle_skills
    else
      return skills_ses
    end
  end
  
  #--------------------------------------------------------------------------
  # new method: battle_skills
  #--------------------------------------------------------------------------
  def battle_skills
    if @battle_skills == nil
      @battle_skills = []
      for i in 0...max_equipped_skills
        if copied_skills[i] != nil and $game_temp.in_battle
          @battle_skills.push(copied_skills[i].id)
          next
        end
        @battle_skills.push(equipped_skills[i].id) if equipped_skills[i] != nil
        @battle_skills.push(0) if equipped_skills[i] == nil
      end
    end
    #---
    result = []
    for skill_id in @battle_skills
      result.push($data_skills[skill_id])
    end
    return result
  end
  
  #--------------------------------------------------------------------------
  # new method: copied_skills
  #--------------------------------------------------------------------------
  def copied_skills
    result = []
    clear_copied_skills if @copied_skills == nil
    for skill_id in @copied_skills
      skill_id = 0 if skill_id == nil
      result.push($data_skills[skill_id])
    end
    return result
  end
  
  #--------------------------------------------------------------------------
  # new method: clear_copied_skills
  #--------------------------------------------------------------------------
  def clear_copied_skills
    @copied_skills = []
    clear_battle_cache if $imported["BattleEngineMelody"]
  end
  
  #--------------------------------------------------------------------------
  # new method: equipped_skills
  #--------------------------------------------------------------------------
  def equipped_skills
    result = []
    create_initial_equipped_skills if @equipped_skills == nil
    for skill_id in @equipped_skills
      skill_id = 0 if skill_id == nil
      result.push($data_skills[skill_id])
    end
    loop do
      break if result.size >= max_equipped_skills
      result.push(nil)
    end
    return result
  end
  
  #--------------------------------------------------------------------------
  # new method: sort_equipped_skills
  #--------------------------------------------------------------------------
  def sort_equipped_skills
    create_initial_equipped_skills if @equipped_skills == nil
    @equipped_skills.delete(nil)
    @equipped_skills.delete(0)
    @equipped_skills.sort!
    i = @equipped_skills.size
    loop do
      break if i >= max_equipped_skills
      @equipped_skills.push(0)
      i += 1
    end
    @battle_skills = nil
  end
  
  #--------------------------------------------------------------------------
  # new method: equip_skill
  #--------------------------------------------------------------------------
  def equip_skill(slot, skill_id)
    skill_id = skill_id.id if skill_id.is_a?(RPG::Skill)
    create_initial_equipped_skills if @equipped_skills == nil
    return if @equipped_skills.include?(skill_id) and skill_id != 0
    @equipped_skills[slot] = skill_id
    purge_illegal_equipped_skills
    clear_battle_cache if $imported["BattleEngineMelody"]
    @battle_skills = nil
  end
  
  #--------------------------------------------------------------------------
  # new method: copy_skill
  #--------------------------------------------------------------------------
  def copy_skill(slot, skill_id)
    skill_id = skill_id.id if skill_id.is_a?(RPG::Skill)
    clear_copied_skills if @copied_skills == nil
    @copied_skills[slot] = skill_id
    clear_battle_cache if $imported["BattleEngineMelody"]
    @battle_skills = nil
  end
  
  #--------------------------------------------------------------------------
  # new method: can_equip_skill?
  #--------------------------------------------------------------------------
  def can_equip_skill?(skill)
    return false if skill == nil
    skill = $data_skills[skill] if skill.is_a?(Integer)
    for key in skill.limit_type
      type = key[0]; amount = key[1]
      if (amount + equip_skill_limit(type)) > equip_skill_limit_max(type)
        return false
      end
    end
    return true
  end
  
  #--------------------------------------------------------------------------
  # new method: equip_skill_limit
  #--------------------------------------------------------------------------
  def equip_skill_limit(type)
    result = 0
    for skill in equipped_skills
      next if skill == nil
      next if skill.limit_type[type] == nil
      result += skill.limit_type[type]
    end
    return result
  end
  
  #--------------------------------------------------------------------------
  # new method: equip_skill_limit_max
  #--------------------------------------------------------------------------
  def equip_skill_limit_max(type)
    @equip_skill_limit = {} if @equip_skill_limit == nil
    result = @equip_skill_limit[type] if @equip_skill_limit[type] != nil
    result = YEM::SKILL_EQUIP::RESTRICTIONS[type][1]
    for equip in equips.compact
      next if equip.type_slots[type] == nil
      result += equip.type_slots[type]
    end
    return [result, 0].max
  end
  
  #--------------------------------------------------------------------------
  # new method: max_equipped_skills
  #--------------------------------------------------------------------------
  def max_equipped_skills
    return @cache_max_equipped_skills if @cache_max_equipped_skills != nil
    if @max_equipped_skills == nil
      max = YEM::SKILL_EQUIP::DEFAULT_MAX_EQUIPS
    else
      max = @max_equipped_skills
    end
    for equip in equips.compact; max += equip.skill_slots; end
    @cache_max_equipped_skills = [max, 0].max
    return @cache_max_equipped_skills
  end
  
  #--------------------------------------------------------------------------
  # new method: max_equipped_skills=
  #--------------------------------------------------------------------------
  def max_equipped_skills=(new_value)
    @max_equipped_skills = new_value
    @cache_max_equipped_skills = nil
    @battle_skills = nil
    purge_illegal_equipped_skills
  end
  
  #--------------------------------------------------------------------------
  # new method: purge_illegal_equipped_skills
  #--------------------------------------------------------------------------
  def purge_illegal_equipped_skills
    create_initial_equipped_skills if @equipped_skills == nil
    if @equipped_skills.size > max_equipped_skills
      for i in max_equipped_skills..@equipped_skills.size
        @equipped_skills.delete_at(i)
      end
    end
    @battle_skills = nil
  end
  
  #--------------------------------------------------------------------------
  # new method: create_initial_equipped_skills
  #--------------------------------------------------------------------------
  def create_initial_equipped_skills
    @equipped_skills = []
    for skill in skills_ses
      break if @equipped_skills.size > max_equipped_skills
      next if skill == nil
      @equipped_skills.push(skill.id)
    end
  end
  
  #--------------------------------------------------------------------------
  # alias method: learn_skill
  #--------------------------------------------------------------------------
  alias learn_skill_ses learn_skill unless $@
  def learn_skill(skill_id)
    unless skill_learn?($data_skills[skill_id])
      for i in 0...max_equipped_skills
        next unless equipped_skills[i] == nil
        equip_skill(i, skill_id) if can_equip_skill?(skill_id)
        break
      end
    end
    learn_skill_ses(skill_id)
  end
  
  #--------------------------------------------------------------------------
  # alias method: forget_skill
  #--------------------------------------------------------------------------
  alias forget_skill_ses forget_skill unless $@
  def forget_skill(skill_id)
    forget_skill_ses(skill_id)
    create_initial_equipped_skills if @equipped_skills == nil
    @equipped_skills.delete(skill_id)
    @battle_skills = nil
  end
  
  #--------------------------------------------------------------------------
  # new method: equip_skill_stat_bonus
  #--------------------------------------------------------------------------
  def equip_skill_stat_bonus(stat)
    result = 0
    for skill in battle_skills
      next if skill == nil
      next if skill.equip_bonuses[stat] == nil
      result += skill.equip_bonuses[stat]
    end
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: base_maxhp
  #--------------------------------------------------------------------------
  alias base_maxhp_ses base_maxhp unless $@
  def base_maxhp
    result = base_maxhp_ses
    result += equip_skill_stat_bonus(:maxhp)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: base_maxmp
  #--------------------------------------------------------------------------
  alias base_maxmp_ses base_maxmp unless $@
  def base_maxmp
    result = base_maxmp_ses
    result += equip_skill_stat_bonus(:maxmp)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: base_atk
  #--------------------------------------------------------------------------
  alias base_atk_ses base_atk unless $@
  def base_atk
    result = base_atk_ses
    result += equip_skill_stat_bonus(:atk)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: base_def
  #--------------------------------------------------------------------------
  alias base_def_ses base_def unless $@
  def base_def
    result = base_def_ses
    result += equip_skill_stat_bonus(:def)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: base_spi
  #--------------------------------------------------------------------------
  alias base_spi_ses base_spi unless $@
  def base_spi
    result = base_spi_ses
    result += equip_skill_stat_bonus(:spi)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: base_agi
  #--------------------------------------------------------------------------
  alias base_agi_ses base_agi unless $@
  def base_agi
    result = base_agi_ses
    result += equip_skill_stat_bonus(:agi)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: hit
  #--------------------------------------------------------------------------
  alias hit_ses hit unless $@
  def hit
    result = hit_ses
    result += equip_skill_stat_bonus(:hit)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: eva
  #--------------------------------------------------------------------------
  alias eva_ses eva unless $@
  def eva
    result = eva_ses
    result += equip_skill_stat_bonus(:eva)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: cri
  #--------------------------------------------------------------------------
  alias cri_ses cri unless $@
  def cri
    result = cri_ses
    result += equip_skill_stat_bonus(:cri)
    return result
  end
  
  #--------------------------------------------------------------------------
  # alias method: odds
  #--------------------------------------------------------------------------
  alias odds_ses odds unless $@
  def odds
    result = odds_ses
    result += equip_skill_stat_bonus(:odds)
    return result
  end
  
  #--------------------------------------------------------------------------
  # overwrite method: skill_can_use?
  #--------------------------------------------------------------------------
  def skill_can_use?(skill); return super(skill); end
  
  #--------------------------------------------------------------------------
  # alias method: change_equip
  #--------------------------------------------------------------------------
  alias change_equip_ses change_equip unless $@
  def change_equip(equip_type, item, test = false)
    change_equip_ses(equip_type, item, test)
    @cache_max_equipped_skills = nil
    purge_illegal_equipped_skills
  end
  
end # Game_Actor

#===============================================================================
# Game_Enemy
#===============================================================================

class Game_Enemy < Game_Battler
  
  #--------------------------------------------------------------------------
  # new method: total_skills
  #--------------------------------------------------------------------------
  def total_skills
    result = []
    for action in enemy.actions
      next unless action.kind == 1
      skill = $data_skills[action.skill_id]
      result.push(skill) unless result.include?(skill)
    end
    result.sort! { |a,b| a.id <=> b.id }
    return result.uniq
  end
  
end # Game_Enemy

#===============================================================================
# Game_Party
#===============================================================================

class Game_Party < Game_Unit
  
  #--------------------------------------------------------------------------
  # alias method: setup_starting_members
  #--------------------------------------------------------------------------
  alias setup_starting_members_ses setup_starting_members unless $@
  def setup_starting_members
    setup_starting_members_ses
    $game_switches[YEM::SKILL_EQUIP::EQUIP_SKILL_SWITCH] = true
  end
  
end # Game_Party

#===============================================================================
# Window_EquipSkill
#===============================================================================

class Window_EquipSkill < Window_Selectable
  
  #--------------------------------------------------------------------------
  # initialize
  #--------------------------------------------------------------------------
  def initialize(actor, help_window)
    @actor = actor
    @help_window = help_window
    dy = @help_window.y + @help_window.height
    super(0, dy, Graphics.width - 240, Graphics.height - dy)
    refresh
    self.active = false
    self.index = 0
  end
  
  #--------------------------------------------------------------------------
  # skill
  #--------------------------------------------------------------------------
  def skill; return @actor.equipped_skills[self.index]; end
  
  #--------------------------------------------------------------------------
  # actor=
  #--------------------------------------------------------------------------
  def actor=(new_actor)
    @actor = new_actor
    refresh
  end
  
  #--------------------------------------------------------------------------
  # refresh
  #--------------------------------------------------------------------------
  def refresh
    @data = @actor.equipped_skills
    @item_max = @data.size
    self.index = [[self.index, @item_max-1].min, 0].max
    create_contents
    for i in 0...@item_max; draw_item(i); end
  end
  
  #--------------------------------------------------------------------------
  # draw_item
  #--------------------------------------------------------------------------
  def draw_item(index)
    rect = item_rect(index)
    self.contents.clear_rect(rect)
    skill = @actor.equipped_skills[index]
    draw_obj_name(skill, rect.clone, true) if skill != nil
    draw_empty(skill, rect.clone, false) if skill == nil
  end
  
  #--------------------------------------------------------------------------
  # new method: draw_obj_name
  #--------------------------------------------------------------------------
  def draw_obj_name(obj, rect, enabled)
    draw_obj_limits(obj, rect, enabled)
    draw_icon(obj.icon_index, rect.x, rect.y, enabled)
    self.contents.font.size = Font.default_size
    self.contents.font.color = normal_color
    self.contents.font.color.alpha = enabled ? 255 : 128
    rect.width -= 96
    self.contents.draw_text(rect.x+24, rect.y, rect.width, WLH, obj.name, 0)
  end
  
  #--------------------------------------------------------------------------
  # new method: draw_obj_limits
  #--------------------------------------------------------------------------
  def draw_obj_limits(obj, rect, enabled)
    dx = 24
    for type in YEM::SKILL_EQUIP::RESTRICT_ORDER.reverse
      next unless YEM::SKILL_EQUIP::RESTRICTIONS[type][2]
      next unless obj.limit_type.include?(type)
      draw_icon(Icon.skill_limit(type), rect.width-dx, rect.y, enabled)
      dx += 24
    end
  end
  
  #--------------------------------------------------------------------------
  # new method: draw_empty
  #--------------------------------------------------------------------------
  def draw_empty(obj, rect, enabled)
    draw_icon(Icon.empty_skill, rect.x, rect.y, enabled)
    self.contents.font.size = Font.default_size
    self.contents.font.color = normal_color
    self.contents.font.color.alpha = enabled ? 255 : 128
    rect.width -= 96; name = Vocab.empty_skill
    self.contents.draw_text(rect.x+24, rect.y, rect.width, WLH, name, 0)
  end
  
  #--------------------------------------------------------------------------
  # update_help
  #--------------------------------------------------------------------------
  def update_help
    none = Vocab.empty_skill_help
    @help_window.set_text(skill == nil ? none : skill.description)
  end
  
end # Window_EquipSkill

#===============================================================================
# Window_EquipSkillData
#===============================================================================

class Window_EquipSkillData < Window_LearnData
  
  #--------------------------------------------------------------------------
  # main_window=
  #--------------------------------------------------------------------------
  def main_window=(new_window)
    @main_window = new_window
    refresh
  end
  
  #--------------------------------------------------------------------------
  # refresh
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    @skill = @main_window.skill
    draw_obj_name
    dy = WLH
    dy = draw_requirements(dy)
    dy = draw_properties(dy) if @skill != nil
  end
  
  #--------------------------------------------------------------------------
  # draw_obj_name
  #--------------------------------------------------------------------------
  def draw_obj_name
    if @skill == nil
      draw_icon(Icon.empty_skill, 0, 0, false)
      self.contents.font.size = Font.default_size
      self.contents.font.color = normal_color
      self.contents.font.color.alpha = 128
      name = Vocab.empty_skill
      self.contents.draw_text(24, 0, contents.width-24, WLH, name, 0)
    else
      super
    end
  end
  
  #--------------------------------------------------------------------------
  # draw_properties
  #--------------------------------------------------------------------------
  def draw_requirements(dy)
    return dy unless YEM::SKILL_EQUIP::SHOW_RESTRICTIONS
    dy = draw_requirement_title(dy)
    dy = draw_limitations(dy)
    return dy
  end
  
  #--------------------------------------------------------------------------
  # draw_requirement_title
  #--------------------------------------------------------------------------
  def draw_requirement_title(dy)
    return dy if dy + WLH > contents.height
    self.contents.font.size = YEM::SKILL::LEARN_DATA[:fontsize]
    self.contents.font.color = system_color
    text = YEM::SKILL_EQUIP::RESTRICTION_TITLE
    self.contents.draw_text(4, dy, contents.width-8, WLH, text, 1); dy += WLH
    return dy
  end
  
  #--------------------------------------------------------------------------
  # draw_limitations
  #--------------------------------------------------------------------------
  def draw_limitations(dy)
    return dy if dy + WLH > contents.height
    for type in YEM::SKILL_EQUIP::RESTRICT_ORDER
      return dy if dy + WLH > contents.height
      next unless YEM::SKILL_EQUIP::RESTRICTIONS[type][2]
      next if @actor.equip_skill_limit_max(type) <= 0
      max_skills = @actor.max_equipped_skills
      next if YEM::SKILL_EQUIP::RESTRICTIONS[type][1] > max_skills
      draw_icon(Icon.skill_limit(type), 0, dy)
      self.contents.font.size = YEM::SKILL::LEARN_DATA[:fontsize]
      self.contents.font.color = system_color
      self.contents.draw_text(24, dy, contents.width-28, WLH, type, 0)
      limit1 = @actor.equip_skill_limit(type)
      limit2 = @actor.equip_skill_limit_max(type)
      text = sprintf("%s/%s", limit1, limit2)
      if limit1 < limit2
        self.contents.font.color = normal_color
      elsif limit1 == limit2
        self.contents.font.color = crisis_color
      elsif limit1 > limit2
        self.contents.font.color = knockout_color
      end
      self.contents.draw_text(4, dy, contents.width-8, WLH, text, 2)
      dy += WLH
    end
    return dy
  end
  
end # Window_EquipSkillData

#===============================================================================
# Window_EquipSkillReplace
#===============================================================================

class Window_EquipSkillReplace < Window_Selectable
  
  #--------------------------------------------------------------------------
  # initialize
  #--------------------------------------------------------------------------
  def initialize(actor, help_window)
    @actor = actor
    @help_window = help_window
    dy = @help_window.y + @help_window.height
    super(0, dy, Graphics.width - 240, Graphics.height - dy)
    refresh
    self.active = false
    self.index = 0
  end
  
  #--------------------------------------------------------------------------
  # replace_skill
  #--------------------------------------------------------------------------
  def replace_skill(skill)
    @replace_skill = skill
    refresh
  end
  
  #--------------------------------------------------------------------------
  # skill
  #--------------------------------------------------------------------------
  def skill; return @data[self.index]; end
  
  #--------------------------------------------------------------------------
  # actor=
  #--------------------------------------------------------------------------
  def actor=(new_actor)
    @actor = new_actor
    self.index = 0
    refresh
  end
  
  #--------------------------------------------------------------------------
  # refresh
  #--------------------------------------------------------------------------
  def refresh
    @data = [nil]
    for skill in @actor.skills
      next unless include?(skill)
      @data.push(skill)
    end
    @data.push(nil) if @data.size > 8
    @item_max = @data.size
    self.index = [[self.index, @item_max-1].min, 0].max
    create_contents
    for i in 0...@item_max; draw_item(i); end
  end
    
  #--------------------------------------------------------------------------
  # include?
  #--------------------------------------------------------------------------
  def include?(skill)
    return false if skill != nil and skill.name == ""
    return true
  end
  
  #--------------------------------------------------------------------------
  # draw_item
  #--------------------------------------------------------------------------
  def draw_item(index)
    rect = item_rect(index)
    self.contents.clear_rect(rect)
    skill = @data[index]
    enabled = enabled?(skill)
    draw_obj_name(skill, rect.clone, enabled) if skill != nil
    draw_empty(skill, rect, true) if skill == nil
  end
  
  #--------------------------------------------------------------------------
  # enabled?
  #--------------------------------------------------------------------------
  def enabled?(skill)
    return true if skill == nil
    return true if skill == @replace_skill
    return false if @actor.equipped_skills.include?(skill)
    clone = Marshal.load(Marshal.dump(@actor))
    clone.forget_skill(@replace_skill.id) if @replace_skill != nil
    return clone.can_equip_skill?(skill)
  end
  
  #--------------------------------------------------------------------------
  # new method: draw_obj_name
  #--------------------------------------------------------------------------
  def draw_obj_name(obj, rect, enabled)
    draw_obj_limits(obj, rect, enabled)
    draw_icon(obj.icon_index, rect.x, rect.y, enabled)
    self.contents.font.size = Font.default_size
    self.contents.font.color = normal_color
    self.contents.font.color.alpha = enabled ? 255 : 128
    rect.width -= 96
    self.contents.draw_text(rect.x+24, rect.y, rect.width, WLH, obj.name, 0)
  end
  
  #--------------------------------------------------------------------------
  # new method: draw_obj_limits
  #--------------------------------------------------------------------------
  def draw_obj_limits(obj, rect, enabled)
    dx = 24
    for type in YEM::SKILL_EQUIP::RESTRICT_ORDER.reverse
      next unless YEM::SKILL_EQUIP::RESTRICTIONS[type][2]
      next unless obj.limit_type.include?(type)
      draw_icon(Icon.skill_limit(type), rect.width-dx, rect.y, enabled)
      dx += 24
    end
  end
  
  #--------------------------------------------------------------------------
  # new method: draw_empty
  #--------------------------------------------------------------------------
  def draw_empty(obj, rect, enabled)
    draw_icon(Icon.empty_skill, rect.x, rect.y, enabled)
    self.contents.font.size = Font.default_size
    self.contents.font.color = normal_color
    self.contents.font.color.alpha = enabled ? 255 : 128
    rect.width -= 96; name = Vocab.empty_skill
    self.contents.draw_text(rect.x+24, rect.y, rect.width, WLH, name, 0)
  end
  
  #--------------------------------------------------------------------------
  # update_help
  #--------------------------------------------------------------------------
  def update_help
    none = Vocab.empty_skill_help
    @help_window.set_text(skill == nil ? none : skill.description)
  end
  
end # Window_EquipSkillReplace

#===============================================================================
# Window_CopySkill
#===============================================================================

class Window_CopySkill < Window_Selectable
  
  #--------------------------------------------------------------------------
  # initialize
  #--------------------------------------------------------------------------
  def initialize(actor, skill, targets)
    @actor = actor
    @skill = skill
    @targets = targets
    dx = YEM::SKILL_EQUIP::COPY_SKILL_WINDOW_X
    dy = YEM::SKILL_EQUIP::COPY_SKILL_WINDOW_Y
    dw = Graphics.width - dx * 2
    dh = Graphics.height - dy - 144
    @description_window = Window_Base.new(dx, dy, dw, 56)
    dy += 56
    dh -= 56
    super(dx, dy, dw, dh)
    @column_max = 2
    @spacing = 4
    self.index = 0
    refresh
  end
  
  #--------------------------------------------------------------------------
  # skill
  #--------------------------------------------------------------------------
  def skill; return @data[self.index]; end
  
  #--------------------------------------------------------------------------
  # set_viewport
  #--------------------------------------------------------------------------
  def set_viewport(viewport)
    self.viewport = viewport
    @description_window.viewport = viewport
  end
  
  #--------------------------------------------------------------------------
  # dispose
  #--------------------------------------------------------------------------
  def dispose
    super
    @description_window.dispose
  end
  
  #--------------------------------------------------------------------------
  # refresh
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    @description_window.contents.clear
    dw = @description_window.contents.width
    text = YEM::SKILL_EQUIP::COPY_SKILL_DESCRIPTION
    @description_window.contents.draw_text(0, 0, dw, WLH, text, 1)
    #---
    @data = []
    for target in @targets
      next if target == @actor
      if target.actor?
        for skill in target.battle_skills
          @data.push(skill) if include?(skill)
        end
      else
        for skill in target.total_skills
          @data.push(skill) if include?(skill)
        end
      end
    end
    @data.sort! { |a,b| a.name <=> b.name }
    @item_max = @data.size
    create_contents
    for i in 0...@item_max; draw_item(i); end
  end
  
  #--------------------------------------------------------------------------
  # include?
  #--------------------------------------------------------------------------
  def include?(skill)
    return false if skill == nil
    return false if skill.cannot_copy
    return false if @data.include?(skill)
    for type in @skill.copy_type
      return true if skill.skill_type.include?(type.upcase)
    end
    return false
  end
  
  #--------------------------------------------------------------------------
  # draw_item
  #--------------------------------------------------------------------------
  def draw_item(index)
    rect = item_rect(index)
    self.contents.clear_rect(rect)
    skill = @data[index]
    return if skill == nil
    enabled = enabled?(skill)
    draw_icon(skill.icon_index, rect.x, rect.y, enabled)
    text = skill.name
    self.contents.font.color = normal_color
    self.contents.font.color.alpha = enabled ? 255 : 128
    self.contents.draw_text(rect.x+24, rect.y, rect.width-28, WLH, text, 0)
  end
  
  #--------------------------------------------------------------------------
  # enable?
  #--------------------------------------------------------------------------
  def enabled?(skill)
    return false if @actor.battle_skills.include?(skill)
    return true
  end
  
end # Window_CopySkill

#===============================================================================
# Scene_Battle
#===============================================================================

class Scene_Battle < Scene_Base
  
  #--------------------------------------------------------------------------
  # alias method: start
  #--------------------------------------------------------------------------
  alias start_ses start unless $@
  def start
    for member in $game_party.members; member.clear_copied_skills; end
    start_ses
  end
  
  #--------------------------------------------------------------------------
  # alias method: battle_end
  #--------------------------------------------------------------------------
  alias battle_end_ses battle_end unless $@
  def battle_end(result)
    for member in $game_party.members; member.clear_copied_skills; end
    battle_end_ses(result)
  end
  
  unless $imported["BattleEngineMelody"]
  #--------------------------------------------------------------------------
  # alias method: execute_action_skill
  #--------------------------------------------------------------------------
  alias execute_action_skill_ses execute_action_skill unless $@
  def execute_action_skill
    @copy_targets = []
    skill = @active_battler.action.skill
    execute_action_skill_ses
    perform_copy_skill(skill)
  end
  end
  
  #--------------------------------------------------------------------------
  # alias method: display_action_effects
  #--------------------------------------------------------------------------
  alias display_action_effects_ses display_action_effects unless $@
  def display_action_effects(target, obj = nil)
    display_action_effects_ses(target, obj)
    return if target.skipped
    return unless obj.is_a?(RPG::Skill)
    @copy_targets = [] if @copy_targets == nil
    @copy_targets.push(target)
  end
  
  #--------------------------------------------------------------------------
  # new method: perform_copy_skill
  #--------------------------------------------------------------------------
  def perform_copy_skill(skill = nil)
    return unless @active_battler.actor?
    skill = @active_battler.action.skill if skill == nil
    return if skill.copy_type == []
    @copy_targets = [] if @copy_targets == nil
    @copy_window = Window_CopySkill.new(@active_battler, skill, @copy_targets)
    if $imported["BattleEngineMelody"]
      pause_atb(true)
      @copy_window.set_viewport(@spriteset.viewportC)
    end
    loop do
      update_basic
      @copy_window.update
      if Input.trigger?(Input::B)
        Sound.play_cancel
        break
      elsif Input.trigger?(Input::C)
        target_skill = @copy_window.skill
        if @copy_window.enabled?(target_skill)
          Sound.play_decision
          slot = @active_battler.battle_skills.index(skill)
          @active_battler.copy_skill(slot, target_skill.id)
          break
        else
          Sound.play_buzzer
        end
      end
    end
    @copy_window.dispose
    @copy_window = nil
    pause_atb(false) if $imported["BattleEngineMelody"]
  end
  
end # Scene_Battle

#===============================================================================
# Scene_Skill
#===============================================================================

class Scene_Skill < Scene_Base
  
  #--------------------------------------------------------------------------
  # new method: create_equip_skill_windows
  #--------------------------------------------------------------------------
  def create_equip_skill_windows
    @equip_skill_window = Window_EquipSkill.new(@actor, @help_window)
    @equip_skill_data = Window_EquipSkillData.new(@actor, @equip_skill_window)
    @equip_skill_replace = Window_EquipSkillReplace.new(@actor, @help_window)
    @windows.push(@equip_skill_window)
    @windows.push(@equip_skill_data)
    @windows.push(@equip_skill_replace)
  end
  
  #--------------------------------------------------------------------------
  # new method: show_equip_skill_windows
  #--------------------------------------------------------------------------
  def show_equip_skill_windows
    @help_window.y = 128
    @equip_skill_window.y = @help_window.y + @help_window.height
    @equip_skill_data.y = @equip_skill_window.y
    @equip_skill_window.update_help
  end
  
  #--------------------------------------------------------------------------
  # new method: update_skill_equip_selection
  #--------------------------------------------------------------------------
  def update_skill_equip_selection
    @equip_skill_window.update
    @equip_skill_data.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @command_window.active = true
      @equip_skill_window.active = false
    elsif Input.repeat?(Input::RIGHT)
      Sound.play_cursor
      next_actor
    elsif Input.repeat?(Input::LEFT)
      Sound.play_cursor
      prev_actor
    elsif Input.trigger?(Input::A)
      slot = @equip_skill_window.index
      return if @actor.equipped_skills[slot] == nil
      Sound.play_equip
      @actor.equip_skill(slot, 0)
      @equip_skill_window.draw_item(slot)
    elsif Input.trigger?(Input::X)
      clone_array = @actor.equipped_skills.clone
      @actor.sort_equipped_skills
      @equip_skill_window.refresh
      Sound.play_equip if @actor.equipped_skills != clone_array
    elsif Input.trigger?(Input::C) or ($TEST and Input.trigger?(Input::F8))
      Sound.play_decision
      skill = @equip_skill_window.skill
      @equip_skill_replace.y = @equip_skill_window.y
      @equip_skill_replace.replace_skill(skill)
      @equip_skill_data.main_window = @equip_skill_replace
      @equip_skill_replace.active = true
      @equip_skill_window.active = false
      @equip_skill_window.y = Graphics.height*8
    end
  end
  
  #--------------------------------------------------------------------------
  # new method: update_skill_equip_replacement
  #--------------------------------------------------------------------------
  def update_skill_equip_replacement
    @equip_skill_replace.update
    @equip_skill_data.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @equip_skill_window.y = @equip_skill_replace.y
      @equip_skill_data.main_window = @equip_skill_window
      @equip_skill_window.active = true
      @equip_skill_replace.active = false
      @equip_skill_replace.y = Graphics.height*8
    #--- Debug Commands ---
    elsif $TEST and Input.trigger?(Input::F8) # Force Equip
      Sound.play_equip
      skill = @equip_skill_replace.skill
      apply_equip_skill(skill)
    #--- Debug Commands ---
    elsif Input.trigger?(Input::C)
      skill = @equip_skill_replace.skill
      if @equip_skill_replace.enabled?(skill)
        Sound.play_equip
        apply_equip_skill(skill)
      else
        Sound.play_buzzer
      end
    end
  end
  
  #--------------------------------------------------------------------------
  # new method: apply_equip_skill
  #--------------------------------------------------------------------------
  def apply_equip_skill(skill)
    skill_id = skill == nil ? 0 : skill.id
    slot = @equip_skill_window.index
    Sound.play_equip
    @actor.equip_skill(slot, skill_id)
    @equip_skill_window.draw_item(slot)
    @equip_skill_window.y = @equip_skill_replace.y
    @equip_skill_data.main_window = @equip_skill_window
    @equip_skill_window.active = true
    @equip_skill_replace.active = false
    @equip_skill_replace.y = Graphics.height*8
    @status_window.refresh
  end
  
end # Scene_Skill

#===============================================================================
# 
# END OF FILE
# 
#===============================================================================