#==============================================================================|
#  ** DoubleX RMVXA Intercept Magic v1.03b                                     |
#------------------------------------------------------------------------------|
#  * Changelog                                                                 |
#    v1.03b(GMT 1400 7-7-2015):                                                |
#    - Improved this script's efficiency and readability                       |
#    v1.03a(GMT 1000 7-12-2014):                                               |
#    - Added <ally intercept>, <enemy intercept> and <intercept chance>notetags|
#    v1.02b(GMT 1000 27-7-2014):                                               |
#    - Fixed crashes with Intercept_MP_Limit or Intercept_TP_Limit being true  |
#    v1.02a(GMT 0700 21-6-2014):                                               |
#    - Added <hit intercept mp> and <hit intercept tp> notetags                |
#    v1.01a(GMT 0200 8-4-2014):                                                |
#    - Allows users to set intercept animations                                |
#    v1.00b(GMT 0900 7-4-2014):                                                |
#    - Fixed intercept magic not working on allies' skills bug                 |
#    v1.00a(GMT 0700 5-4-2014):                                                |
#    - 1st version of this script finished                                     |
#------------------------------------------------------------------------------|
#  * Author                                                                    |
#    DoubleX                                                                   |
#------------------------------------------------------------------------------|
#  * Terms of use                                                              |
#    None other than not claiming this script as created by anyone except      |
#    DoubleX or his alias                                                      |
#------------------------------------------------------------------------------|
#  * Prerequisites                                                             |
#    Scripts:                                                                  |
#    - none                                                                    |
#    Knowledge:                                                                |
#    - Use of notetags                                                         |
#------------------------------------------------------------------------------|
#  * Functions                                                                 |
#    - Allows users to set states that intercepts magic under some conditions  |
#------------------------------------------------------------------------------|
#  * Manual                                                                    |
#    To use this script, open the script editor and put this script into an    |
#    open slot between ▼ Materials and ▼ Main. Save to take effect.            |
#------------------------------------------------------------------------------|
#  * Compatibility                                                             |
#    Scripts aliasing or rewriting method:                                     |
#    - self.load_database under module DataManager                             |
#    - add_state under class Game_Battler                                      |
#    - use_item under class Scene_Battle                                       |
#    may have compatibility issues with this script                            |
#    Place this script above those aliasing any of these method if possible    |
#==============================================================================|

($imported ||= {})["DoubleX RMVXA Intercept Magic"] = true

#==============================================================================|
#  ** You only need to edit this part as it's about what this script does      |
#------------------------------------------------------------------------------|

module DoubleX_RMVXA
  module Intercept_Magic

