#==============================================================================|
#  ** Script Info                                                              |
#------------------------------------------------------------------------------|
#  * Script Name                                                               |
#    DoubleX RMVXA Linked Battlers                                             |
#------------------------------------------------------------------------------|
#  * Functions                                                                 |
#    Lets users set some states to make their owners share some stats together |
#------------------------------------------------------------------------------|
#  * Terms Of Use                                                              |
#    You shall keep this script's Script Info part's contents intact           |
#    You shalln't claim that this script is written by anyone other than       |
#    DoubleX or his aliases                                                    |
#    None of the above applies to DoubleX or his aliases                       |
#------------------------------------------------------------------------------|
#  * Prerequisites                                                             |
#    Abilities:                                                                |
#    1. Some RGSS3 scripting proficiency to fully utilize this script          |
#------------------------------------------------------------------------------|
#  * Instructions                                                              |
#    1. Open the script editor and put this script into an open slot between   |
#       Materials and Main, save to take effect.                               |
#------------------------------------------------------------------------------|
#  * Links                                                                     |
#    Script Usage 101:                                                         |
#    1. forums.rpgmakerweb.com/index.php?/topic/32752-rmvxa-script-usage-101/  |
#    2. rpgmakervxace.net/topic/27475-rmvxa-script-usage-101/                  |
#    This script:                                                              |
#    1. [url]http://pastebin.com/bfCuAkKT[/url]                                           |
#    Mentioned Patreon Supporters:                                             |
#    [url]https://www.patreon.com/posts/71738797[/url]                                    |
#------------------------------------------------------------------------------|
#  * Authors                                                                   |
#    DoubleX                                                                   |
#------------------------------------------------------------------------------|
#  * Changelog                                                                 |
#    v1.00b(GMT 0400 8-11-2015):                                               |
#    1. Notetag values are now symbols of methods in the configuration regions |
#    2. This script doesn't need DoubleX RMVXA Linked Battlers Compatibility to|
#       be compatible with all its addressed scripts                           |
#    3. Further improved this script's compatibility, efficiency and simplicity|
#    v1.00a(GMT 1500 7-8-2015):                                                |
#    1. 1st version of this script finished                                    |
#==============================================================================|

#==============================================================================|
#  ** Notetag Info                                                             |
#------------------------------------------------------------------------------|
#  * State Notetags:                                                           |
#    1. <linked battlers: lbcx, lbsx, lbwx>                                    |
#       - Sets the owners of this state meeting lbcx to share stats included in|
#         lbsx with weight lbwx applied to each of them when any included stat |
#         of any included battler changes                                      |
#       - Only the 1st applicable notetag of the state with the highest        |
#         priority will be applied to the stat change of the linked battler    |
#       - If a linked battler can't take all of that battler's share due to    |
#         hitting the minimum or maximum stat value, thost not being taken by  |
#         that battler will be shared by the rest of the linked battlers also  |
#       - The battler having a stat to be changed is the last linked battler   |
#         taking that battler's share                                          |
#       - lbcx can be set in Linked Battler Condition Notetag Values           |
#       - lbsx can be set in Linked Battler Stat Notetag Values                |
#       - lbwx can be set in Linked Battler Weight Notetag Values              |
#==============================================================================|

($doublex_rmvxa ||= {})[:Linked_Battlers] = "v1.00b"

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

