# )----------------------------------------------------------------------------(
# )--     AUTHOR:     Mr. Trivel                                             --(
# )--     NAME:       Learn Skills from Items                                --(
# )--     CREATED:    2014-06-18                                             --(
# )--     VERSION:    1.2                                                    --(
# )----------------------------------------------------------------------------(
# )--                        VERSION HISTORY:                                --(
# )--  v1.0 - Initial script.                                                --(
# )--  v1.1 - Added 2 customizable options - LP_ON_UNEQUIP and <LearnedOnly> --(
# )--  v1.2 - Parts of script rewritten for better speed and compatibility.  --(
# )----------------------------------------------------------------------------(
# )--                          DESCRIPTION                                   --(
# )--  Equipment can have a spell inside of them which requires X amount of  --(
# )--  Learning Points (further LP). LP is gained from slaying enemies.      --(
# )--  Once Actor reaches required LP for that spell, he learns it forever.  --(
# )--                                                                        --(
# )--  Each Class has school affinities. E.g. Healing school affinity will   --(
# )--  help Actor learn healing skills Y times faster, but Destruction spells--(
# )--  Z times slower.                                                       --(
# )--  Actor can use item skills before learning it while item is equipped.  --(
# )----------------------------------------------------------------------------(
# )--                          INSTRUCTIONS                                  --(
# )--      CLASS:                                                            --(
# )--  <Schools: A, B, C, D> E.g. <Schools : 0.5, 1.5, 1, 2> will set school --(
# )--  affinities to 0.5 for Healing, 1.5 for Destruction, 1 for Conjuration --(
# )--  and 2 for Laziness. 0.5 - means actor will receive only 50% of LP for --(
# )--  that school's spell. 2 - actor will receive 200% of LP for that       --(
# )--  school's spell.                                                       --(
# )--                                                                        --(
# )--      EQUIPMENT:                                                        --(
# )--  <Skills: A, B, C> E.g. <Skills: 26, 27, 28> in an Equipmenet Note tag --(
# )--  will mean that it holds 26th, 26th and 28th Skill in database.        --(
# )--                                                                        --(
# )--      SKILL:                                                            --(
# )--  <LpCost: X> E.g. <LPCost: 120> means that it requires 120 LP to be    --(
# )--  learned.                                                              --(
# )--  <School: X> E.g. <School: 0> means the Skill's affinity is Healing.   --(
# )--  So classes Healing affinity affects LP of this skill.                 --(
# )--  <LearnedOnly> Skill has to be learned first before player can use it. --(
# )--                                                                        --(
# )--      ENEMY:                                                            --(
# )--  <LP: X> E.g. <LP: 10> means that enemy will give 10 base LP when it's --(
# )--  slain.                                                                --(
# )----------------------------------------------------------------------------(
# )--                          LICENSE INFO                                  --(
# )--   [url]http://mrtrivelvx.wordpress.com/terms-of-use/[/url]                        --(
# )----------------------------------------------------------------------------(

