#============================================================================
# Jobs Profficiency & Rewards v1.3
# By Emerald
#----------------------------------------------------------------------------
# You're free to use the script for any game, as long as you give credits
#----------------------------------------------------------------------------
# Version History
# 1.0 -> Started script. Added all basic values (configuration, Job Levels,
#        Job Exp., Exp. Degrade, Job Drops).
# 1.1 -> Added a window which appears when a job level increases.
# 1.2 -> Added a method which makes changes to DataManager
#        unnecessary.
# 1.3 -> Updated DataManager methods to avoid bugs while loading savefiles.
#----------------------------------------------------------------------------
# With this script, you can easily make evented jobs without having to go
# through the trouble of wasting variables or conditional branches.
#
# Instructions:
#
# Just as always, put this script between ▼ Materials and ▼ Main (way to cliche
# people).
#
# To define the different jobs and their exp to next level/max level, go to
# Jobs. Use the following syntax:
#
# Job ID => [exp to next level, ..., initial level]
#
# Job ID of the first job should be 1 and the following number of any subsequent
# job.
# Exp to next level is how much exp. the player must get in this job to level up.
# You can put as many of these in the array as you want. The final Max Level is
# the same as the amount of times you've added an 'exp to next level' element + 1.
# Initial level is the starting level of the player in the job. You can just leave
# it at 1. NOTE  that the exp in the very first element is the exp needed to reach
# level 2, not the level which comes after the initial level. Also, NEVER set the
# initial level to 0.
#
#
# To define all the drops gained by doing a job, go to Drops. Use this syntax:
#
# Sort ID => [[Drop Type, Drop Amount, Drop Random Amount, Drop Chance, Drop Rand Incr, Drop Chan Incr, Drop ID]]
#
# Sort ID is just an ID to use in the method for executing the drop check.
# Drop Type defines WHAT is dropped. Drop types are:
# 0 - Item
# 1 - Weapon
# 2 - Armor
# 3 - Gold
# 4 - Job Experience
# Drop Amount is the standard amount gained of the drop.
# Drop Random Amount is the limit of the random amount of drop gained.
# Chance is the chance that the player gets the drop. Like 75 is 75% chance.
# Drop Rand Incr is the value that Drop Random Amount will be multiplied with for
# every level higher than 1. Note that if you want to have a 10% increase, use
# 1.10, not 10.00.
# Drop Chan Incr is the same as Drop Rand Incr, but this time for the chance.
# Drop ID is the ID of what is dropped. If the Drop Type is 3, you can leave this
# out. If the Drop Type is 0, 1 or 2 the Drop ID is the ID of the item gained.
# If the Drop Type is 4, the Drop ID is the ID of the job to which experience is
# added.
#
#
# At the moment the game should check if anything is gained from the job, use
# $jobs_experience.random_drops(sort, job) in a script call command. Sort is the
# Sort ID within Drops. Job is the Job ID to which the sort belongs.
#
# You can also use $jobs_experience.level(job id) to get the level of the job with
# job id.
#
#
# Module EME
# JOB_LEVEL_VOCAB | this is the name of the levels for jobs, shown in the level up
#                   window.
# JOB_NAMES       | this is an array containing all the names for the jobs. Set to
#                   nil if a job doesn't have a name.
# JOB_SOUND       | this is the sound to be played when job level increases. Set
#                   nil if you don't want a sound to be played.
# JOB_SOUND2      | this is the sound to be played when job level decreases. Set
#                   nil if you don't want a sound to be played.
# LVL_WNDW_WAIT   | this is the amount of frames to wait before the level up
#                   window disappears.
# LVL_WNDW_SKIN   | skin of the window shown upon job level up. Must be in the
#                   folder System. Don't add the extension name.
# JOB_WNDW_SHOW   | set to true if you want the job level up window to appear.
#
#
# OPTIONAL
# If you want to degrade exp/levels as time goes by, set LOST_EXP to the amount
# of exp which is lost. Create a new Common Event. Set the trigger to Paralell
# Process. Use the script call command and enter:
#
# wait(frames)
# $jobs_experience.exp_degrade
#
# Where frames is the amount of frames before the player loses LOST_EXP.
# NOTE that EVERY job loses exp. equal to LOST_EXP. Also, the event KEEPS RUNNING,
# even when the player is doing a job. Unless the required exp. is a very high
# amount, keep degrade time high! Last, the Job Level will NOT decrease until
# the exp. for that job is equal to 0.
#----------------------------------------------------------------------------
# Made as request for:
# ShadowFox
#----------------------------------------------------------------------------
# If you have any issues with this script, contact me at
# [url]http://www.rpgmakervxace.net/index.php?/[/url]
#============================================================================
#
# CONFIGURATION
#
#============================================================================
module EME