#------------------------------------------------------------------------------|
#  * Notetag <intercept tier: x> for skills and states:                        |
#    - Allows battlers having states with this notetag to intercept skills with|
#      this notetag(x must be greater than 0 in order for this notetag to work)|
#    - If the intercept tier of the states is greater than or equal to that of |
#      the skills, those skills will be intercepted if other conditions are met|
#    - If more than 1 battler can intercept a skill, the one having any        |
#      intercept state for the shortest time will intercept the skill          |
#    - This notetag needs <ally intercept> or <enemy intercept> to be present  |
#      to work(they can be used together to let any battler be the interceptor)|
#------------------------------------------------------------------------------|
#  * Notetag <intercept mp> for skills and states:                             |
#    - Interceptors having states with this notetag absorb mp equal to the mp  |
#      cost of the skills intercepted if those skills also have this notetag   |
#    - Put this notetag below <intercept tier: x> to make this notetag work    |
#------------------------------------------------------------------------------|
#  * Notetag <intercept tp> for skills and states:                             |
#    - Interceptors having states with this notetag absorb tp equal to the tp  |
#      cost of the skills intercepted if those skills also have this notetag   |
#    - Put this notetag below <intercept tier: x> to make this notetag work    |
#------------------------------------------------------------------------------|
#  * (v1.02a+)Notetag <hit intercept mp> for skills and states:                |
#    - Failed interceptions due to Intercept_MP_Limit will cause the skill to  |
#      only hit the interceptor if both the skills and states have this notetag|
#------------------------------------------------------------------------------|
#  * (v1.02a+)Notetag <hit intercept tp> for skills and states:                |
#    - Failed interceptions due to Intercept_TP_Limit will cause the skill to  |
#      only hit the interceptor if both the skills and states have this notetag|
#------------------------------------------------------------------------------|
#  * (v1.03a+)Notetag <ally intercept> for skills and states:                  |
#    - Interceptors having states with this notetag can intercept skills with  |
#      this notetag if their users are allies and other conditions are met     |
#    - Putting this notetag above <enemy intercept> means allies will always   |
#      intercept the skills if enemies can also intercept them                 |
#    - The ordering of <ally intercept> and <enemy intercept> in skills to be  |
#      intercepted will be used if intercepting states also has those notetags |
#    - Put this notetag below <intercept tier: x> to make this notetag work    |
#------------------------------------------------------------------------------|
#  * (v1.03a+)Notetag <enemy intercept> for skills and states:                 |
#    - Interceptors having states with this notetag can intercept skills with  |
#      this notetag if their users are enemies and other conditions are met    |
#    - Putting this notetag above <ally intercept> means enemies will always   |
#      intercept the skills if allies can also intercept them                  |
#    - The ordering of <ally intercept> and <enemy intercept> in skills to be  |
#      intercepted will be used if intercepting states also has those notetags |
#    - Put this notetag below <intercept tier: x> to make this notetag work    |
#------------------------------------------------------------------------------|
#  * (v1.03a+)Notetag <intercept chance: x> for skills and states:             |
#    - Interceptors having states with this notetag have a x% chance to        |
#      intercept skills that can be intercepted if other conditions are met    |
#    - Skills that can be intercepted with this notetag have a x% chance to be |
#      intercepted by interceptors if other conditions are met                 |
#    - The real chance of success is that of intercepting states multiplied by |
#      that of skills to be intercepted                                        |
#    - If this notetag is absent, the chance of success will be 100%           |
#------------------------------------------------------------------------------|

#------------------------------------------------------------------------------|
#  * (v1.01a+)Intercept_Animation_Id, default = 0                              |
#    Animations with id Intercept_Animation_Id will be played upon interception|
#    if 0 < Intercept_Animation_Id < 1000                                      |
#------------------------------------------------------------------------------|
  Intercept_Animation_Id = 0

#------------------------------------------------------------------------------|
#  * Intercept_SE, default = RPG::SE.new(File, Volume, Pitch)                  |
#    SE file File with volume Volume and pitch Pitch will be played upon       |
#    successful interceptions                                                  |
#------------------------------------------------------------------------------|
  # File is a SE file without specifying its extension and with or without
  # specifying its path
  # Volume and Pitch range from 1 to 100 and 5 to 200 respectively
  # Setting Intercept_SE as nil or false will disable this feature
  Intercept_SE = RPG::SE.new("Absorb1", 80, 100)

#------------------------------------------------------------------------------|
#  * Intercept_Times_Limit, default = 0                                        |
#    Intercept states will worn off after its battlers intercepted             |
#    Intercept_Times_Limit skills(0 here means no such limit)                  |
#------------------------------------------------------------------------------|
  Intercept_Times_Limit = 0

#------------------------------------------------------------------------------|
#  * (v1.02a+)Count_Fail_Intercept, default = true                             |
#    Failed interceptions will also be counted for Intercept_Times_Limit       |
#------------------------------------------------------------------------------|
  Count_Fail_Intercept = true

#------------------------------------------------------------------------------|
#  * Intercept_MP_Limit, default = true                                        |
#    If Intercept_MP_Limit is true and the interceptors' MP will be greater    |
#    than their MMP after intercepting a skill, that skill can't be intercepted|
#------------------------------------------------------------------------------|
  Intercept_MP_Limit = true

