#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Unlimited Levels by Blizzard
# Version: 1.0
# Type: Actor Attribute Modifier
# Date: 10.2.2010
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#   
#  This work is protected by the following license:
# #----------------------------------------------------------------------------
# #  
# #  Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
# #  ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
# #  
# #  You are free:
# #  
# #  to Share - to copy, distribute and transmit the work
# #  to Remix - to adapt the work
# #  
# #  Under the following conditions:
# #  
# #  Attribution. You must attribute the work in the manner specified by the
# #  author or licensor (but not in any way that suggests that they endorse you
# #  or your use of the work).
# #  
# #  Noncommercial. You may not use this work for commercial purposes.
# #  
# #  Share alike. If you alter, transform, or build upon this work, you may
# #  distribute the resulting work only under the same or similar license to
# #  this one.
# #  
# #  - For any reuse or distribution, you must make clear to others the license
# #    terms of this work. The best way to do this is with a link to this web
# #    page.
# #  
# #  - Any of the above conditions can be waived if you get permission from the
# #    copyright holder.
# #  
# #  - Nothing in this license impairs or restricts the author's moral rights.
# #  
# #----------------------------------------------------------------------------
# 
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# 
# Compatibility:
# 
#   99% compatible with SDK v1.x. 95% compatible with SDK v2.x. Can cause
#   incompatibility issues with custom leveling systems. WILL corrupt your old
#   savegames.
# 
# 
# Features:
# 
#   - allows actors to have levels higher than 99
#   - automatic calculation of generated stats with minimum error rate
#   - easy to use
# 
# 
# Explanation:
# 
#   This script will allow actors to have levels higher than 99. It
#   automatically calculates the required EXP and the stats using RMXP's
#   default method of calculation.
# 
# 
# Notes:
# 
#   - It is recommended that you also use a script that allows unlimited
#     Max HP, Max SP, Str, Dex, Agi, Int and EXP in combination with this
#     script.
#   - In case a speed setting other than -10, 0 and 10 is being used, the
#     attributes generated by this script can be higher by 1 in some cases for
#     some levels due to a computational error in the interpolation function.
# 
# 
# If you find any bugs, please report them here:
# http://www.chaosproject.co.nr
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

#==============================================================================
# module BlizzCFG
#==============================================================================

module BlizzCFG

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Level Database
# 
#   Use following template to give your actors a custom maximum level:
# 
#     when ID then LEVEL
# 
#   ID    - ID of the actor in the database
#   LEVEL - initial level / final level of that actor
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  
  def self.initial_level(id)
    return case id
    ### START Initial Level Database
    when 1 then 50
    when 2 then 105
    ### END Initial Level Database
    else
      nil
    end
  end  
  
  def self.final_level(id)
    return case id
    ### START Final Level Database
    when 1 then 139
    when 2 then 120
    ### END Final Level Database
    else
      nil
    end
  end  
  
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Level Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Attribute Database
# 
#   Use following template to give your actors a custom attribute
#   calculation.
# 
#     when ID then [START, END, SPEED]
# 
#   ID    - ID of the actor in the database
#   START - attribute value at starting level
#   END   - attribute value at final level
#   SPEED - inflation speed setting (from -10 to 10)
#   
#   The SPEED setting is working the same as RMXP's speed setting for stat
#   generation. -10 is the slowest curve while 10 is the fastest curve. 0 is
#   the normal speed and will generate a linear curve.
#   If you have an actor with the same initial and final level, the START
#   value will be used.
#   
#   Any actor not defined here will use the default parameters that can be set
#   up with RMXP's database. Keep in mind that actors that can have a level
#   over 99 MUST HAVE their parameter behavior defined here or the game will
#   crash!
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  
  def self.maxhp_parameters(id)
    return case id
    ### START Max HP
    when 1 then [3000, 9999, 2]
    when 2 then [6000, 9999, -1]
    ### END Max HP
    else
      nil
    end
  end  
  
  def self.maxsp_parameters(id)
    return case id
    ### START Max SP
    when 1 then [3000, 9999, -4]
    when 2 then [6000, 9999, 3]
    ### END Max SP
    else
      nil
    end
  end  
  
  def self.str_parameters(id)
    return case id
    ### START Str
    when 1 then [300, 999, 10]
    when 2 then [600, 999, 2]
    ### END Str
    else
      nil
    end
  end  
  
  def self.dex_parameters(id)
    return case id
    ### START Dex
    when 1 then [300, 999, 3]
    when 2 then [600, 999, 6]
    ### END Dex
    else
      nil
    end
  end  
  
  def self.agi_parameters(id)
    return case id
    ### START Agi
    when 1 then [300, 999, -1]
    when 2 then [600, 999, 3]
    ### END Agi
    else
      nil
    end
  end  
  
  def self.int_parameters(id)
    return case id
    ### START Int
    when 1 then [300, 999, -10]
    when 2 then [600, 999, -6]
    ### END Int
    else
      nil
    end
  end  
  
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Attribute Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  
  $unlimited_levels = 1.0
  
