#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# RO Job/Skill System by Blizzard
# Version: 2.2b
# Type: Ragnarok Online Job/Skill System Clone
# Date: 5.11.2007
# Date 1.0b: 4.1.2008
# Date 1.01b: 4.1.2008
# Date 1.2b: 26.1.2008
# Date 1.3b: 2.6.2008
# Date 1.4b: 8.6.2008
# Date 1.5b: 6.8.2008
# Date 1.6b: 23.11.2009
# Date 2.0b: 17.2.2010
# Date 2.01b: 4.9.2010
# Date 2.1b: 22.1.2011
# Date 2.2b: 22.6.2012
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#   
#  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.
# #  
# #----------------------------------------------------------------------------
# 
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# 
#   Special Thanks for requesting this goes to Nightfox!
# 
# 
# new in 1.0b:
#   - fixed font problem
#   - now beta
# 
# new in 1.01b:
#   - fixed a crash problem where enemies would be tested on skill levels
# 
# new in 1.2b:
#   - actors can now learn Chaos Drive transformation skills through this
#     system (REQUIRES CRLS 5.0 OR HIGHER)
#   - classes/jobs now can have stat modifiers
# 
# new in 1.3b:
#   - skills can now have other skills as requirements
# 
# new in 1.4b:
#   - added option to hide skills that haven't met the prerequisites yet
#   - improved coding and the way data display is being refreshed
# 
# new in 1.5b:
#   - fixed bug with forgetting skills
#   - added option to forget all skills from other classes when changing the
#     class
# 
# new in 1.6b:
#   - now more compatible with Blizz-ABS 2.57
# 
# new in 2.0b:
#   - fixed bug where HP/SP wouldn't apply when the max HP/SP were decreased
#   - fixed bug with skill usage when JOB_ONLY was not active
#   - now more compatible with Blizz-ABS 2.7
#   - improved coding
# 
# new in 2.01b:
#   - fixed bug when activating JOB_ONLY
# 
# new in 2.1b:
#   - fixed a few small problems with Blizz-ABS
# 
# new in 2.2b:
#   - fixed a the bug where during actor parameter testing the class of the
#     dummy actor would change and unequip equipment
#   - fixed crash bug that could occur when trying to change the class again
# 
#   
# Compatibility:
#   
#   95% compatible with SDK v1.x, 60% compatible with SDK v2.x. Can cause
#   incompatibility issues with other exotic Skill Systems, CMS-es and CBS-es.
#   Fully compatible with Blizz-ABS, not compatible with Mr. Mo's ABS. WILL
#   corrupt old savegames.
# 
# 
# Explanantion:
#   
#   This script allows you to use a skill system that is very similar to the
#   skill system of the MMORPG Ragnarok Online. By gaining jobs and job levels
#   the characters get points which they can use to learn and make skills
#   stronger. Stronger skills have a higher numerical effect and lower SP cost.
#   This script also allows the usage of a job change system.
#   
#   
# Features:
#   
#   - job/class level and and change system
#   - skill level system that can be turned off as well
#   - gain Job Points for each Job Level and use them to power up your skills
#     or learn new ones
#   - increased SP cost and decreased skill power for skills that have not
#     been improved to the maximum level
#   - two fully functional scenes for class changing and skill
#     learning/improving
#   - easy setup and use
#   - compatible with Blizz-ABS and RTAB
#   - wide range of possible uses
#   
#   
# Instructions:
#   
# - How the system works:
#   
#   When a skill is learned, its power is less than 100%, its SP cost is higher
#   than 100% and its level is 1. To learn a skill only 1 JP (Job Point) is
#   needed. For every increase of the skill's level another JP is needed. When
#   the skill has reached its maximum level, the power is exactly 100% and the
#   SP cost exactly is 100%. Everything between is linearry distributed.
#   
#   Example:
#     Skill ID:       15
#     Min Lvl:         1
#     Max Lvl:        11
#     Lvl 1 Power:    20%
#     Max Power:     100%
#     Lvl 1 Cost:    150%
#     Min Cost:      100%
#   These would be the statistics of a skill at level 5:
#     Current Lvl:     5
#     Current Power:  52%
#     Current Cost:  130%
#   
# - Configuration
#   
#   INIT_JP      - initial number of Job Points
#   LVL1_POWER   - set this number to the percentage of the skill power a skill
#                  should have when having level 1
#   LVL1_COST    - set this number to the percentage of the CP cost a skill
#                  should have when having level 1
#   LVLUP_RATE   - if you have the feeling that you reach a job level to
#                  quickly increase this number or the other way around
#   EXP_RATIO    - this number determines the JOBEXP / EXP ratio in percents
#                  (i.e. if you set number to 144 and get 2000 EXP, you will
#                  get 2880 JOBEXP)
#   RESET_LVLS   - if you set this value to true, each skill that is forgotten
#                  will be completely deleted, the JP will NOT be returned, you
#                  have to do that manually
#   JOB_ONLY     - if you set this value to true, the skill level system will
#                  be turned off completely
#   USE_LEVEL    - if you set this value to true, the level required for a
#                  class change is not the current class' job level, but the
#                  real level
#   USE_ALL      - if you set this value to true, a character is not allowed to
#                  change his job as long as his JP are not zero, this creates
#                  virtually the impression that each class his its own JP
#   CLASS_SKILLS - if you set this value to true, all skills learned from one
#                  class will be removed, this option does not affect the game
#                  if the JOB_ONLY option is being used
#   HIDE_SKILLS  - if you se this to true, skills won't be displayed in the
#                  window where you can learn skills until all requirements are
#                  met
#   RO_RIGHT     - if you set this value to true, the windows in the scenes
#                  will appear at the right side
#   EVASION      - name displayed for the attribute "Evasion"
#   UP_COLOR     - color of text that displays increasing stats
#   DOWN_COLOR   - color of text that displays decreasing stats
#   CD_SKILLS    - if you are using CRLS and want actors to be able to learn CD
#                  skills through this system, you need to include all
#                  learnable IDs of CD skills so the system knows that those
#                  are not normal skills, but CD skills
#   
#   Press CTRL+F and type "START RO Skill Database" (without the double quotes)
#   and setup your skill database. The skills available for a job/class are the
#   ones you specify in your class database. The level required to be able to
#   learn a skill is now the job level. In other words, you need the given job
#   level to be able to learn that specific skill.
#   
# 
# Additional Informations:
#   
#   If you wish to call the class change scene, use a "Call Script" event
#   command and type following command into the window:
#   
#     $scene = Scene_ClassChange.new
#   
#   If you wish to call the job point distribution scene, use this command:
#   
#     $scene = Scene_SkillChange.new
#   
#   If you want to manually change a skill and/or job level/EXP, simply use:
#   
#     $game_actors[ID].skill_level_change(NUMBER, S_ID)
#     $game_actors[ID].job_level_change(NUMBER, C_ID)
#     $game_actors[ID].add_job_exp(NUMBER, C_ID)
#   
#   ID     - ID of the actor in the database
#   C_ID   - ID of the class in the database
#   S_ID   - ID of the skill in the database
#   NUMBER - numeric value
#   
#   If you leave out C_ID, the current class ID will be used. Keep in mind that
#   you can CHANGE skill and job level, but you can only INCREASE Job EXP.
#   You can also manually change the value of the Job Points.
#   
#     $game_actors[ID].jp = NUMBER
#   
#   Keep in mind that increasing the job level manually will cause that JP are
#   being increased as well while decreasing the job level will NOT cause the
#   JP to decrease.
#   Here are the formulas for new effect and cost calculation for reference.
#   
#     effect = ORIGINAL * (LVL1_POWER + (skill_level - 1) *
#              (100 - LVL1_POWER) / (skill_maxlevel - 1)) / 100
#     cost   = ORIGINAL * (LVL1_COST - (skill_level - 1) *
#              (LVL1_COST - 100) / (skill_maxlevel - 1)) / 100
#   
#   This is the formula for calculation of how much EXP are needed to reach
#   the next job level.
# 
#     EXP_needed_for_lvl(lvl) = LVLUP_RATE * lvl * (lvl - 1)
#   
#   
# Important note:
#   
#   If you use this system to learn CD skills, it is recommended that you leave
#   the skills' maximum level at only 1 as the consumption cost of the stats
#   cannot change in CRLS. CD skills also don't appear in the improvement
#   screen. Don't forget that you need to let the class be able to learn the CD
#   skills just like a normal skill. If you don't have CRLS installed, the
#   skill will be learned as if it was a normal skill.
#   
#   
# If you find any bugs, please report them here:
# http://forum.chaos-project.com
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