#------------------------------------------------------------------------------|
#  * Intercept_TP_Limit, default = true                                        |
#    If Intercept_TP_Limit is true and the interceptors' TP will be greater    |
#    than their max TP value after intercepting a skill, that skill can't be   |
#    intercepted                                                               |
#------------------------------------------------------------------------------|
  Intercept_TP_Limit = true

#------------------------------------------------------------------------------|
#  * Intercept_Learnt_Skill, default = true                                    |
#    Battlers can only intercept skills that they're learnt                    |
#------------------------------------------------------------------------------|
  Intercept_Learnt_Skill = true

#------------------------------------------------------------------------------|
#  * Intercept_Usable_Skill, default = true                                    |
#    Battlers can only intercept skills that they can use at the moment        |
#------------------------------------------------------------------------------|
  Intercept_Usable_Skill = true

#------------------------------------------------------------------------------|
#  * Intercept_Learn_Skill, default = false                                    |
#    Successful interceptions causes interceptors to learn intercepted skills  |
#------------------------------------------------------------------------------|
  Intercept_Learn_Skill = false

#------------------------------------------------------------------------------|
#  * Intercept_MCR, default = true                                             |
#    The MP absorbed by the interceptor will be the actual MP used by the users|
#    of the skills intercepted If Intercept_MCR is true                        |
#------------------------------------------------------------------------------|
  Intercept_MCR = true

  end # Intercept_Magic
end # DoubleX_RMVXA

#==============================================================================|

#==============================================================================|
#  ** You need not edit this part as it's about how this script works          |
#------------------------------------------------------------------------------|

class << DataManager

  #----------------------------------------------------------------------------|
  #  Alias method: load_database                                               |
  #----------------------------------------------------------------------------|
  alias load_database_intercept_magic load_database
  def load_database
    load_database_intercept_magic
    # Added to load intercept magic notetags
    load_notetags_intercept_magic
    #
  end # load_database

  #----------------------------------------------------------------------------|
  #  New method: load_notetags_intercept_magic                                 |
  #----------------------------------------------------------------------------|
  def load_notetags_intercept_magic
    [$data_skills, $data_states].each { |data|
      data.each { |obj| obj.load_notetags_intercept_magic if obj }
    }
  end # load_notetags_intercept_magic

end # DataManager

class RPG::BaseItem

  #----------------------------------------------------------------------------|
  #  New public instance variables                                             |
  #----------------------------------------------------------------------------|
  attr_accessor :intercept_tier
  attr_accessor :intercept_mp
  attr_accessor :intercept_tp
  attr_accessor :hit_intercept_mp
  attr_accessor :hit_intercept_tp
  attr_accessor :battler_intercept
  attr_accessor :intercept_chance

  #----------------------------------------------------------------------------|
  #  New method: load_notetags_intercept_magic                                 |
  #----------------------------------------------------------------------------|
  def load_notetags_intercept_magic
    im = DoubleX_RMVXA::Intercept_Magic
    @intercept_tier = 0
    @intercept_chance =100
    @battler_intercept = {}
    @intercept_mp = @intercept_tp = false
    @hit_intercept_mp = @hit_intercept_tp = false
    @note.split(/[\r\n]+/).each { |line|
      case line
      when /<(?:INTERCEPT_TIER|intercept tier):[ ]*(\d+)>/i
        @intercept_tier = $1.to_i if $1.to_i > @intercept_tier
      when /<(?:INTERCEPT_MP|intercept mp)>/i
        @intercept_mp ||= @intercept_tier > 0
      when /<(?:INTERCEPT_TP|intercept tp)>/i
        @intercept_tp ||= @intercept_tier > 0
      when /<(?:HIT_INTERCEPT_MP|hit intercept mp)>/i
        @hit_intercept_mp ||= im::Intercept_MP_Limit && @intercept_mp
      when /<(?:HIT_INTERCEPT_TP|hit intercept tp)>/i
        @hit_intercept_tp ||= im::Intercept_TP_Limit && @intercept_tp
      when /<(?:ALLY_INTERCEPT|ally intercept)>/i
        @battler_intercept[:ally] = true
      when /<(?:ENEMY_INTERCEPT|enemy intercept)>/i
        @battler_intercept[:enemy] = true
      when /<(?:INTERCEPT_CHANCE|intercept chance):[ ]*(\d+)>/i
        @intercept_chance = $1.to_i if $1.to_i < @intercept_chance
      end
    }
    @intercept_chance /= 100.0
  end # load_notetags_intercept_magic