module DoubleX_RMVXA

  module Linked_Battlers

    #--------------------------------------------------------------------------|
    #  Linked Battler Condition Notetag Values                                 |
    #  - Setups lbcx used by <linked battlers: lbcx, lbsx, lbwx>               |
    #--------------------------------------------------------------------------|
    # lbcx are read at:
    # 1. RPG::State
    #    - @linked_battlers << [$1.downcase.to_sym, $2.downcase.to_sym, 
    #      $3.downcase.to_sym] in load_linked_battlers_notes
    # lbcx are used at:
    # 1. Game_BattlerBase
    #    - mem.state?(state_id) && lb.send(cond, mem, self) in
    #      get_linked_battlers
    # lbcx are strings of names of methods under DoubleX_RMVXA::Linked_Battlers
    # lbcx names can only use alphanumeric characters and can't use uppercase
    # letters
    # The battler having a stat to be changed can be referenced by target
    # Each of the rest of the linked battlers can be referenced by battler
    # The below lbcx are examples added to help you set your lbcx
    # You can freely use, rewrite and/or delete these examples

    # Sets the linked battler condition to include all linked battlers
    def self.lbc1(battler, target)
      true
    end

    # Sets the linked battler condition to include all and no linked battlers if
    # switch with id x is on and off respectively
    def self.lbc2(battler, target)
      $game_switches[x]
    end

    # Sets the linked battler condition to include all linked battlers that are
    # opponents of the battler having a stat to be changed
    def self.lbc3(battler, target)
      target.opposite?(battler)
    end

    # Adds new lbcx here
    

    #--------------------------------------------------------------------------|
    #  Linked Battler Stat Notetag Values                                      |
    #  - Setups lbsx used by <linked battlers: lbcx, lbsx, lbwx>               |
    #--------------------------------------------------------------------------|
    # lbsx are read at:
    # 1. RPG::State
    #    - @linked_battlers << [$1.downcase.to_sym, $2.downcase.to_sym, 
    #      $3.downcase.to_sym] in load_linked_battlers_notes
    # lbsx are used at:
    # 1. Game_BattlerBase
    #    - return [l_b, state_id] if lb.send(l_b[1], self).include?(stat) in
    #      linked_battler_state_id
    # lbsx are strings of names of methods under DoubleX_RMVXA::Linked_Battlers
    # lbsx names can only use alphanumeric characters and can't use uppercase
    # letters
    # The battler having a stat to be changed can be referenced by battler
    # It must return an array, which should include strings of a getter method
    # of each stat to be included
    # The below lbsx are examples added to help you set your lbsx
    # You can freely use, rewrite and/or delete these examples

    # Sets the linked battler stat to include hp, mp and tp
    def self.lbs1(battler)
      ["hp", "mp", "tp"]
    end

    # Sets the linked battler stat to always include hp and mp, and include tp
    # only if it's displayed in battle
    def self.lbs2(battler)
      ["hp", "mp", $data_system.opt_display_tp ? "tp" : nil]
    end

    # Sets the linked battler stat to include nothing
    def self.lbs3(battler)
      []
    end

    # Adds new lbsx here
    

    #--------------------------------------------------------------------------|
    #  Linked Battler Weight Notetag Values                                    |
    #  - Setups lbwx used by <linked battlers: lbcx, lbsx, lbwx>               |
    #--------------------------------------------------------------------------|
    # lbwx are read at:
    # 1. RPG::State
    #    - @linked_battlers << [$1.downcase.to_sym, $2.downcase.to_sym, 
    #      $3.downcase.to_sym] in load_linked_battlers_notes
    # lbwx are used in methods included in LINKED_STAT
    # lbwx are strings of names of methods under DoubleX_RMVXA::Linked_Battlers
    # lbwx names can only use alphanumeric characters and can't use uppercase
    # letters
    # It must return a real number
    # The battler having a stat to be changed can be referenced by target
    # Each of the rest of the linked battlers can be referenced by battler
    # The below lbwx are examples added to help you set your lbwx
    # You can freely use, rewrite and/or delete these examples

    # Sets the linked battler weight to be the same for all linked battlers
    def self.lbw1(battler, target)
      1
    end

    # Sets the linked battler weight to be multiplied by x if the linked battler
    # is the one having a stat to be changed
    def self.lbw2(battler, target)
      battler == target ? x : 1
    end

    # Sets the linked battler weight to be 0 for all linked battlers
    def self.lbw3(battler, target)
      0
    end

    # Adds new lbwx here
    

    # Sets the battler methods to be used by linked battlers
    # Its keys must be the battler stat getter method string
    # Its values must be an array containing the battler stat setter method,
    # its argument list, the one being modified, and the minimum and maximum
    # value of that battler stat of each linked battler
    # The methods returning those minimum and maximum values must be referenced
    # by battler
    # Methods with name method_name will be aliased to
    # linked_battlers_method_name
    LINKED_STATS = {

      # General form:
      # [:def_class, :super_class] => {
      #   "getter" => ["setter", "args", "mod arg", "stat_min", "stat_max"]
      # }

      [:Game_BattlerBase] => {
        # General form: 
        # "getter" => ["setter", "args", "mod arg", "stat_min", "stat_max"]
        "hp" => ["hp=", "hp", "hp", "0", "battler.mhp"],
        "mp" => ["mp=", "mp", "mp", "0", "battler.mmp"],
        "tp" => ["tp=", "tp", "tp", "0", "battler.max_tp"]
        # Adds new methods here
        
      }

      # Adds new classes here
      

    }

  end # Linked_Battlers

end # DoubleX_RMVXA