# used for compatibility
$ro_jobskill_clone = 2.2

#==============================================================================
# module BlizzCFG
#------------------------------------------------------------------------------
#  This module serves for configuration in my scripts and for consistency.
#==============================================================================

module BlizzCFG
  
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  INIT_JP = 1
  LVL1_POWER = 50
  LVL1_COST = 200
  LVLUP_RATE = 20
  EXP_RATIO = 20
  RESET_LVLS = false
  JOB_ONLY = false
  USE_LEVEL = false
  USE_ALL = false
  CLASS_SKILLS = !false
  HIDE_SKILLS = false
  RO_RIGHT = false
  EVASION = 'EVA'
  UP_COLOR = Color.new(0, 255, 0) # (R, G, B)
  DOWN_COLOR = Color.new(255, 0, 0) # (R, G, B)
  CD_SKILLS = [61]
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

  def self.roskill_maxlevel(id)
    case id
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START RO Skill Database
# 
#   You can define the max level of each skill here. Use following template to
#   set up your configuration:
# 
#     when ID then return NUMBER
# 
#   ID     - the skill ID
#   NUMBER - the maximum level
# 
#   Note that using values lower than 1 WILL CAUSE BUGS! Default value is 1 and
#   skills that are not defined here will have the default value automatically
#   applied.
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    when 57 then return 5
    #when 61 then return 3
    when 62 then return 5
    when 63 then return 10
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END RO Skill Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    end
    return 1
  end
  
  def self.roskill_reqs(id)
    case id
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START RO Skill Requirement Database
# 
#   You have the option to make skills require not only a specific level, but
#   other skills and their levels as well. Such a skill will not appear in the
#   list of skills until all requirements are met.
#   Use following template to set up your configuration:
# 
#     when ID then return [[SKILL_ID1, MIN_LEVEL1], [SKILL_ID2, MIN_LEVEL2], ...]
# 
#   ID        - the skill ID
#   SKILL_ID  - ID of the required skill
#   MIN_LEVEL - minimum required level of the required skill
# 
#   You can add as many requirements as you want, separate them with commas.
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    when 2 then return [[1, 2]]
    when 62 then return [[61, 1], [63, 4]]
    when 3 then return [[1, 3], [2, 2]]
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END RO Skill Requirement Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    end
    return []
  end
  
  def self.rojob_maxlevel(id)
    case id
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START RO Job Database
# 
#   You can define the max level of each job here. Use following template to
#   set up your configuration:
# 
#     when ID then return NUMBER
# 
#   ID     - the class ID
#   NUMBER - the maximum level
# 
#   Note that using values lower than 1 WILL CAUSE BUGS! Default value is 1 and
#   jobs that are not defined here will have the default value automatically
#   applied.
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    when 1 then return 10
    when 2 then return 30
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END RO Job Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    end
    return 1
  end
  
  def self.rojob_next(id)
    case id
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START RO Job-Connection Database
#   
#   Here you can define job change trees. When you have one job active you can
#   change to any other job that is defined here. It is possible to define
#   recursive trees where a class can be changed back as well without problems.
#   Use following template to set up your configuration:
# 
#     when ID then return [[MIN_LEVEL1, NEW_ID1], [MIN_LEVEL2, NEW_ID2], ...]
# 
#   ID        - the current class ID
#   MIN_LEVEL - minimum level required to be allowed to change
#   NEW_ID    - the ID of the new class
# 
#   You can add as many next classes as you want, separate them with commas.
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    when 1 then return [[1, 2], [15, 3]]
    when 2 then return [[10, 1], [15, 3], [1, 4], [1, 5], [1, 6]]
    when 3 then return [[1, 2], [6, 7]]
    when 4 then return [[1, 2]]
    when 5 then return [[1, 2], [8, 6], [10, 8]]
    when 6 then return [[1, 2], [11, 3]]
    when 7 then return [[1, 2], [5, 1], [5, 4]]
    when 8 then return [[1, 2], [5, 7]]
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END RO Job-Connection Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    end
    return [[]]
  end
  
  def self.job_stat_mod(id)
    p_maxhp = p_maxsp = p_str = p_dex = p_agi = p_int = 0
    m_maxhp = m_maxsp = m_str = m_dex = m_agi = m_int = 1.0
    case id
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Job Stat Modifier Database
#   
#   You are able to set up modifiers for actor stats that change depending on
#   the current job. Use following template to set up your configuration:
# 
#     when ID
#       p_maxhp = PLUS
#       p_maxsp = PLUS
#       p_str = PLUS
#       p_dex = PLUS
#       p_agi = PLUS
#       p_int = PLUS
#       m_maxhp = MULTI
#       m_maxsp = MULTI
#       m_str = MULTI
#       m_dex = MULTI
#       m_agi = MULTI
#       m_int = MULTI
# 
#     ID    - the current class ID
#     PLUS  - an integer value (default is 0)
#     MULTI - a decimal value (default is 1.0)
# 
#   The values that have p_ before that name are static modifiers. For example,
#   if you use 100, then the given stat will increase by 100 if the actor has
#   the given class. If you use -200, then it will decrease by 200 from the
#   actor's basis.
#   The values that have m_ before that name are dynamic modifiers. For
#   example, if you use 1.1, then the given stat will increase by 10% if the
#   actor has the given class. If you use 0.8, then it will decrease by 20%
#   from the actor's basis.
#   
# Note:
#   
#   It might be a good idea to create a neutral class if you are using this
#   feature. If you don't set up a class here, then the default values will be
#   applied. Keep in mind that first all static modifiers will be applied and
#   afterwards the dynamic modifiers.
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    when 1
      p_maxhp = 100
      p_maxsp = -20
      p_str = 20
      p_dex = 10
      p_agi = 10
      p_int = -20
      m_maxhp = 1.1
      m_maxsp = 0.9
      m_str = 1.1
      m_dex = 1.1
      m_agi = 1.0
      m_int = 0.8
    when 2
      p_maxhp = -200
      p_maxsp = 50
      p_str = -20
      p_dex = 0
      p_agi = 0
      p_int = 30
      m_maxhp = 0.9
      m_maxsp = 1.1
      m_str = 0.7
      m_dex = 0.9
      m_agi = 1.1
      m_int = 1.2
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END RO Job Stat Modifier Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    end
    return [p_maxhp, m_maxhp, p_maxsp, m_maxsp, p_str, m_str, p_dex, m_dex,
        p_agi, m_agi, p_int, m_int]
  end
  
  # constants
  
  YesNo = ['Yes', 'No']
  AreYouSure = 'Are you sure?'
  Current = 'Current'
  JobPoints = 'Job Points'
  JobLevel = 'Job Level'
  JobEXP = 'Job EXP'
  EXP = 'EXP'
  Next = 'next'
  EmptyEXP = '------'
  None = 'None'
  Lv = 'Lv'
  SkillLevel = 'Skill Level'
  MaximumLevel = 'Maximum Level'
  Cost = 'Cost'
  Power = 'Power'
  ClassCommands = ['Select', 'Next', 'Previous', 'Exit']
  ChangeClass = 'Change Class?'
  SkillCommands = ['Learn new Skill', 'Improve Skill', 'Next', 'Previous', 'Exit']
  LearnSkill = 'Learn Skill?'
  ImproveSkill = 'Improve Skill?'
  
end

#==============================================================================
# Game_Actor
#------------------------------------------------------------------------------
#  This class was enhanced with various additional variables to make this
#  system work properly. Also a number of methods were added to handle the new
#  data.
#==============================================================================