end # RPG::BaseItem

module Vocab

  InterceptMagic = "%s intercepts the skill!"
  LearnInterceptMagic = "%s learns the intercepted skill!"
  FailInterceptMagic = "%s fails to intercept the skill!"

end # Vocab

class Game_Temp

  #----------------------------------------------------------------------------|
  #  New public instance variable                                              |
  #----------------------------------------------------------------------------|
  attr_accessor :skill_interceptor

  #----------------------------------------------------------------------------|
  #  (v1.03b+)Alias method: initialize                                         |
  #----------------------------------------------------------------------------|
  alias initialize_intercept_magic initialize
  def initialize
    initialize_intercept_magic
    # Added to initialize the array storing all skill interceptors
    @skill_interceptor = []
    #
  end # initialize

  #----------------------------------------------------------------------------|
  #  New method: intercept_order                                               |
  #----------------------------------------------------------------------------|
  def intercept_order(subject)
    @skill_interceptor.each_with_index { |battler, index|
      return index + 1 if battler == subject
    }
  end # intercept_order

end # Game_Temp

class Game_Action

  #----------------------------------------------------------------------------|
  #  (v1.02a+)New method: fail_intercept                                       |
  #----------------------------------------------------------------------------|
  def fail_intercept(target)
    return [target] if item.for_user?
    return [target] * item.number_of_targets if item.for_random?
    if item.for_one?
      return [target] * (1 + (attack? ? subject.atk_times_add.to_i : 0))
    end
    return [target] * opponents_unit.alive_members.size if item.for_opponent?
    return [target] * friends_unit.dead_members.size if item.for_dead_friend?
    [target] * friends_unit.alive_members.size
  end # fail_intercept

end # Game_Action

class Game_BattlerBase

  #----------------------------------------------------------------------------|
  #  New public instance variables                                             |
  #----------------------------------------------------------------------------|
  attr_accessor :intercept_order
  attr_accessor :intercept_times

  #----------------------------------------------------------------------------|
  #  (v1.03b+)Alias method: initialize                                         |
  #----------------------------------------------------------------------------|
  alias initialize_intercept_magic initialize
  def initialize
    initialize_intercept_magic
    # Added to initialize the order of this battler among all interceptors
    @intercept_order = 0
    #
  end # initialize

  #----------------------------------------------------------------------------|
  #  New method: intercept_magic                                               |
  #----------------------------------------------------------------------------|
  def intercept_magic(notetag)
    if @states
      intercept_magic = notetag == :tier ? 0 : notetag == :key ? [] : false
      @states.each { |state|
        case notetag
        when :tier
          if $data_states[state].intercept_tier > intercept_magic
            intercept_magic = $data_states[state].intercept_tier
          end
        when :key
          $data_states[state].battler_intercept.each_key { |key|
            intercept_magic.push(key) unless intercept_magic.include?(key)
          }
        when :mp
          return true if $data_states[state].intercept_mp
        when :tp
          return true if $data_states[state].intercept_tp
        when :hit_mp
          return true if $data_states[state].hit_intercept_mp
        when :hit_tp
          return true if $data_states[state].hit_intercept_tp
        when :chance
          return true if rand < $data_states[state].intercept_chance
        end
      }
    end
    intercept_magic
  end # intercept_magic

  #----------------------------------------------------------------------------|
  #  New method: remove_intercept_states                                       |
  #----------------------------------------------------------------------------|
  def remove_intercept_states
    @states.delete_if { |state| $data_states[state].intercept_tier > 0 }
    @intercept_times = 0
    $game_temp.skill_interceptor.delete(self) if @intercept_order > 0
    @intercept_order = 0
  end # remove_intercept_states

  #----------------------------------------------------------------------------|
  #  (v1.02a+)New method: intercept_mp_tp                                      |
  #----------------------------------------------------------------------------|
  def intercept_mp_tp(notetag, item, user = nil)
    if notetag == :mp
      return item.mp_cost unless DoubleX_RMVXA::Intercept_Magic::Intercept_MCR
      return (item.mp_cost * user.mcr).to_i
    elsif notetag == :tp
      return item.tp_cost
    end
    mmp > tp ? mmp + 1 : tp + 1
  end # intercept_mp_tp

