#==============================================================================
# Rinobi: State Stages
# -----------------------------------------------------------------------------
# A unique approach to progressive state effects.
#==============================================================================
# Version History:
# -----------------------------------------------------------------------------
# 1.0 [04/29/2016] Completed
# 2.0 [05/11/2016] Bug fixes, Removal methods added, User Friendly Update
#==============================================================================
# * Instructions
# -----------------------------------------------------------------------------
# Create states with incremental effects within the database.
# Add state IDs within the Settings Module to reflect your states setup.
# Your ID list should be ordered from minor to best, or bad to worst states.
# 
# There are two ways to apply incremental states. You may use the script calls
# listed below, or simply apply states as you normally would through the
# database. Applying a state on a target which already has that state, or any
# state a part of the increment group, will instead apply a lesser or greater
# state depending upon the situation and your settings within the module below.
#==============================================================================
# * Script Calls
# -----------------------------------------------------------------------------
# For use within damage formulas. These script calls are completely optional.
# target    - a = user | b = target
# state     - Name of state. May be a number, string, or symbol.
# type      - :pos = positive | :neg = Negative
# chance    - Chance that state is applied. (1 - 100)
# increment - Number of state stages to progress. Limited by settings below.
# ----------------------
# ** Applying States
# ----------------------
# target.stage(state, type, chance, increment)
# 
# Example: b.stage(:atk, :pos, 65, 2) 
# @ 65% chance to increment attack state by 2 stages.
# 
# Example: b.stage(:def, :neg)
# @ Default chance to increment defense state by the default advance amount.
# ----------------------
# ** Removing States
# ----------------------
# target.state_removal(state, type)
# target.type_removal(type)
# target.pos_removal
# target.neg_removal
# target.purge_states
# 
# Example: a.state_removal(:atk, :neg)
# @ Removes all negative attack state effects from the user.
# 
# Example: b.type_removal(:pos)
# @ Removes all positive stage states from the target.
# 
# Example: b.neg_removal
# @ Removes all negative stage states from the target.
#
# Example: a.purge_states
# @ Removes all states from the user.
#==============================================================================
# * Compatibility
# -----------------------------------------------------------------------------
# New Methods:
# - stage	-> Game_Battler
# Alias Methods:
# - add_state	-> Game_Battler
#===============================================================================
module RINOBI module StateStages # No Touchie!
#===============================================================================
# ** Settings Module
# ------------------------------------------------------------------------------
# This script is not plug & play. The settings below are absolutely necessary.
# 
# name		- Can be any integer, string, or symbol.
# :pos IDs	- The positive effect IDs of the states in your database.
# :neg IDs	- The negative effect IDs of the states in your database.
# 
# You may exclude :pos or :neg from the hash if you so choose.
# 
# name => {:pos => [positive effect IDs], :neg => [negative effect IDs]}
#===============================================================================
  Default_Chance  = 100 # Default apply chance. 1 - 100
  Default_Advance = 1   # Default increment amount.
  Default_Chance  = 100 # Default apply chance. 1 - 100
  Default_Advance = 1   # Default increment amount.
  States = { # NOPE
    :nil => {:pos => [], :neg => []}, # Copy/Paste
    :mhp => {:pos => [13,14,15,16,17,18], :neg => [19,20,21,22,23,24]},
    :mmp => {:pos => [25,26,27,28,29,30], :neg => [31,32,33,34,35,36]},
    :atk => {:pos => [37,38,39,40,41,42], :neg => [43,44,45,46,47,48]},
    :def => {:pos => [49,50,51,52,53,54], :neg => [55,56,57,58,59,60]},
    :mat => {:pos => [61,62,63,64,65,66], :neg => [67,68,69,70,71,72]},
    :mdf => {:pos => [73,74,75,76,77,78], :neg => [79,80,81,82,83,84]},
    :agi => {:pos => [85,86,87,88,89,90], :neg => [91,92,93,94,95,96]},
    :psn => {:neg => [97,98,99,100,101,102]},
    :res => {:pos => [103,104,105,106,107,108]},
  } # DO NOT MODIFY