class Game_Actor
  
  # setting all accessible variables
  attr_accessor :jp
  #----------------------------------------------------------------------------
  # override setup
  #  Adds some hashes for additional data.
  #----------------------------------------------------------------------------
  alias setup_skilllevels_later setup
  def setup(id)
    @skill_level, @job_level, @job_exp, @jp = {}, {}, {}, BlizzCFG::INIT_JP
    setup_skilllevels_later(id)
    @skills = [] unless BlizzCFG::JOB_ONLY
  end
  #----------------------------------------------------------------------------
  # job_level
  #  id - class ID
  #  Safe return of any job level, current job level is default.
  #----------------------------------------------------------------------------
  def job_level(id = @class_id)
    return (@job_level[id] == nil ? 1 : @job_level[id])
  end
  #----------------------------------------------------------------------------
  # job_exp
  #  id - class ID
  #  Safe return of any job exp, current job exp are default.
  #----------------------------------------------------------------------------
  def job_exp(id = @class_id)
    return (@job_exp[id] == nil ? 0 : @job_exp[id])
  end
  #----------------------------------------------------------------------------
  # job_level_change
  #  val  - new level value
  #  id   - class ID
  #  flag - determines whether EXP should be updated or not
  #  This method processes change of a job level.
  #----------------------------------------------------------------------------
  def job_level_change(val, id = @class_id, flag = true)
    # get level
    new_level = BlizzCFG.rojob_maxlevel(id)
    # limit level value
    if new_level > val
      new_level = val
    elsif new_level < 1
      new_level = 1
    end
    # get Job Points
    jp = new_level - self.job_level(id)
    # increase Job Points
    @jp += jp if jp > 0
    # set new Job level
    @job_level[id] = new_level
    # set Job EXP if the setting flag is active
    @job_exp[id] = BlizzCFG::LVLUP_RATE * new_level * (new_level - 1) if flag
  end
  #----------------------------------------------------------------------------
  # override exp=
  #  val  - new exp value
  #  This method was modified to add job EXP each time real EXP are added.
  #----------------------------------------------------------------------------
  alias exp_is_rosys_later exp=
  def exp=(val)
    # store old EXP and skills
    old_exp, skills = @exp, @skills.clone
    exp_is_rosys_later(val)
    # no skills can be learned, remove any learned skills
    @skills = skills
    # increase Job EXP
    exp = @exp - old_exp
    add_job_exp(exp * BlizzCFG::EXP_RATIO / 100) if exp > 0
  end
  #----------------------------------------------------------------------------
  # add_job_exp
  #  val - new exp value
  #  id  - class ID
  #  This method executes job exp increasing.
  #----------------------------------------------------------------------------
  def add_job_exp(val, id = @class_id)
    max_level = BlizzCFG.rojob_maxlevel(id)
    # set new Job EXP
    exp1 = self.job_exp(id) + val
    exp2 = BlizzCFG::LVLUP_RATE * max_level * (max_level - 1)
    @job_exp[id] = (exp1 < exp2 ? exp1 : exp)
    # as long as Job level can be increased
    while self.job_level(id) < max_level && self.job_exp(id) >=
        BlizzCFG::LVLUP_RATE * self.job_level(id) * (self.job_level(id) + 1)
      # increase Job level
      job_level_change(self.job_level(id) + 1, id, false)
    end
  end
  #----------------------------------------------------------------------------
  # job_max_level?
  #  Checks if the Job's level is at the maximum.
  #----------------------------------------------------------------------------
  def job_max_level?
    return (self.job_level >= BlizzCFG.rojob_maxlevel(@class_id))
  end
  #----------------------------------------------------------------------------
  # override base_maxhp
  #  This method was changed to allow class stat modifiers.
  #----------------------------------------------------------------------------
  alias base_maxhp_rosys_later base_maxhp
  def base_maxhp
    result, mods = base_maxhp_rosys_later, BlizzCFG.job_stat_mod(@class_id)
    return ((result + mods[0]) * mods[1]).to_i
  end
  #----------------------------------------------------------------------------
  # override base_maxsp
  #  This method was changed to allow class stat modifiers.
  #----------------------------------------------------------------------------
  alias base_maxsp_rosys_later base_maxsp
  def base_maxsp
    result, mods = base_maxsp_rosys_later, BlizzCFG.job_stat_mod(@class_id)
    return ((result + mods[2]) * mods[3]).to_i
  end
  #----------------------------------------------------------------------------
  # override base_str
  #  This method was changed to allow class stat modifiers.
  #----------------------------------------------------------------------------
  alias base_str_rosys_later base_str
  def base_str
    result, mods = base_str_rosys_later, BlizzCFG.job_stat_mod(@class_id)
    return ((result + mods[4]) * mods[5]).to_i
  end
  #----------------------------------------------------------------------------
  # override base_dex
  #  This method was changed to allow class stat modifiers.
  #----------------------------------------------------------------------------
  alias base_dex_rosys_later base_dex
  def base_dex
    result, mods = base_dex_rosys_later, BlizzCFG.job_stat_mod(@class_id)
    return ((result + mods[6]) * mods[7]).to_i
  end
  #----------------------------------------------------------------------------
  # override base_agi
  #  This method was changed to allow class stat modifiers.
  #----------------------------------------------------------------------------
  alias base_agi_rosys_later base_agi
  def base_agi
    result, mods = base_agi_rosys_later, BlizzCFG.job_stat_mod(@class_id)
    return ((result + mods[8]) * mods[9]).to_i
  end
  #----------------------------------------------------------------------------
  # override base_int
  #  This method was changed to allow class stat modifiers.
  #----------------------------------------------------------------------------
  alias base_int_rosys_later base_int
  def base_int
    result, mods = base_int_rosys_later, BlizzCFG.job_stat_mod(@class_id)
    return ((result + mods[10]) * mods[11]).to_i
  end
  #----------------------------------------------------------------------------
  # get_skill_sp_cost_factor
  #  skill_id - skill ID
  #  Returns the SP cost factor of the skill for this actor.
  #----------------------------------------------------------------------------
  def get_skill_sp_cost_factor(skill_id)
    return 1 if skill_max_level?(skill_id)
    return ((BlizzCFG::LVL1_COST - (self.skill_level(skill_id) - 1) *
        (BlizzCFG::LVL1_COST - 100.0) /
        (BlizzCFG.roskill_maxlevel(skill_id) - 1)) / 100)
  end
  #----------------------------------------------------------------------------
  # get_skill_damage_factor
  #  skill_id - skill ID
  #  Returns the damage factor of the skill for this actor.
  #----------------------------------------------------------------------------
  def get_skill_damage_factor(skill_id)
    return 1 if skill_max_level?(skill_id)
    return (BlizzCFG::LVL1_POWER + (self.skill_level(skill_id) - 1) *
        (100.0 - BlizzCFG::LVL1_POWER) /
        (BlizzCFG.roskill_maxlevel(skill_id) - 1)) / 100
  end
  #----------------------------------------------------------------------------
  # skill_max_level?
  #  skill_id - skill ID
  #  Checks if a skill has reached the max level.
  #----------------------------------------------------------------------------
  def skill_max_level?(skill_id)
    return (self.skill_level(skill_id) >= BlizzCFG.roskill_maxlevel(skill_id))
  end
  # if the JOB_ONLY option is not being used, a couple of methods are being
  # parsed for skill level handling
  unless BlizzCFG::JOB_ONLY
  #----------------------------------------------------------------------------
  # skill_level
  #  id - skill ID
  #  Safe return of a skill level for this actor.
  #----------------------------------------------------------------------------
  def skill_level(id)
    return (@skill_level[id] == nil ? 1 : @skill_level[id])
  end
  #----------------------------------------------------------------------------
  # skill_level_change
  #  val - new level value
  #  id  - skill ID
  #  This method processes change of a skill level.
  #----------------------------------------------------------------------------
  def skill_level_change(val, id)
    max_level = BlizzCFG.roskill_maxlevel(id)
    if val > max_level
      @skill_level[id] = max_level
    elsif max_level < 1
      @skill_level[id] = 1
    else
      @skill_level[id] = val
    end
  end
  #----------------------------------------------------------------------------
  # override forget_skill
  #  id - skill ID
  #  This method additionally resets a level when a skill gets removed.
  #----------------------------------------------------------------------------
  alias forget_skill_rosys_later forget_skill
  def forget_skill(id)
    learned = @skills.include?(id)
    forget_skill_rosys_later(id)
    # reset skill level of forgotten skill if that option is active
    @skill_level[id] = 1 if BlizzCFG::RESET_LVLS && learned && !@skills.include?(id)
  end
  #----------------------------------------------------------------------------
  # override skill_can_use?
  #  skill_id - skill ID
  #  This method additionally takes into account the increased SP cost.
  #----------------------------------------------------------------------------
  alias skill_can_use_rosys_later? skill_can_use?
  def skill_can_use?(skill_id)
    skill = $data_skills[skill_id]
    # if not enough SP considering skill level SP cost modification
    if self.sp < (skill.sp_cost * get_skill_sp_cost_factor(skill.id)).to_i
      # skill cannot be used
      return false
    end
    return skill_can_use_rosys_later?(skill_id)
  end
  end
  