end # Game_BattlerBase

class Game_Battler < Game_BattlerBase

  #----------------------------------------------------------------------------|
  #  Alias method: add_state                                                   |
  #----------------------------------------------------------------------------| 
  alias add_state_intercept_magic add_state
  def add_state(state_id)
    add_state_intercept_magic(state_id)
    # Added to set the intercept order
    add_intercept_states(state_id) if $data_states[state_id].intercept_tier > 0
    #
  end # add_state

  #----------------------------------------------------------------------------|
  #  (v1.02a+)New method: add_intercept_states                                 |
  #----------------------------------------------------------------------------|
  def add_intercept_states(state_id)
    if (interceptor = $game_temp.skill_interceptor).include?(self)
      interceptor.delete(self)
    end
    interceptor << self
    @intercept_order = $game_temp.intercept_order(self)
  end # add_intercept_states

end # Game_Battler

class Game_Unit

  #----------------------------------------------------------------------------|
  #  New method: intercept_magic                                               |
  #----------------------------------------------------------------------------| 
  def intercept_magic(user, item, key)
    return nil unless is_a?(Game_Party) || is_a?(Game_Troop)
    im = DoubleX_RMVXA::Intercept_Magic
    intercept_member = nil
    members.each { |member|
      next if member.intercept_magic(:tier) < item.intercept_tier
      next unless member.intercept_magic(:key).include?(key)
      next if im::Intercept_MP_Limit && item.intercept_mp && 
      member.intercept_magic(:mp) && (!item.hit_intercept_mp || 
      !member.intercept_magic(:hit_mp)) && 
      member.intercept_mp_tp(:mp, item, user) > member.mmp - member.mp
      next if im::Intercept_TP_Limit && item.intercept_tp && 
      member.intercept_magic(:tp) && (!item.hit_intercept_tp || 
      !member.intercept_magic(:hit_tp)) && 
      member.intercept_mp_tp(:tp, item) > member.max_tp - member.tp
      next if im::Intercept_Learnt_Skill && member.actor? && 
      !member.skill_learn?(item)
      next if im::Intercept_Usable_Skill && !member.usable?(item)
      next unless member.intercept_magic(:chance)
      next if intercept_member && 
      intercept_member.intercept_order >= member.intercept_order
      intercept_member = member
    }
    intercept_member
  end # intercept_magic

end # Game_Unit

class Window_BattleLog < Window_Selectable

  #----------------------------------------------------------------------------|
  #  New method: display_intercept_item                                        |
  #----------------------------------------------------------------------------| 
  def display_intercept_item(target)
    if (im = DoubleX_RMVXA::Intercept_Magic)::Intercept_SE
      im::Intercept_SE.play
    end
    add_text(sprintf(Vocab::InterceptMagic, target.name))
  end # display_intercept_item

  #----------------------------------------------------------------------------|
  #  New method: display_learn_intercept_item                                  |
  #----------------------------------------------------------------------------| 
  def display_learn_intercept_item(target)
    add_text(sprintf(Vocab::LearnInterceptMagic, target.name))
  end # display_learn_intercept_item

  #----------------------------------------------------------------------------|
  #  (v1.02a+)New method: display_fail_intercept_item                          |
  #----------------------------------------------------------------------------| 
  def display_fail_intercept_item(target)
    add_text(sprintf(Vocab::FailInterceptMagic, target.name))
  end # display_fail_intercept_item