module MrTS
  module Spell_Learning
    # )------------------------------------------------------------------------(
    # )--  Does Actor lose all LP for the skill on equipment if unequips it? --(
    # )------------------------------------------------------------------------(
    LOSE_LP_ON_UNEQUIP = true
    
    # )------------------------------------------------------------------------(
    # )--  Your school names go here. If you wanna call the names.           --(
    # )------------------------------------------------------------------------(
    SchoolNames= ["Healing",
                  "Destruction",
                  "Conjuration",
                  "Laziness"
                  ]
    # )------------------------------------------------------------------------(
    # )--  Number of schools you're going to have.                           --(
    # )------------------------------------------------------------------------(
    NumberOfSchools = 4
    
    # )------------------------------------------------------------------------(
    DefaultSpellLearningCost = 30#If not defined, spell will cost 30 LP to learn
    DefaultSpellSchool = 0               #If not defined will return school as 0
    DefaultLP = 1                # Default number of Learning Points enemy gives
    # )------------------------------------------------------------------------(
    
    
    # )------------------------------------------------------------------------(
    # )-- You can call MrTS::Spell_Learning::get_school_name(index) to get   --(
    # )-- school's name.                                                     --(
    # )------------------------------------------------------------------------(
    def self.get_school_name(index)
      SchoolNames[index] ? SchoolNames[index] : nil
    end
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: Game_Troop                                                      --(
# )----------------------------------------------------------------------------(
class Game_Troop < Game_Unit
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: lp_total                                                 --(
  # )--------------------------------------------------------------------------(
  def lp_total
    dead_members.inject(0) {|r, enemy| r += enemy.lp }
  end
end

# )----------------------------------------------------------------------------(
# )-- Module: BattleManager                                                  --(
# )----------------------------------------------------------------------------(
module BattleManager
  class << self ; alias :mrts_itsk_gain_exp :gain_exp ; end
    
  # )--------------------------------------------------------------------------(
  # )-- Alias Method: gain_exp                                               --(
  # )--------------------------------------------------------------------------(  
  def self.gain_exp
    $game_party.battle_members.each { |a| a.add_lp($game_troop.lp_total) }
    mrts_itsk_gain_exp
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: Game_Enemy                                                      --(
# )----------------------------------------------------------------------------(
class Game_Enemy < Game_Battler
  
  # )--------------------------------------------------------------------------(
  # )-- Public Instance Variables                                            --(
  # )--------------------------------------------------------------------------(
  attr_reader   :lp
  
  # )--------------------------------------------------------------------------(
  # )-- Alias To: initialize                                                 --(
  # )--------------------------------------------------------------------------(
  alias mrts_initialize initialize
  def initialize(index, enemy_id)
    mrts_initialize(index, enemy_id)
    @lp = enemy.lpgive
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: Game_Actor                                                      --(
# )----------------------------------------------------------------------------(
class Game_Actor < Game_Battler
  
  # )--------------------------------------------------------------------------(
  # )-- ublic Instance Variables                                             --(
  # )--------------------------------------------------------------------------(
  attr_reader   :learning_points
  attr_reader   :school_affinities

  # )--------------------------------------------------------------------------(
  # )-- Alias To: setup                                                      --(
  # )--------------------------------------------------------------------------(
  alias mrts_ga_setup setup
  def setup(actor_id)
    mrts_ga_setup(actor_id)
    setup_lp
  end
  
  # )--------------------------------------------------------------------------(
  # )-- Alias To: release_unequippable_items                                 --(
  # )--------------------------------------------------------------------------(
  alias mrts_release_unequippable_items release_unequippable_items
  def release_unequippable_items(item_gain = true)
    mrts_release_unequippable_items
    return unless MrTS::Spell_Learning::LOSE_LP_ON_UNEQUIP
    eq_ar = get_equips_skills
    @learning_points.each_key do |key|
      @learning_points[key] = 0 unless eq_ar.include?(key)
    end if @learning_points
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: setup_lp                                                 --(
  # )--------------------------------------------------------------------------(
  def setup_lp
    @learning_points = {}
    @school_affinities = []
    schools = self.class.note =~ /<schools:\s*(\d+.*\d*),*>/i ? $1 : nil
    schools.scan(/(\d+\.*\d*)/).collect do |i|
      @school_affinities.push(i[0].to_f)
    end if schools
    @school_affinities += [1.0]*MrTS::Spell_Learning::NumberOfSchools unless @school_affinities.size > 0
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: add_lp                                                   --(
  # )--------------------------------------------------------------------------(
  def add_lp(amount)
    ar_sk = get_equips_skills
    ar_sk.each do |i| 
      add_learning_points(i, amount) 
    end if ar_sk.size > 0
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: get_equips_skills                                        --(
  # )--------------------------------------------------------------------------(
  def get_equips_skills
    arr = []
    equips.each do |eq|
      arr += eq.lp_skills_held if eq
    end
    arr = arr.uniq if arr.size > 1
    arr
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: add_learning_points                                      --(
  # )--------------------------------------------------------------------------(
  def add_learning_points(skill_id, amount)
    return if @skills.include?(skill_id)
    if @learning_points.has_key?(skill_id)
      @learning_points[skill_id] += (amount * get_school_multiplier(skill_id)).to_i
    else
      @learning_points[skill_id] = (amount * get_school_multiplier(skill_id)).to_i
    end
    try_to_learn(skill_id)
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: get_school_multiplier                                    --(
  # )--------------------------------------------------------------------------(
  def get_school_multiplier(skill_id)
    @school_affinities[$data_skills[skill_id].lpschool]
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: try_to_learn                                             --(
  # )--------------------------------------------------------------------------(
  def try_to_learn(skill_id)
    if @learning_points[skill_id] >= $data_skills[skill_id].lpcost
      learn_skill(skill_id)
      @learning_points.delete(skill_id)
    end
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: get_lp_skill_from                                        --(
  # )--------------------------------------------------------------------------(
  def get_lp_skill_from(skill_id)
    @learning_points[skill_id] ? @learning_points[skill_id] : 0
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: include_skill?                                           --(
  # )--------------------------------------------------------------------------(
  def include_skill?(skill_id)
    @skills.include?(skill_id)
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: Window_SkillList                                                --(
# )----------------------------------------------------------------------------(
class Window_SkillList < Window_Selectable
  
  # )--------------------------------------------------------------------------(
  # )-- Overwrite Method: make_item_list                                     --(
  # )--------------------------------------------------------------------------(
  def make_item_list
    @data = @actor ? @actor.skills.select {|skill| include?(skill) } : []
    arr = []
    @actor.equips.each { |eq| arr += eq.lp_skills_held if eq }
    arr = arr.uniq
    arr.each do |a| 
      skill = Marshal.load(Marshal.dump($data_skills[a]))
      @data.push(skill) if include?(skill) && !@actor.include_skill?(skill.id)
      skill.name += " [" + @actor.get_lp_skill_from(a).to_s + "/" + skill.lpcost.to_s + "]"
    end
  end
  
  # )--------------------------------------------------------------------------(
  # )-- Overwrite Method: enable?                                            --(
  # )--------------------------------------------------------------------------(
  def enable?(item)
    @actor && @actor.usable?(item) && (!item.lponly  || @actor.include_skill?(item.id))
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: RPG::Skill                                                      --(
# )----------------------------------------------------------------------------(
class RPG::Skill < RPG::UsableItem
  attr_accessor :lpcost
  attr_accessor :lpschool
  attr_accessor :lponly
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: parse_lp                                                 --(
  # )--------------------------------------------------------------------------(
  def parse_lp
    @lpcost = note =~ /<LPCost:\s*(\d+)>/i ? $1.to_i : MrTS::Spell_Learning::DefaultSpellLearningCost
    @lpschool = note =~ /<school:\s*(\d*)>/i ? $1.to_i : MrTS::Spell_Learning::DefaultSpellSchool
    @lponly = note=~ /<LearnedOnly>/i ? true : false
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: RPG::EquipItem                                                  --(
# )----------------------------------------------------------------------------(
class RPG::EquipItem < RPG::BaseItem
  
  attr_accessor :lp_skills_held
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: parse_lp                                                 --(
  # )--------------------------------------------------------------------------(
  def parse_lp
    array = []
    string = note =~ /<Skills:\s*((\d+,*\s*)*)>/i ? $1 : nil
    string.scan(/(\d+)/).collect do |i|
      array.push(i[0].to_i)
    end if string
    @lp_skills_held = array
  end
end

# )----------------------------------------------------------------------------(
# )-- Class: RPG::EquipItem                                                  --(
# )----------------------------------------------------------------------------(
class RPG::Enemy
  attr_accessor :lpgive
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: parse_lp                                                 --(
  # )--------------------------------------------------------------------------(
  def parse_lp
    @lpgive = note=~ /<LP:\s*(\d*)>/i ? $1.to_i : MrTS::Spell_Learning::DefaultLP
  end
end

# )----------------------------------------------------------------------------(
# )-- Module: DataManager                                                    --(
# )----------------------------------------------------------------------------(
module DataManager
  class << self     
    alias :mrts_lp_create_game_objects    :create_game_objects
  end
  
  # )--------------------------------------------------------------------------(
  # )-- Alias: create_game_objects                                           --(
  # )--------------------------------------------------------------------------(
  def self.create_game_objects
    mrts_lp_create_game_objects
    parse_lp
  end
  
  # )--------------------------------------------------------------------------(
  # )-- New Method: self.parse_lp                                            --(
  # )--------------------------------------------------------------------------(
  def self.parse_lp
    data = $data_skills + $data_armors + $data_weapons + $data_enemies
    for item in data
      next if item.nil?
      item.parse_lp
    end
  end
end