Jobs = {
  1 => [5, 10, 15, 20, 25, 30, 35, 40, 45, 1]
}

Drops = {
  1 => [[0, 5, 5, 75, 1.20, 0.90, 1]]
}

  LOST_EXP          =  1
  JOB_LEVEL_VOCAB   = "Level"
  JOB_NAMES         = ["Mining"]
  JOB_SOUND         = "Fanfare1"
  JOB_SOUND_VOLUME  = 80
  JOB_SOUND_PITCH   = 100
  JOB_SOUND2        = "Gag"
  JOB_SOUND_VOLUME2 = 80
  JOB_SOUND_PITCH2  = 100
  LVL_WNDW_WAIT     = 10
  LVL_WNDW_SKIN     = "Window"
  JOB_WNDW_SHOW     = true

end

#---------------------------------------------------------
# Only edit things past here if you know what you're doing
#---------------------------------------------------------

#============================================================================
#
# DataManager
# Takes care of initializing and saving/loading the variables.
#============================================================================
module DataManager

  class << self
    alias eme_jpr_create_objects create_game_objects
    alias eme_jpr_make_contents make_save_contents
    alias eme_jpr_extract_contents extract_save_contents
  end

  def self.create_game_objects
    self.eme_jpr_create_objects
    $jobs_experience = Job_Experience.new
  end

  def self.make_save_contents
    contents = self.eme_jpr_make_contents
    contents[:jobs] = $jobs_experience
    return contents
  end

  def self.extract_save_contents(contents)
    self.eme_jpr_extract_contents(contents)
    $jobs_experience = contents[:jobs]
  end

end

#============================================================================
#
# Window_JobLevel
# Window shown if job level up.
#============================================================================

class Window_JobLevel < Window_Base

  def initialize(x = 40, y = 148, width = 464, height = 48)
    super
    self.windowskin = Cache.system(EME::LVL_WNDW_SKIN)
    Audio.me_play('Audio/ME/' + EME::JOB_SOUND, EME::JOB_SOUND_VOLUME, EME::JOB_SOUND_PITCH) if EME::JOB_SOUND != nil
    refresh
  end

  def refresh
    contents.clear
    if EME::JOB_NAMES[$eme_job - 1] == nil
      draw_text(4, 0, contents.width - 4, 24, "Job " + EME::JOB_LEVEL_VOCAB + " increased to" + $jobs_experience.level($eme_job).to_s + "!", 1)
    else
      draw_text(4, 0, contents.width - 4, 24, EME::JOB_NAMES[$eme_job - 1] + " " + EME::JOB_LEVEL_VOCAB + " increased to " + $jobs_experience.level($eme_job).to_s + "!", 1)
    end
  end

end

#============================================================================
#
# Window_JobLevel2
# Window shown if job level down.
#============================================================================

class Window_JobLevel2 < Window_Base

  def initialize(x = 40, y = 148, width = 464, height = 48)
    super
    self.windowskin = Cache.system(EME::LVL_WNDW_SKIN)
    Audio.me_play('Audio/ME/' + EME::JOB_SOUND2, EME::JOB_SOUND_VOLUME2, EME::JOB_SOUND_PITCH2) if EME::JOB_SOUND2 != nil
    refresh
  end

  def refresh
    contents.clear
    if EME::JOB_NAMES[$eme_job - 1] == nil
      draw_text(4, 0, contents.width - 4, 24, "Job " + EME::JOB_LEVEL_VOCAB + " decreased to" + $jobs_experience.level($eme_job).to_s + "...", 1)
    else
      draw_text(4, 0, contents.width - 4, 24, EME::JOB_NAMES[$eme_job - 1] + " " + EME::JOB_LEVEL_VOCAB + " decreased to " + $jobs_experience.level($eme_job).to_s + "...", 1)
    end
  end