#===============================================================================
# ** End of Settings
#-------------------------------------------------------------------------------
# Editing beyond this area may result in unfathomable terror.
#===============================================================================
end end # No Touchie!
$imported = {} if $imported.nil?
$imported[:RIN_StateStages] = true
#==============================================================================
# ** Class: Game_Battler
#==============================================================================
class Game_Battler < Game_BattlerBase
  #--------------------------------------------------------------------------
  # * New Method: negative state removal
  #--------------------------------------------------------------------------
  def purge_states
    state_hash = RINOBI::StateStages::States
    state_hash.each do |key, hash|
      hash.each do |k, h| 
        h.each {|id| remove_state(id) if states.any?{|state| state.id == id}}
      end
    end
  end # neg_remove_state
  #--------------------------------------------------------------------------
  # * New Method: negative state removal
  #--------------------------------------------------------------------------
  def neg_removal
    state_hash = RINOBI::StateStages::States
    state_hash.each do |key, hash|
      removal = hash.select {|key| key == :neg}
      removal.each do |key, hash|
        hash.each {|id| remove_state(id) if states.any?{|state| state.id == id}}
      end
    end
  end # neg_remove_state
  #--------------------------------------------------------------------------
  # * New Method: positive state removal
  #--------------------------------------------------------------------------
  def pos_removal
    state_hash = RINOBI::StateStages::States
    state_hash.each do |key, hash|
      removal = hash.select {|key| key == :pos}
      removal.each do |key, hash|
        hash.each {|id| remove_state(id) if states.any?{|state| state.id == id}}
      end
    end
  end # neg_remove_state
  #--------------------------------------------------------------------------
  # * New Method: optional type removal
  #--------------------------------------------------------------------------
  def type_removal(type_key)
    state_hash = RINOBI::StateStages::States
    state_hash.each do |key, hash|
      removal = hash.select {|key| key == type_key}
      removal.each do |key, hash|
        hash.each {|id| remove_state(id) if states.any?{|state| state.id == id}}
      end
    end
  end # neg_remove_state
  #--------------------------------------------------------------------------
  # * New Method: optional state removal
  #--------------------------------------------------------------------------
  def state_removal(type, stage_key)
    state_hash = RINOBI::StateStages::States
    removal = state_hash[type].select {|key| key == stage_key}
    removal.each do |key, hash|
      hash.each {|id| remove_state(id) if states.any?{|state| state.id == id}}
    end
  end # neg_remove_state
  #--------------------------------------------------------------------------
  # * New Method: stageing fuctionality
  #--------------------------------------------------------------------------
  def stage(state, type, 
    chan = RINOBI::StateStages::Default_Chance, 
    add = RINOBI::StateStages::Default_Advance)
    # ----------------------------------------------------------------------
    return unless rand < (chan / 100.0)
    state_hash = RINOBI::StateStages::States
    return unless state_hash.has_key?(state)
    state_array = state_hash[state]
    return unless state_array.has_key?(type)
    # ----------------------------------------------------------------------
    type2 = nil
    if state_hash[state].keys.length > 1
      type2 = state_hash[state].keys[1] if type == state_hash[state].keys[0]
      type2 = state_hash[state].keys[0] if type == state_hash[state].keys[1]
    end
    # ----------------------------------------------------------------------
    if type2 && state_array[type2].any? {|s| state?(s)}
      current = states.select {|c| state_array[type2].include?(c.id)}
      index = Hash[state_array[type2].map.with_index.to_a]
      index = index[current[0].id]
      if index - add == -1
        remove_state(current[0].id)
      elsif index - add < -1
        remove_state(current[0].id)
        add -= index + 1
        if add > state_array[type].length
          add = state_array[type].length
        end
        add_state(state_array[type][add - 1])
      else
        remove_state(current[0].id)
        add_state(state_array[type2][index - add])
      end
    # ----------------------------------------------------------------------
    elsif state_array[type].any? {|s| state?(s)}
      return if state?(state_array[type][-1])
      current = states.select {|c| state_array[type].include?(c.id)}
      index = Hash[state_array[type].map.with_index.to_a]
      index = index[current[0].id]
      current.each {|c| remove_state(c.id)}
      if add + index >= state_array[type].length
        add = state_array[type].length
        add_state(state_array[type][add - 1])
      else
        add_state(state_array[type][index + add])
      end
    # ----------------------------------------------------------------------
    else
      add > state_array[type].length ? add = state_array[type].length : add
      add_state(state_array[type][add - 1])
    end
  end # stage()
  #--------------------------------------------------------------------------
  # * Add State
  #--------------------------------------------------------------------------
  alias :stage_add_state :add_state
  def add_state(state_id)
    #  index = Hash[state_array[type2].map.with_index.to_a]
    #  index = index[current[0].id]
    state_hash = RINOBI::StateStages::States
    state_hash.each do |key, hash|
      hash.each do |k, v|
        # print v if v.include?(state_id)
        next unless v.include?(state_id)
        index = v.index(state_id)
        add = index + 1
        state_array = state_hash[key]
        # ----------------------------------------------------------------------
        type1 = k ; type2 = nil
        if state_hash[key].keys.length > 1
          type2 = state_hash[key].keys[1] if type1 == state_hash[key].keys[0]
          type2 = state_hash[key].keys[0] if type1 == state_hash[key].keys[1]
        end
        # ----------------------------------------------------------------------
        if type2 && state_array[type2].any? {|s| state?(s)}
          current = states.select {|c| state_array[type2].include?(c.id)}
          index = Hash[state_array[type2].map.with_index.to_a]
          index = index[current[0].id]
          if index - add == -1
            return remove_state(current[0].id)
          elsif index - add < -1
            remove_state(current[0].id)
            add -= index + 1
            if add > state_array[type1].length
              add = state_array[type1].length
            end
            state_id = state_array[type1][add - 1]
          else
            remove_state(current[0].id)
            state_id = state_array[type2][index - add]
          end
        # ----------------------------------------------------------------------
        elsif state_array[type1].any? {|s| state?(s)}
          return if state?(state_array[type1][-1])
          current = states.select {|c| state_array[type1].include?(c.id)}
          index = Hash[state_array[type1].map.with_index.to_a]
          index = index[current[0].id]
          current.each {|c| remove_state(c.id)}
          remove_state(state_id)
          if add + index >= state_array[type1].length
            add = state_array[type1].length
            state_id = state_array[type1][add - 1]
          else
            state_id = state_array[type1][index + add]
          end
        # ----------------------------------------------------------------------
        end
      end
    end
    stage_add_state(state_id)
  end
end # class Game_Battler < Game_BattlerBase