end

#==============================================================================
# Game_Battler
#------------------------------------------------------------------------------
#  This class was modified to support skill levels.
#==============================================================================

unless BlizzCFG::JOB_ONLY
class Game_Battler
  
  #----------------------------------------------------------------------------
  # override skill_effect
  #  user  - the skill performer
  #  skill - the skill
  #  This method was modified to support changed damage handling.
  #----------------------------------------------------------------------------
  alias skill_effect_rosys_later skill_effect
  def skill_effect(user, skill)
    # stores old values and executes skill
    last_hp = self.hp
    last_sr = self.sr if $crls && self.is_a?(Game_Actor)
    result = skill_effect_rosys_later(user, skill)
    # if skill was a success and effect needs to be modified
    if result && self.damage.is_a?(Numeric) && user.is_a?(Game_Actor) &&
        !user.skill_max_level?(skill.id)
      # restore values
      self.hp = last_hp
      self.sr = last_sr if $crls && self.is_a?(Game_Actor)
      # modifiy damage considering skill level
      self.damage = (self.damage * user.get_skill_damage_factor(skill.id)).to_i
      # apply skill effect on HP
      self.hp -= self.damage
    end
    return result
  end
  
end

#==============================================================================
# Window_Skill
#------------------------------------------------------------------------------
#  This class was modified to display correct SP consumption if skill levels
#  are being used.
#==============================================================================

class Window_Skill < Window_Selectable
  
  #--------------------------------------------------------------------------
  # override draw_item
  #  i - index
  #  This method was modified to print the correct SP cost.
  #--------------------------------------------------------------------------
  alias draw_item_rosys_later draw_item
  def draw_item(i)
    draw_item_rosys_later(i)
    skill = @data[i]
    # decide color depending on the fact if currently usable
    if @actor.skill_can_use?(skill.id)
      self.contents.font.color = normal_color
    else
      self.contents.font.color = disabled_color
    end
    # remove old SP display
    self.contents.fill_rect(236 + i % 2 * 320, i / 2 * 32, 48, 32,
        Color.new(0, 0, 0, 0))
    # calculate SP cost considering skill level
    sp_cost = (skill.sp_cost * @actor.get_skill_sp_cost_factor(skill.id)).to_i
    # draw SP cost
    self.contents.draw_text(236 + i % 2 * 320, i / 2 * 32, 48, 32,
        sp_cost.to_s, 2)
  end
  
end

#==============================================================================
# Map_Battler
#------------------------------------------------------------------------------
#  This is a Blizz-ABS class.
#==============================================================================

# if Blizz-ABS is being used
if $BlizzABS && BlizzABS::VERSION >= 2.7
class Map_Battler
  
  #----------------------------------------------------------------------------
  # override skill_consumption
  #  Corrects SP consumption in Blizz-ABS.
  #----------------------------------------------------------------------------
  alias skill_consumption_rosys_later skill_consumption
  def skill_consumption(skill)
    if self.is_a?(Map_Actor) && self.valid? &&
        !@battler.skill_max_level?(skill.id)
      skill = skill.clone
      skill.sp_cost = (skill.sp_cost *
          @battler.get_skill_sp_cost_factor(skill.id)).to_i
      if $tons_version != nil && $tons_version >= 7.4 && $game_system.HP_SKILL
        skill.hp_cost = (skill.hp_cost *
            @battler.get_skill_sp_cost_factor(skill.id)).to_i
      end
    end
    skill_consumption_rosys_later(skill)
  end
  
end

#==============================================================================
# Hud
#------------------------------------------------------------------------------
#  This is a Blizz-ABS class.
#==============================================================================

class Hud < Sprite
  
  def get_skills_left
    # stop if skill is not hot skill or does not exist
    return -2 if @skill == nil || @skill == 0
    # infinite usages if SP cost is zero
    return -1 if $data_skills[@skill].sp_cost == 0
    # get SP cost
    sp_cost = ($data_skills[@skill].sp_cost * 
        actor.get_skill_sp_cost_factor(@skill)).to_i
    # if using SP Cost Mod Status
    if $tons_version != nil && $tons_version >= 6.54 &&
        $game_system.SP_COST_MOD
      # get modified cost
      sp_cost = BlizzCFG.get_cost_mod(actor.states, sp_cost)
    end
    # infinite usages if SP cost is zero
    return -1 if sp_cost == 0
    # calculate skills left to use
    return (@sp / sp_cost)
  end
  
end
end

#==============================================================================
# Scene_Battle
#------------------------------------------------------------------------------
#  This class was modified to support correct SP consumption if skill levels
#  are being used.
#==============================================================================

class Scene_Battle
  
  #----------------------------------------------------------------------------
  # override use_skill
  #  skill - the skill to be used
  #  Corrects SP consumption in DBS and RTAB.
  #----------------------------------------------------------------------------
  alias make_skill_action_result_rosys_later make_skill_action_result
  def make_skill_action_result(battler = nil)
    # if RTAB is being used
    if battler != nil
      # store old SP and make result
      old_sp = battler.sp
      make_skill_action_result_rosys_later(battler)
    else
      # store old SP and make result
      old_sp, battler = @active_battler.sp, @active_battler
      make_skill_action_result_rosys_later
    end
    # if skill was really used and SP consumption needs to be modified
    if battler.is_a?(Game_Actor) && @phase4_step != 1 &&
        battler.sp != @skill.sp_cost && !battler.skill_max_level?(@skill.id)
      # change SP considering skill level
      battler.sp = old_sp - (@skill.sp_cost *
          battler.get_skill_sp_cost_factor(@skill.id)).to_i
      @status_window.refresh
    end
  end
  
end
end

#==============================================================================
# Window_Base
#------------------------------------------------------------------------------
#  This class was enhanced with a few drawing utility mehods.
#==============================================================================

class Window_Base < Window
  
  #----------------------------------------------------------------------------
  # draw_actor_battler
  #  actor - the actor
  #  x     - x coordinate
  #  y     - y coordinate
  #  Draws the actor's battler graphic in a window.
  #----------------------------------------------------------------------------
  def draw_actor_battler(actor, x, y)
    # get bitmap and dimentions
    bitmap = RPG::Cache.battler(actor.battler_name, actor.battler_hue)
    cw, ch = bitmap.width, bitmap.height
    src_rect = Rect.new(0, 0, cw, ch)
    # transfer bitmap on window
    self.contents.blt(x - cw / 2, y - ch / 2, bitmap, src_rect)
  end
  #----------------------------------------------------------------------------
  # draw_actor_job
  #  actor - the actor
  #  x     - x coordinate
  #  y     - y coordinate
  #  width - max width
  #  Draws the actor's job data.
  #----------------------------------------------------------------------------
  def draw_actor_job(actor, x, y, width)
    self.contents.font.color = system_color
    # draw all static system words
    self.contents.draw_text(x, y, width, 32, BlizzCFG::Current + ':')
    self.contents.draw_text(x, y + 32, width, 32, BlizzCFG::JobPoints + ':')
    self.contents.draw_text(x, y + 64, width, 32, BlizzCFG::JobLevel + ':')
    self.contents.draw_text(x, y + 96, width, 32, BlizzCFG::JobEXP + ':')
    self.contents.draw_text(x, y + 128, width, 32, BlizzCFG::Next + ':')
    self.contents.font.color = normal_color
    # draw all the data
    self.contents.draw_text(x, y, width, 32, actor.class_name, 2)
    self.contents.draw_text(x, y + 64, width, 32, actor.job_level.to_s, 2)
    self.contents.draw_text(x, y + 96, width, 32, actor.job_exp.to_s, 2)
    nex = BlizzCFG::LVLUP_RATE * actor.job_level * (actor.job_level + 1)
    if actor.job_max_level?
      self.contents.draw_text(x, y + 128, width, 32, BlizzCFG::EmptyEXP, 2)
    else
      self.contents.draw_text(x, y + 128, width, 32,
          (nex - actor.job_exp).to_s, 2)
    end
    # change color to red if no Job Points left
    self.contents.font.color = Color.new(255, 0, 0) if actor.jp == 0
    self.contents.draw_text(x, y + 32, width, 32, actor.jp.to_s, 2)
  end
  