end

#============================================================================
#
# Job_Experience
# Class which makes experience/level/other variables.
#============================================================================

class Job_Experience

  def initialize
    @data = []
  end

  def [](variable_id)
    @data[variable_id] || 0
  end

  def []=(variable_id, value)
    @data[variable_id] = value
    level_change?(variable_id)
    on_change
  end

  def level(variable_id)
    last_element = EME::Jobs[variable_id].size - 1
    return EME::Jobs[variable_id][last_element]
  end

  def level_change?(variable_id)
    last_element = EME::Jobs[variable_id].size - 1
    level = EME::Jobs[variable_id][last_element] - 1
    if @data[variable_id] >= EME::Jobs[variable_id][level] and level != last_element
      EME::Jobs[variable_id][last_element] += 1
      @data[variable_id] -= EME::Jobs[variable_id][level]
      $eme_job = variable_id
      if EME::JOB_WNDW_SHOW
        create_level_window
        EME::LVL_WNDW_WAIT.times { Fiber.yield }
        $job_level_window.dispose
      end
    end
  end

  def on_change
    $game_map.need_refresh = true
  end

  def create_level_window
    $job_level_window = Window_JobLevel.new
  end

  def times_done
    return @times_done
  end

  def times_done_add
    @times_done += 1
  end

  def exp_degrade
    for i in 1..EME::Jobs.size
      last_element = EME::Jobs[i].size - 1
      if EME::Jobs[i][last_element] != 1
        if $jobs_experience[i] == 0
          EME::Jobs[i][last_element] -= 1
          if EME::JOB_WNDW_SHOW
            $job_level_window2 = Window_JobLevel2.new
            EME::LVL_WNDW_WAIT.times { Fiber.yield }
            $job_level_window2.dispose
          end
          level = level(i)
          $jobs_experience[i] -= EME::LOST_EXP
          $jobs_experience[i] += EME::Jobs[i][level - 1]
        else
          $jobs_experience[i] -= 1
        end
      else
        $jobs_experience[i] -= EME::LOST_EXP
        $jobs_experience[i] = 0 if $jobs_experience[i] < 0
      end
    end
  end

  def random_drops(sort, job_id)
    for i in 0... EME::Drops[sort].size
      chance =  EME::Drops[sort][i][3] * (EME::Drops[sort][i][5] ** ($jobs_experience.level(job_id) - 1))
      chance.round
      if rand(100) <= chance
        type = EME::Drops[sort][i][0]
        amount = EME::Drops[sort][i][1]
        rand_amount = EME::Drops[sort][i][2]
        case type
        when 0
          item_id = EME::Drops[sort][i][6]
          real_amount = amount + rand(rand_amount) * (EME::Drops[sort][i][4] ** ($jobs_experience.level(job_id) - 1))
          real_amount.round
          $game_party.gain_item($data_items[item_id], (real_amount.to_f).truncate)
        when 1
          weapon_id = EME::Drops[sort][i][6]
          real_amount = amount + rand(rand_amount) * (EME::Drops[sort][i][4] ** ($jobs_experience.level(job_id) - 1))
          real_amount.round
          $game_party.gain_item($data_weapons[weapon_id], (real_amount.to_f).truncate)
        when 2
          armor_id = EME::Drops[sort][i][6]
          real_amount = amount + rand(rand_amount) * (EME::Drops[sort][i][4] ** ($jobs_experience.level(job_id) - 1))
          real_amount.round
          $game_party.gain_item($data_armors[armor_id], (real_amount.to_f).truncate)
        when 3
          real_amount = amount + rand(rand_amount) * (EME::Drops[sort][i][4] ** ($jobs_experience.level(job_id) - 1))
          real_amount.round
          $game_party.gain_gold((real_amount.to_f).truncate)
        when 4
          job_id = EME::Drops[sort][i][6]
          real_amount = amount + rand(rand_amount) * (EME::Drops[sort][i][4] ** ($jobs_experience.level(job_id) - 1))
          real_amount.round
          $jobs_experience[job_id] += (real_amount.to_f).truncate
        end
      end
    end
  end

end