end

#==============================================================================
# Wrapper_Base
#==============================================================================

class Wrapper_Base
  
  def initialize(initial_level, final_level)
    @initial_level, @final_level = initial_level, final_level
  end
  
end

#==============================================================================
# Wrapper_ExpList
#==============================================================================

class Wrapper_ExpList < Wrapper_Base
  
  def initialize(initial_level, final_level, inflation, basis)
    super(initial_level, final_level)
    @data = [0, 0]
    pow = 2.4 + inflation / 100.0
    (2..(@final_level + 1)).each {|i|
        @data[i] = @data[i - 1] + (basis * ((i + 3) ** pow) / (5 ** pow)).to_i}
  end
  
  def [](i)
    return ((i >= @initial_level && i <= @final_level) ? @data[i] : 0)
  end
  
end

#==============================================================================
# Wrapper_Parameters
#==============================================================================

class Wrapper_Parameters < Wrapper_Base
  
  def initialize(initial_level, final_level, id, parameters)
    super(initial_level, final_level)
    @id, @parameters = id, parameters
  end
  
  def calculate_parameter(min, max, speed, level)
    p_range, l_range = max - min, (@final_level - @initial_level).to_f
    linear = (min + p_range * ((level - @initial_level) / l_range)).ceil
    return linear if speed == 0
    if speed < 0
      curve = (min + p_range * (((level - @initial_level) / l_range) ** 2)).ceil
    else
      curve = (max - p_range * (((@final_level - level) / l_range) ** 2)).ceil
    end
    return ((curve * speed.abs + linear * (10 - speed.abs)) / 10)
  end
  
  def [](type, level)
    values = case type
    when 0 then BlizzCFG.maxhp_parameters(@id)
    when 1 then BlizzCFG.maxsp_parameters(@id)
    when 2 then BlizzCFG.str_parameters(@id)
    when 3 then BlizzCFG.dex_parameters(@id)
    when 4 then BlizzCFG.agi_parameters(@id)
    when 5 then BlizzCFG.int_parameters(@id)
    else
      nil
    end
    return @parameters[type, level] if values == nil
    return values[0] if @initial_level == @final_level
    return calculate_parameter(values[0], values[1], values[2], level)
  end
  
end

#==============================================================================
# RPG::Actor
#==============================================================================

class RPG::Actor
  
  alias initial_level_unlimited_levels_later initial_level
  def initial_level
    level = BlizzCFG.initial_level(@id)
    return (level != nil ? level : initial_level_unlimited_levels_later)
  end
  
  alias final_level_unlimited_levels_later final_level
  def final_level
    level = BlizzCFG.final_level(@id)
    return (level != nil ? level : final_level_unlimited_levels_later)
  end
  
  def parameters
    return Wrapper_Parameters.new(initial_level, final_level, @id, @parameters)
  end
  
end

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

class Game_Actor
  
  def make_exp_list
    actor = $data_actors[@actor_id]
    @exp_list = Wrapper_ExpList.new(actor.initial_level, actor.final_level,
        actor.exp_inflation, actor.exp_basis)
  end
  
end