end

#==============================================================================
# Window_Dialog
#------------------------------------------------------------------------------
#  Confirmation Dialog window class.
#==============================================================================

class Window_Dialog < Window_Command
  
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(width, commands = BlizzCFG::YesNo,
        caption = BlizzCFG::AreYouSure)
    # add another command, serves as fix
    commands = commands + ['']
    # set caption
    @caption = caption
    @cursor_width = 32
    super(width, commands)
    # font fix
    if $fontface != nil
      self.contents.font.name = $fontface
      self.contents.font.size = $fontsize
    elsif $defaultfonttype != nil
      self.contents.font.name = $defaultfonttype
      self.contents.font.size = $defaultfontsize
    end
    # set variables
    self.x, self.y, self.z = 320 - self.width / 2, 200 - self.height / 2, 1500
    @item_max, self.opacity = commands.size - 1, 192
    commands.each {|c|
        w = self.contents.text_size(c).width
        @cursor_width = w if @cursor_width < w}
    @cursor_width += 32
    # refresh display
    refresh
    update_cursor_rect
  end
  #----------------------------------------------------------------------------
  # refresh
  #  Added caption text.
  #----------------------------------------------------------------------------
  def refresh
    super
    self.contents.font.color = system_color
    self.contents.draw_text(4, 0, self.width - 40, 32, @caption, 1)
  end
  #----------------------------------------------------------------------------
  # draw_item
  #  i     - index
  #  color - font color
  #  Changed method to draw commands one line off.
  #----------------------------------------------------------------------------
  def draw_item(index, color)
    self.contents.font.color = color
    rect = Rect.new(4, 32 * (index + 1), self.contents.width - 8, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    self.contents.draw_text(rect, @commands[index], 1)
  end
  #----------------------------------------------------------------------------
  # update_cursor_rect
  #  Changed method to draw cursor one line off.
  #----------------------------------------------------------------------------
  def update_cursor_rect
    if @index < 0 || @item_max == 0
      self.cursor_rect.empty
    else
      x = (self.contents.width - @cursor_width) / 2
      self.cursor_rect.set(x, (@index + 1) * 32, @cursor_width, 32)
    end
  end
  
end

#==============================================================================
# Window_ClassStatus
#------------------------------------------------------------------------------
#  This window displays the character status and includes data about the
#  current Job like Level, EXP and Job Points along with stat change if the
#  class is being changed.
#==============================================================================

class Window_ClassStatus < Window_Base
  
  # setting all accessible variables
  attr_accessor :actor
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(actor)
    super(BlizzCFG::RO_RIGHT ? 0 : 224, 0, 416, 480)
    @actor = actor
    self.contents = Bitmap.new(width - 32, height - 32)
    # font fix
    if $fontface != nil
      self.contents.font.name = $fontface
      self.contents.font.size = $fontsize
    elsif $defaultfonttype != nil
      self.contents.font.name = $defaultfonttype
      self.contents.font.size = $defaultfontsize
    end
    refresh
  end
  #----------------------------------------------------------------------------
  # refresh
  #  Processes all that is being drawn.
  #----------------------------------------------------------------------------
  def refresh(id = nil)
    self.contents.clear
    # stop if actor doesn't exist
    return if @actor == nil
    actor = @actor.clone
    # can't use Game_Actor#class_id= because it unequips equipment
    actor.instance_variable_set('@class_id', id) if id != nil
    # draw actor data
    draw_actor_battler(@actor, 280, 128)
    draw_actor_name(@actor, 4, 0)
    draw_actor_level(@actor, 4, 32)
    draw_actor_state(@actor, 4, 64)
    draw_actor_hp(@actor, 4, 160, 160)
    draw_actor_sp(@actor, 4, 192, 160)
    draw_actor_hp_mod(@actor, 4, 160, actor, 160)
    draw_actor_sp_mod(@actor, 4, 192, actor, 160)
    draw_actor_job(@actor, 188, 288, 192)
    (0..6).each {|i|
        draw_actor_parameter(@actor, 4, 224 + 32 * i, i)
        draw_actor_parameter_mod(@actor, 4, 224 + 32 * i, i, actor)}
    self.contents.font.color = system_color
    self.contents.draw_text(4, 96, 80, 32, BlizzCFG::EXP)
    self.contents.draw_text(4, 128, 80, 32, BlizzCFG::Next)
    self.contents.font.color = normal_color
    self.contents.draw_text(4, 96, 156, 32, @actor.exp_s, 2)
    self.contents.draw_text(4, 128, 156, 32, @actor.next_rest_exp_s, 2)
  end
  #--------------------------------------------------------------------------
  # draw_actor_hp_mod
  #  actor - the actor
  #  x     - x-coordinate
  #  y     - y-coordinate
  #  other - the actor before
  #  width - maximal allowed width
  #  This method erases the max HP value to redraw it in the right color.
  #--------------------------------------------------------------------------
  def draw_actor_hp_mod(actor, x, y, other, width = 144)
    # stop if width exceeds max
    return if width - 32 < 108
    # decide color
    if other.maxhp > actor.maxhp
      self.contents.font.color = BlizzCFG::UP_COLOR
    elsif other.maxhp < actor.maxhp
      self.contents.font.color = BlizzCFG::DOWN_COLOR
    else
      return
    end
    # delete old display
    self.contents.fill_rect(x + width - 48, y, 48, 32, Color.new(0, 0, 0, 0))
    # draw
    self.contents.draw_text(x + width - 48, y, 48, 32, other.maxhp.to_s)
  end
  #--------------------------------------------------------------------------
  # draw_actor_sp_mod
  #  actor - the actor
  #  x     - x-coordinate
  #  y     - y-coordinate
  #  other - the actor before
  #  width - maximal allowed width
  #  This method erases the max HP value to redraw it in the right color.
  #--------------------------------------------------------------------------
  def draw_actor_sp_mod(actor, x, y, other, width = 144)
    # stop if width exceeds max
    return if width - 32 < 108
    # decide color
    if other.maxsp > actor.maxsp
      self.contents.font.color = BlizzCFG::UP_COLOR
    elsif other.maxsp < actor.maxsp
      self.contents.font.color = BlizzCFG::DOWN_COLOR
    else
      return
    end
    # delete old display
    self.contents.fill_rect(x + width - 48, y, 48, 32, Color.new(0, 0, 0, 0))
    # draw
    self.contents.draw_text(x + width - 48, y, 48, 32, other.maxsp.to_s)
  end
  #--------------------------------------------------------------------------
  # draw_actor_parameter_mod
  #  actor - the actor
  #  x     - x-coordinate
  #  y     - y-coordinate
  #  other - the actor before
  #  type  - which stat
  #  This method erases a stat value to redraw it in the right color.
  #--------------------------------------------------------------------------
  def draw_actor_parameter_mod(actor, x, y, type, other)
    # decide parameter
    case type
    when 3 then str, v1, v2 = $data_system.words.str, actor.str, other.str
    when 4 then dex, v1, v2 = $data_system.words.dex, actor.dex, other.dex
    when 5 then agi, v1, v2 = $data_system.words.agi, actor.agi, other.agi
    when 6 then int, v1, v2 = $data_system.words.int, actor.int, other.int
    else
      return
    end
    # decide color
    if v2 > v1
      self.contents.font.color = BlizzCFG::UP_COLOR
    elsif v2 < v1
      self.contents.font.color = BlizzCFG::DOWN_COLOR
    else
      return
    end
    # delete old display
    self.contents.fill_rect(x + 120, y, 36, 32, Color.new(0, 0, 0, 0))
    # draw
    self.contents.draw_text(x + 120, y, 36, 32, v2.to_s, 2)
  end
  
end
  
#==============================================================================
# Window_Class
#------------------------------------------------------------------------------
#  This window is a slight modification of the Window_Command window to avoid
#  recoding.
#==============================================================================

class Window_Class < Window_Command
  
  #----------------------------------------------------------------------------
  # draw_item
  #  i     - index
  #  color - font color
  #  Changed to draw class/job and level requirement.
  #----------------------------------------------------------------------------
  def draw_item(i, color)
    self.contents.font.color = color
    rect = Rect.new(4, 32 * i, self.contents.width - 8, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    self.contents.draw_text(rect, @commands[i][0])
    self.contents.draw_text(rect, @commands[i][1], 2)
  end
  
end

#==============================================================================
# Window_SkillLearn
#------------------------------------------------------------------------------
#  This window displays all skills that can be still learned.
#==============================================================================

class Window_SkillLearn < Window_Command
  
  # setting all accessible variables
  attr_reader :commands
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(width, actor)
    @actor = actor
    super(width, refresh_skills)
    self.z, self.height, self.index = 500, 224, -1
    self.x, self.active = BlizzCFG::RO_RIGHT ? 320 : 0, false
  end
  #----------------------------------------------------------------------------
  # refresh_skills
  #  This method sets up the skill list again.
  #----------------------------------------------------------------------------
  def refresh_skills
    skills = $data_classes[@actor.class_id].learnings.clone
    # if using the option to hide skills that don't meet the requirements
    if BlizzCFG::HIDE_SKILLS
      # temporary variable
      lvl = (BlizzCFG::USE_LEVEL ? @actor.level : @actor.job_level)
      # get all learnable skills that weren't learned already
      skills = skills.find_all {|learn|
          @actor.job_level >= learn.level &&
          BlizzCFG.roskill_reqs(learn.skill_id).all? {|r|
              @actor.skills.include?(r[0]) && @actor.skill_level(r[0]) >= r[1]}}
    end
    # filter out all skills that weren't learned already
    skills = skills.find_all {|learn| !@actor.skills.include?(learn.skill_id)}
    return (skills.size == 0 ? [nil] : skills)
  end
  #----------------------------------------------------------------------------
  # refresh
  #  This method was modifies to draw "None" is no skills are available and
  #  refreshes the skill list upon redrawing.
  #----------------------------------------------------------------------------
  def refresh
    @commands = refresh_skills
    @item_max = @commands.size
    if @commands[0] == nil
      self.contents.clear
      self.contents.font.color = disabled_color
      self.contents.draw_text(4, 0, self.contents.width - 8, 32, BlizzCFG::None)
    else
      super
    end
  end
  #----------------------------------------------------------------------------
  # draw_item
  #  i     - index
  #  color - font color
  #  Draws a specific skill and the level requirement to learn it.
  #----------------------------------------------------------------------------
  def draw_item(i, color = nil)
    lvl = (BlizzCFG::USE_LEVEL ? @actor.level : @actor.job_level)
    # decide color depending on which level is used
    if !BlizzCFG::HIDE_SKILLS && (lvl < @commands[i].level ||
        BlizzCFG.roskill_reqs(@commands[i].skill_id).any? {|r|
             !@actor.skills.include?(r[0]) || @actor.skill_level(r[0]) < r[1]})
      self.contents.font.color = disabled_color
    else
      self.contents.font.color = normal_color
    end
    # get rectangle
    rect = Rect.new(32, 32 * i, self.contents.width - 36, 32)
    # get icon bitmap
    bitmap = RPG::Cache.icon($data_skills[@commands[i].skill_id].icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    # draw bitmap
    self.contents.blt(4, 4 + 32 * i, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    # draw name and requirement if not using the hiding option
    self.contents.draw_text(rect, $data_skills[@commands[i].skill_id].name)
    unless BlizzCFG::HIDE_SKILLS
      self.contents.draw_text(rect,
        "(#{BlizzCFG::Lv} #{@commands[i].level})", 2)
    end
  end
  #----------------------------------------------------------------------------
  # update_help
  #  Updates the skill status display.
  #----------------------------------------------------------------------------
  def update_help
    @help_window.set_text(@commands[index] == nil ? 0 : @commands[index].skill_id)
  end
  
end

#==============================================================================
# Window_SkillImprove
#------------------------------------------------------------------------------
#  This window displays skills that are already learned.
#==============================================================================

class Window_SkillImprove < Window_Command
  
  # setting all accessible variables
  attr_accessor :commands
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(width, actor)
    @actor, skills = actor, actor.skills
    skills = [nil] if skills.size == 0
    super(width, skills)
    self.z, self.height, self.index = 500, 224, -1
    self.x, self.active = BlizzCFG::RO_RIGHT ? 0 : 320, false
  end
  #----------------------------------------------------------------------------
  # set_commands
  #  commands - new commands
  #  Sets a new list of skills and updates the display.
  #----------------------------------------------------------------------------
  def set_commands(commands)
    commands = [nil] if commands.size == 0
    @commands, @item_max = commands, commands.size
    self.contents.dispose
    self.contents = Bitmap.new(width - 32, @item_max * 32)
    refresh
  end
  #----------------------------------------------------------------------------
  # refresh
  #  Changed to draw "None" if no skills are available.
  #----------------------------------------------------------------------------
  def refresh
    if @commands[0] == nil
      self.contents.clear
      self.contents.font.color = disabled_color
      self.contents.draw_text(4, 0, self.contents.width - 8, 32, BlizzCFG::None)
    else
      super
    end
  end
  #----------------------------------------------------------------------------
  # draw_item
  #  i     - index
  #  color - font color
  #  Draws a specific skill with SP cost, considering the changed SO cost due
  #  to the skill level.
  #----------------------------------------------------------------------------
  def draw_item(i, color = nil)
    skill = $data_skills[@commands[i]]
    # decide color whether skill can still be improved
    if @actor.skill_max_level?(skill.id)
      self.contents.font.color = disabled_color
    else
      self.contents.font.color = color
    end
    # get rectangle
    rect = Rect.new(32, 32 * i, self.contents.width - 36, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    # get icon bitmap
    bitmap = RPG::Cache.icon(skill.icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    # draw bitmap
    self.contents.blt(4, 4 + 32 * i, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(rect, skill.name)
    # calculate SP cost considering skill level
    sp_cost = (skill.sp_cost * @actor.get_skill_sp_cost_factor(skill.id)).to_i
    # draw SP cost
    self.contents.draw_text(rect, sp_cost.to_s, 2)
  end
  #----------------------------------------------------------------------------
  # update_help
  #  Updates the skill status display.
  #----------------------------------------------------------------------------
  def update_help
    @help_window.set_text(@commands[index] == nil ? 0 : @commands[index])
  end
  
end

#==============================================================================
# Window_SkillLevel
#------------------------------------------------------------------------------
#  This window displays the current skill's data like Level, Power Percentage,
#  modified SP Cost, etc.
#==============================================================================

class Window_SkillLevel < Window_Base
  
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(actor)
    super(BlizzCFG::RO_RIGHT ? 0 : 416, 0, 224, 192)
    @actor, self.contents = actor, Bitmap.new(width - 32, height - 32)
    # font fix
    if $fontface != nil
      self.contents.font.name = $fontface
      self.contents.font.size = $fontsize
    elsif $defaultfonttype != nil
      self.contents.font.name = $defaultfonttype
      self.contents.font.size = $defaultfontsize
    end
    @help_window = Window_Help.new
  end
  #----------------------------------------------------------------------------
  # refresh
  #  Helping method for easier code overview that redraws the display no matter
  #  what.
  #----------------------------------------------------------------------------
  def refresh
    return if @skill == nil
    id, @skill = @skill.id, nil
    set_text(id)
  end
  #----------------------------------------------------------------------------
  # set_text
  #  id - skill ID
  #  This method draws the currently selected skill's data and stores it so the
  #  display only gets redrawn each time it changes.
  #----------------------------------------------------------------------------
  def set_text(id)
    # stop if same skill as before
    return if @skill == $data_skills[id]
    self.contents.clear
    @skill = $data_skills[id]
    # if skill doesn't exist
    if @skill == nil
      # emtpy description window and stop
      @help_window.set_text('')
      return
    end
    # get icon bitmap and draw it
    bitmap = RPG::Cache.icon(@skill.icon_name)
    self.contents.blt(4, 4, bitmap, Rect.new(0, 0, 24, 24))
    self.contents.draw_text(32, 0, 156, 32, @skill.name)
    # calculate SP cost considering skill level
    sp_cost = (@skill.sp_cost * @actor.get_skill_sp_cost_factor(@skill.id)).to_i
    # calculate damage multiplier considering skill level
    power = (100 * @actor.get_skill_damage_factor(@skill.id)).to_i
    self.contents.font.color = system_color
    # draw all static words
    self.contents.draw_text(4, 32, 184, 32, BlizzCFG::SkillLevel + ':')
    self.contents.draw_text(4, 64, 184, 32, BlizzCFG::MaximumLevel + ':')
    self.contents.draw_text(4, 96, 184, 32, BlizzCFG::Cost + ':')
    self.contents.draw_text(4, 128, 184, 32, BlizzCFG::Power + ':')
    self.contents.draw_text(4, 64, 184, 32,
        BlizzCFG.roskill_maxlevel(@skill.id).to_s, 2)
    self.contents.font.color = normal_color
    # draw all the data
    self.contents.draw_text(4, 32, 184, 32, @actor.skill_level(@skill.id).to_s, 2)
    sp_cost = "#{sp_cost} #{$data_system.words.sp}"
    self.contents.draw_text(4, 96, 184, 32, sp_cost, 2)
    self.contents.draw_text(4, 128, 184, 32, "#{power}%", 2)
    # set help window text to skill description
    @help_window.set_text(@skill.description, 1)
  end
  #----------------------------------------------------------------------------
  # dispose
  #  This method was enhanced to dispose the skill description window.
  #----------------------------------------------------------------------------
  def dispose
    @help_window.dispose
    super
  end
  
end

#==============================================================================
# Window_JobLevel
#------------------------------------------------------------------------------
#  This window displays job data.
#==============================================================================

class Window_JobLevel < Window_Base
  
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(actor)
    super(BlizzCFG::RO_RIGHT ? 416 : 0, 0, 224, 192)
    @actor, self.contents = actor, Bitmap.new(width - 32, height - 32)
    # font fix
    if $fontface != nil
      self.contents.font.name = $fontface
      self.contents.font.size = $fontsize
    elsif $defaultfonttype != nil
      self.contents.font.name = $defaultfonttype
      self.contents.font.size = $defaultfontsize
    end
    refresh
  end
  #----------------------------------------------------------------------------
  # refresh
  #  This method draws the job data.
  #----------------------------------------------------------------------------
  def refresh
    self.contents.clear
    draw_actor_job(@actor, 4, 0, 184)
  end
  
end

#==============================================================================
# Scene_ClassChange
#------------------------------------------------------------------------------
#  This scene processes the class/job change system.
#==============================================================================

class Scene_ClassChange
  
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(index = 0, scene = Scene_Map)
    @actor, @scene = $game_party.actors[index], scene
  end
  #----------------------------------------------------------------------------
  # main
  #  Main processing method.
  #----------------------------------------------------------------------------
  def main
    # create main command window
    @command_window = Window_Command.new(224, BlizzCFG::ClassCommands)
    @command_window.x = BlizzCFG::RO_RIGHT ? 416 : 0
    # create status window
    @status_window = Window_ClassStatus.new(@actor)
    @old_index = 0
    make_class_window
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      break if $scene != self
    end
    Graphics.freeze
    # delete all windows
    @command_window.dispose
    @status_window.dispose
    @class_window.dispose
  end
  #----------------------------------------------------------------------------
  # make_class_window
  #  This method helps to make the code easier to overview.
  #----------------------------------------------------------------------------
  def make_class_window
    # delete old window if there is one
    @class_window.dispose unless @class_window == nil || @class_window.disposed?
    # get configuration and initialize data
    @configs = BlizzCFG.rojob_next(@actor.class_id)
    commands, lvl = [], (BlizzCFG::USE_LEVEL ? @actor.level : @actor.job_level)
    # if no configs
    if @configs[0].size == 0
      # set to "None"
      commands = [[BlizzCFG::None, '']]
    else
      # add command data
      @configs.each {|c| commands.push([$data_classes[c[1]].name,
          "(#{BlizzCFG::Lv} #{c[0]})"])}
    end
    # create window with given data
    @class_window = Window_Class.new(224, commands)
    @class_window.x, @class_window.y = BlizzCFG::RO_RIGHT ? 416 : 0, 160
    @class_window.height, @class_window.index = 320, -1
    # if no configuration
    if @configs[0].size == 0
      # set text color to disabled
      @class_window.disable_item(0)
      @command_window.disable_item(0)
    else
      # disable each new class/job that does not fulfill the requirement
      @configs.each_index {|i|
          @class_window.disable_item(i) if lvl < @configs[i][0]}
      @command_window.refresh
    end
  end
  #----------------------------------------------------------------------------
  # update
  #  This is the main update method which calls the appropriate method
  #  depending on which window is currently active.
  #----------------------------------------------------------------------------
  def update
    if @command_window.active
      @command_window.update
      update_command
    elsif @sure_window != nil
      @sure_window.update
      update_sure
    elsif @class_window.active
      @class_window.update
      update_classchange
    end
  end
  #----------------------------------------------------------------------------
  # update_comand
  #  This method updates the command window input.
  #----------------------------------------------------------------------------
  def update_command
    # if cancel button pressed
    if Input.trigger?(Input::B)
      # play sound and return to previous scene
      $game_system.se_play($data_system.cancel_se)
      $scene = @scene.new
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      size = $game_party.actors.size
      # depending on chosen option activate jobchange, change actor or leave
      case @command_window.index
      when 0
        if @configs[0].size == 0
          $game_system.se_play($data_system.buzzer_se)
          return
        end
        $game_system.se_play($data_system.decision_se)
        @command_window.active, @class_window.active = false, true
        @class_window.index = @old_index
        @status_window.refresh(@configs[@class_window.index][1])
      when 1 then $scene = self.class.new((@actor.index + 1) % size, @scene)
      when 2 then $scene = self.class.new((@actor.index + size - 1) % size, @scene)
      when 3 then $scene = @scene.new
      end
      $game_system.se_play($data_system.decision_se)
    end
  end
  #----------------------------------------------------------------------------
  # update_classchange
  #  This method updates the class change window input.
  #----------------------------------------------------------------------------
  def update_classchange
    # if cancel button pressed
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @command_window.active = true
      @old_index = @class_window.index
      @class_window.active, @class_window.index = false, -1
      @status_window.refresh
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      lvl = (BlizzCFG::USE_LEVEL ? @actor.level : @actor.job_level)
      # if requirements are not fulfilled
      if lvl < @configs[@class_window.index][0]
        $game_system.se_play($data_system.buzzer_se)
      else
        $game_system.se_play($data_system.decision_se)
        # create confirmation window
        @sure_window = Window_Dialog.new(224, BlizzCFG::YesNo,
            BlizzCFG::ChangeClass)
        @sure_window.z, @class_window.active = 500, false
      end
    # if up/down is being pressed
    elsif Input.trigger?(Input::UP) || Input.trigger?(Input::DOWN)
      # apply status window change
      @status_window.refresh(@configs[@class_window.index][1])
    end
  end
  #----------------------------------------------------------------------------
  # update_sure
  #  This method updates the confirmation window input.
  #----------------------------------------------------------------------------
  def update_sure
    # if cancel button pressed
    if Input.trigger?(Input::B)
      # play sound and remove confirmation window
      $game_system.se_play($data_system.cancel_se)
      @sure_window.dispose
      @class_window.active, @sure_window = true, nil
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      # either accept or decline and remove confirmation window
      case @sure_window.index
      when 0
        id = @actor.class_id
        @actor.class_id = @configs[@class_window.index][1]
        @actor.hp, @actor.sp = @actor.hp, @actor.sp
        @status_window.refresh
        if !BlizzCFG::JOB_ONLY && BlizzCFG::CLASS_SKILLS &&
            @actor.class_id != id && $data_classes[id] != nil
          # remove all skills
          $data_classes[id].learnings.each {|i| @actor.forget_skill(i.skill_id)}
        end
        make_class_window
        @sure_window.dispose
        @command_window.active, @sure_window = true, nil
        @old_index = 0
      when 1
        @sure_window.dispose
        @class_window.active, @sure_window = true, nil
      end
    end
  end
  
end

#==============================================================================
# Scene_SkillChange
#------------------------------------------------------------------------------
#  This scene processes the learning and improving (leveling up) of RO skills.
#==============================================================================

class Scene_SkillChange
  
  #----------------------------------------------------------------------------
  # Initialization
  #----------------------------------------------------------------------------
  def initialize(index = 0, scene = Scene_Map)
    @actor, @scene = $game_party.actors[index], scene
  end
  #----------------------------------------------------------------------------
  # main
  #  This is the main processing method.
  #----------------------------------------------------------------------------
  def main
    # create main command window
    @command_window = Window_Command.new(192, BlizzCFG::SkillCommands)
    # create other windows
    @learn_window = Window_SkillLearn.new(320, @actor)
    @skill_window = Window_SkillImprove.new(320, @actor)
    @status_window = Window_SkillLevel.new(@actor)
    @job_window = Window_JobLevel.new(@actor)
    # set window positions
    @command_window.y = @status_window.y = @job_window.y = 64
    @command_window.x, @learn_window.y, @skill_window.y = 224, 256, 256
    @learn_window.x, @skill_window.x = 320, 0 if BlizzCFG::RO_RIGHT
    @learn_window.help_window = @skill_window.help_window = @status_window
    # skill status window must be clear
    @status_window.set_text(0)
    # disable command if no skills in the given category
    @command_window.disable_item(0) if @learn_window.commands[0] == nil
    @command_window.disable_item(1) if @skill_window.commands[0] == nil
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      break if $scene != self
    end
    Graphics.freeze
    # remove all windows
    [@command_window, @learn_window, @skill_window, @status_window,
        @job_window].each {|win|win.dispose}
  end
  #----------------------------------------------------------------------------
  # update
  #  This is the main update method which calls the appropriate method
  #  depending on which window is currently active.
  #----------------------------------------------------------------------------
  def update
    if @command_window.active
      @command_window.update
      update_command
    elsif @sure_window != nil
      @sure_window.update
      # update the correct confirmation
      @learn_window.index >= 0 ? update_sure_learn : update_sure_skill
    elsif @learn_window.active
      @learn_window.update
      update_learn
    elsif @skill_window.active
      @skill_window.update
      update_skill
    end
  end
  #----------------------------------------------------------------------------
  # update_sure
  #  This method updates the command window input.
  #----------------------------------------------------------------------------
  def update_command
    # if cancel button pressed
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = @scene.new
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      size = $game_party.actors.size
      # choose next menu, change actor or leave
      case @command_window.index
      when 0
        # if no skills in this category
        if @learn_window.commands[0] == nil
          # play sound and stop
          $game_system.se_play($data_system.buzzer_se)
          return
        end
        # play sound and activate other window
        $game_system.se_play($data_system.decision_se)
        @command_window.active, @learn_window.active = false, true
        @learn_window.index = 0
      when 1
        # if no skills in this category
        if @skill_window.commands[0] == nil
          # play sound and stop
          $game_system.se_play($data_system.buzzer_se)
          return
        end
        # play sound and activate other window
        $game_system.se_play($data_system.decision_se)
        @command_window.active, @skill_window.active = false, true
        @skill_window.index = 0
      when 2 then $scene = self.class.new((@actor.index + 1) % size, @scene)
      when 3 then $scene = self.class.new((@actor.index + size - 1) % size, @scene)
      when 4 then $scene = @scene.new
      end
      $game_system.se_play($data_system.decision_se)
    end
  end
  #----------------------------------------------------------------------------
  # update_sure
  #  This method updates the skill learn window input.
  #----------------------------------------------------------------------------
  def update_learn
    # if cancel button pressed
    if Input.trigger?(Input::B)
      # play sound and return to main command
      $game_system.se_play($data_system.cancel_se)
      @command_window.active, @learn_window.active = true, false
      @status_window.set_text(0)
      @learn_window.index = -1
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      lvl = (BlizzCFG::USE_LEVEL ? @actor.level : @actor.job_level)
      # temporary variable
      learn = @learn_window.commands[@learn_window.index]
      # if skill doesn't exist, cannot be learned, no Job Points or reqs not fulfilled
      if learn == nil || @actor.jp == 0 || lvl < learn.level ||
          BlizzCFG.roskill_reqs(learn.skill_id).any? {|r|
              !@actor.skills.include?(r[0]) || @actor.skill_level(r[0]) < r[1]}
        # play sound
        $game_system.se_play($data_system.buzzer_se)
      else
        # play sound and create confirmation window
        $game_system.se_play($data_system.decision_se)
        @sure_window = Window_Dialog.new(224, BlizzCFG::YesNo,
            BlizzCFG::LearnSkill)
        @learn_window.active = false
      end
    end
  end
  #----------------------------------------------------------------------------
  # update_sure
  #  This method updates the skill improve window input.
  #----------------------------------------------------------------------------
  def update_skill
    # if cancel button pressed
    if Input.trigger?(Input::B)
      # play sound and return to main command
      $game_system.se_play($data_system.cancel_se)
      @command_window.active, @skill_window.active = true, false
      @status_window.set_text(0)
      @skill_window.index = -1
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      skill = $data_skills[@skill_window.commands[@skill_window.index]]
      # if no Job Points skill or skill already maximized
      if @actor.jp == 0 || @actor.skill_max_level?(skill.id)
        # play sound
        $game_system.se_play($data_system.buzzer_se)
      else
        # play sound and create confirmation window
        $game_system.se_play($data_system.decision_se)
        @sure_window = Window_Dialog.new(224, BlizzCFG::YesNo,
            BlizzCFG::ImproveSkill)
        @skill_window.active = false
      end
    end
  end
  #----------------------------------------------------------------------------
  # update_sure
  #  This method updates the confirmation of learning input.
  #----------------------------------------------------------------------------
  def update_sure_learn
    # if cancel button pressed
    if Input.trigger?(Input::B)
      # play sound and remove confirmation window
      $game_system.se_play($data_system.cancel_se)
      @sure_window.dispose
      @learn_window.active, @sure_window = true, nil
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      # if confirmed
      if @sure_window.index == 0
        # consume Job Point
        @actor.jp -= 1
        # temporary variable
        id = @learn_window.commands[@learn_window.index].skill_id
        # if CRLS is installed and CD skill
        if $crls != nil && BlizzCFG::CD_SKILLS.include?(id)
          # learn new CD skill
          @actor.learn_cd(id)
        else
          # learn new skill
          @actor.learn_skill(id)
        end
        # update window displays
        @learn_window.refresh
        @skill_window.set_commands(@actor.skills.clone)
        if @learn_window.commands[0] == nil
          @command_window.disable_item(0)
        else
          @command_window.draw_item(0, @command_window.normal_color)
        end
        if @skill_window.commands[0] == nil
          @command_window.disable_item(1)
        else
          @command_window.draw_item(1, @command_window.normal_color)
        end
        @job_window.refresh
      end
      # remove confirmation window
      @sure_window.dispose
      @learn_window.active, @sure_window = true, nil
    end
  end
  #----------------------------------------------------------------------------
  # update_sure
  #  This method updates the confirmation of improving input.
  #----------------------------------------------------------------------------
  def update_sure_skill
    # if cancel button pressed
    if Input.trigger?(Input::B)
      # play sound and remove confirmation window
      $game_system.se_play($data_system.cancel_se)
      @sure_window.dispose
      @skill_window.active, @sure_window = true, nil
    # if confirm button pressed
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      if @sure_window.index == 0
        skill = $data_skills[@skill_window.commands[@skill_window.index]]
        # consume Job Point
        @actor.jp -= 1
        # improve skill
        @actor.skill_level_change(@actor.skill_level(skill.id) + 1, skill.id)
        # update window displays
        [@status_window, @skill_window, @learn_window, @job_window].each {|win|
            win.refresh}
        (0..1).each {|i| @command_window.draw_item(i, Color.new(255, 255, 255))}
        @command_window.disable_item(0) if @learn_window.commands[0] == nil
        @command_window.disable_item(1) if @skill_window.commands[0] == nil
      end
      # remove confirmation window
      @sure_window.dispose
      @skill_window.active, @sure_window = true, nil
    end
  end
  
end