#==============================================================================|
#  ** Script Implementations                                                   |
#     You need not edit this part as it's about how this script works          |
#------------------------------------------------------------------------------|
#  * Script Support Info:                                                      |
#    1. Prerequisites                                                          |
#       - Decent RGSS3 scripting proficiency to fully comprehend this script   |
#    2. Method documentation                                                   |
#       - The 1st part describes why this method's rewritten/aliased for       |
#         rewritten/aliased methods or what the method does for new methods    |
#       - The 2nd part describes what the arguments of the method are          |
#       - The 3rd part informs which version rewritten, aliased or created this|
#         method                                                               |
#       - The 4th part informs whether the method's rewritten or new           |
#       - The 5th part informs whether the method's a real or potential hotspot|
#       - The 6th part describes how this method works for new methods only,   |
#         and describes the parts added, removed or rewritten for rewritten or |
#         aliased methods only                                                 |
#       Example:                                                               |
# #--------------------------------------------------------------------------| |
# #  Why rewrite/alias/What this method does                                 | |
# #--------------------------------------------------------------------------| |
# # *argv: What these variables are                                            |
# # &argb: What this block is                                                  |
# def def_name(*argv, &argb) # Version X+; Rewrite/New; Hotspot                |
#   # Added/Removed/Rewritten to do something/How this method works            |
#   def_name_code                                                              |
#   #                                                                          |
# end # def_name                                                               |
#------------------------------------------------------------------------------|

class << DataManager # Edit

  alias load_database_linked_battlers load_database
  def load_database(*argv, &argb)
    load_database_linked_battlers(*argv, &argb)
    $data_states.each { |obj| obj.load_linked_battlers_notes if obj } # Added
  end # load_database

end # DataManager

class RPG::State < RPG::BaseItem # Edit

  #----------------------------------------------------------------------------|
  #  New public instance variable                                              |
  #----------------------------------------------------------------------------|
  attr_accessor :linked_battlers # An array of all linked battler notetag values

  def load_linked_battlers_notes # New
    @linked_battlers = []
    # Stores all lbcx, lbsx and lbwx triples from matching lines sequentially
    @note.split(/[\r\n]+/).each { |l|
      next unless l =~ /< *linked +battlers *: *(\w+) *, *(\w+) *, *(\w+) *>/i
      @linked_battlers << [$1.downcase.to_sym, $2.downcase.to_sym, 
      $3.downcase.to_sym]
    }
    #
  end # load_linked_battlers_notes

end # RPG::State

#------------------------------------------------------------------------------|
#  *  Adds helper methods used by methods used by linked battlers              |
#------------------------------------------------------------------------------|
class Game_BattlerBase # Edit

  # state_id: The id of the state to be included by all linked battlers
  # cond: The conditions for a linked battlers to be included
  def get_linked_battlers(state_id, cond) # New
    lb = DoubleX_RMVXA::Linked_Battlers
    ($game_party.alive_members + $game_troop.alive_members).select! { |mem|
      mem.state?(state_id) && lb.send(cond, mem, self)
    }
  end # get_linked_battlers

  # stat: The stat of a linked battler to be changed
  def linked_battler_state_id(stat) # New
    lb = DoubleX_RMVXA::Linked_Battlers
    @states.each { |state_id|
      $data_states[state_id].linked_battlers.each { |l_b|
        return [l_b, state_id] if lb.send(l_b[1], self).include?(stat)
      }
    }
    nil
  end # linked_battler_state_id

end # Game_BattlerBase

# Aliases methods used by linked battlers
DoubleX_RMVXA::Linked_Battlers::LINKED_STATS.each { |klass, defs|
  klass_def = %Q(
class #{klass[0].id2name}#{klass[1] ? " < #{klass[1].id2name}" : ""}
)
  defs.each { |get, stat|
    klass_def += %Q(
  alias linked_battlers_#{stat[0]} #{stat[0]}
  def #{stat[0]}(#{stat[1]})
    lb_si = linked_battler_state_id("#{get}")
    return self.linked_battlers_#{stat[0]}(#{stat[1]}) unless lb_si
    get_linked_battlers_#{get}(#{stat[1]}, lb_si[0], lb_si[1])
  end

  def get_linked_battlers_#{get}(#{stat[1]}, linked_battler, state_id)
    battlers = get_linked_battlers(state_id, linked_battler[0])
    index = battlers.index(self)
    battlers[index], battlers[-1] = battlers[-1], battlers[index]
    lb = DoubleX_RMVXA::Linked_Battlers
    weights = battlers.collect { |b| lb.send(linked_battler[2], b, self) }
    return if (sum = weights.inject(:+)) == 0
    diff = #{stat[2]} - self.#{get}
    set_linked_battlers_#{get}(#{stat[1]}, battlers, diff, sum, weights)
  end

  def set_linked_battlers_#{get}(#{stat[1]}, battlers, diff, sum, weights)
    battlers.each_with_index { |battler, index|
      change = diff * (weight = weights[index]) / sum
      if (new_stat = battler.#{get} + change) < min = #{stat[3]}
        change = battler.#{get} - min
        #{stat[2]} = min
      elsif new_stat > max = #{stat[4]}
        change = max - battler.#{get}
        #{stat[2]} = max
      else
        #{stat[2]} = new_stat
      end
      battler.linked_battlers_#{stat[0]}(#{stat[1]})
      diff -= change
      sum -= weight
    }
  end
)
  }
  eval(klass_def + %Q(
end
))
}

#------------------------------------------------------------------------------|

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