end # Window_BattleLog

class Scene_Battle < Scene_Base

  #----------------------------------------------------------------------------|
  #  Alias method: use_item                                                    |
  #----------------------------------------------------------------------------| 
  alias use_item_intercept_magic use_item
  def use_item
    # Rewritten to intercept magic when conditions are met
    item = @subject.current_action.item
    unless item.is_a?(RPG::Skill) && item.intercept_tier > 0
      return use_item_intercept_magic
    end
    return use_item_intercept_magic unless rand < item.intercept_chance
    interceptor = nil
    item.battler_intercept.each_key { |key|
      interceptor ||= 
      @subject.friends_unit.intercept_magic(@subject, item, key) if key == :ally
      next if if key != :enemy
      interceptor ||= 
      @subject.opponents_unit.intercept_magic(@subject, item, key)
    }
    interceptor ? intercept_magic(interceptor, item) : use_item_intercept_magic
    #
  end # use_item

  #----------------------------------------------------------------------------|
  #  New method: intercept_magic                                               |
  #----------------------------------------------------------------------------| 
  def intercept_magic(target, item)
    @log_window.display_use_item(@subject, item)
    @subject.use_item(item)
    refresh_status
    target.intercept_times ||= 0
    if item.hit_intercept_mp && target.intercept_magic(:hit_mp) && 
    target.intercept_mp_tp(:mp, item, @subject) > target.mmp - target.mp || 
    item.hit_intercept_tp && target.intercept_magic(:hit_tp) && 
    target.intercept_mp_tp(:tp, item) > target.max_tp - target.tp
      fail_intercept(target, item)
    else
      success_intercept(target, item)
    end
    if (im = DoubleX_RMVXA::Intercept_Magic)::Intercept_Times_Limit > 0 && 
    target.intercept_times >= im::Intercept_Times_Limit
      target.remove_intercept_states
    end
    refresh_status
  end # intercept_magic

  #----------------------------------------------------------------------------|
  #  (v1.02a+)New method: fail_intercept                                       |
  #----------------------------------------------------------------------------| 
  def fail_intercept(target, item)
    @log_window.display_fail_intercept_item(target)
    if DoubleX_RMVXA::Intercept_Magic::Count_Fail_Intercept
      target.intercept_times += 1
    end
    targets = @subject.current_action.fail_intercept(target).compact
    targets.each {|target| item.repeats.times { invoke_item(target, item) } }
  end # fail_intercept

  #----------------------------------------------------------------------------|
  #  (v1.02a+)New method: success_intercept                                    |
  #----------------------------------------------------------------------------| 
  def success_intercept(target, item)
    im = DoubleX_RMVXA::Intercept_Magic
    @log_window.display_intercept_item(target)
    if im::Intercept_Animation_Id > 0 && im::Intercept_Animation_Id < 1000
      show_animation([target], im::Intercept_Animation_Id)
    end
    target.intercept_times += 1
    if item.intercept_mp && target.intercept_magic(:mp)
      target.mp += target.intercept_mp_tp(:mp, item, @subject)
      target.mp = target.mmp if target.mp > target.mmp
    if item.intercept_tp && target.intercept_magic(:tp)
      target.tp += target.intercept_mp_tp(:tp, item)
      target.tp = target.max_tp if target.tp > target.max_tp
    end
    return unless im::Intercept_Learn_Skill
    return unless target.actor? && target.skill_learn?(item)
    target.learn_skill(item.id)
    @log_window.display_learn_intercept_item(target)
  end # success_intercept

end # Scene_Battle

#==============================================================================|