#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Advanced Analyze System by Blizzard
# Version: 2.3b
# Type: Enemy Scan Window and Skill
# Date: 5.7.2006
# Date v1.1b: 31.8.2006
# Date v1.2b: 23.2.2007
# Date v1.3b: 7.7.2007
# Date v2.0b: 12.7.2007
# Date v2.1b: 6.8.2007
# Date v2.2b: 24.9.2007
# Date v2.21b: 8.4.2008
# Date v2.3b: 28.7.2009
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#   
#  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:
# 
#   96% compatible with SDK v1.x. 70% compatible with SDK v2.x. May cause
#   incompatibility issues with exotic CBS-es. WILL corrupt your old savegames.
# 
# 
# Features:
# 
#   - make one or more skills to be able to analyze enemies
#   - display of full data of enemies
#   - option to disable different information
#   - integrated support for my "Bestiary" script and option to override it and
#     only add analyzed enemies
#   - press SHIFT/ENTER to change the appearance of the analyze window
#   - use LEFT/RIGHT/UP/DOWN to navigate through the information database
# 
# new in v1.1b:
#   - shorter, better and more simple code
#   - fixed the bug where trying to use a skill in the menu caused loss of SP,
#     no matter if the skill was used or could not be used
#   - updates now the spriteset while the Analyze window is visible
# 
# new in v1.2b:
#   - improved coding (uses less RAM now and processes faster)
# 
# new in v1.3b:
#   - increased compatibility
# 
# new in v2.0b:
#   - completely overworked and fixed compatibility issues
# 
# new in v2.1b:
#   - added custom info possibility
# 
# new in v2.2b:
#   - rewritten conditions using classic syntax to avoid RGSS conditioning bug
#   - improved coding
# 
# new in v2.21b:
#   - improved coding
# 
# new in v2.3b:
#   - improved coding
# 
# 
# Instructions:
# 
# - Explanation:
# 
#   This script will allow your characters to retrieve information about
#   enemies during battle and show them in a window. It also has built-in
#   compatibility for my "Bestiary" script and allows adding enemies to it only
#   if enemies were analyzed at least once. This script can easily be used for
#   Pokémon typed games.
# 
# - Configuration:
# 
#   Configure the part below and make one or more skills, that can analyze
#   enemies. Add the IDs into the array called ANALYZE_IDS and separate them
#   with commas. If you have one or more scripts using dummy elements (e.g. my
#   EQUAP Skills, SephirothSpawn's Limit Break, etc.) be sure to include every
#   dummy element ID in the array called ELM_DUMMIES, also separated by commas.
#   With advanced configuration it is possible to disable different information
#   display, even during the game. Also it can be set up, that an enemy is
#   being rendered unanalyzeable or only partially unanalyzeable (e.g. disable
#   display of extreme element weaknesses for an enemy, etc.). Put this script
#   UNDER my "Bestiary" script if you use it.
# 
# - For scripters:
# 
#   The variable $game_system.analyzed includes an array of enemy IDs from 
#   enemies, that were analyzed at least once during a fight. You can use this
#   array to make your own bestiary script working together with this script
#   and let only analyzed enemies be added into the bestiary. You can refer to
#   the global variable $advanced_analyze to check if this script is there.
# 
# 
# Important notes:
# 
#   You MUST configure the part below if you have scripts that use dummy
#   elements! Do NOT give your enemies MORE than 12 elements/status effects of
#   one resistance type (e.g. 13 or more elements, that are absorbed), because
#   they won't be displayed. If you target anyone else than enemies, the skill
#   will analyze all enemies anyway.
# 
# 
# If you find any bugs, please report them here:
# http://www.chaosproject.co.nr
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

# basic configuration

ANALYZE_IDS = [81, 82, 83] # IDs of analyzing skills
ELM_DUMMIES = [] # include EVERY dummy element ID that is used by other scripts
STA_DUMMIES = [] # include EVERY dummy status effect ID that you use
EVASION = 'EVA' # word displayed for Evasion

# set the value below to true to only ADD information of analyzed enemies into
# the bestiary if you use my Bestiary script

$override_bestiary = false

# set this value to true if you want the custom Analyze window information to
# be used in the bestiary as well, this way you use only one information for
# both systems

$override_bestiary_info = false

# enemy IDs from enemies, that can't be analyzed (e.g. bosses)

CANT_ANALYZE = [4] # overrides the IDs below and renders an enemy unanalyzeable

CANT_ANALYZE_BASIC = [3] # HP, SP, EXP, Gold, Item drop + chance
CANT_ANALYZE_STATS = [1] # STR, DEX, INT, AGI
CANT_ANALYZE_EXTSTATS = [1, 3] # ATK, PDEF, MDEF
CANT_ANALYZE_XTRWEAK = [1] # extreme element weakness
CANT_ANALYZE_WEAK = [2] # element weakness
CANT_ANALYZE_RESIST = [2, 3] # element resistance
CANT_ANALYZE_NULLIFY = [2] # element nullification
CANT_ANALYZE_ABSORB = [3] # element absorbtion
CANT_ANALYZE_XTRWEAK_S = [1] # extreme status effect weakness
CANT_ANALYZE_WEAK_S = [2] # status effect weakness
CANT_ANALYZE_RESIST_S = [2, 3] # status effect resistance
CANT_ANALYZE_NULLIFY_S = [2] # status effect nullification
CANT_ANALYZE_ABSORB_S = [3] # status effect absorbtion
CANT_ANALYZE_CUSTOM = [] # custom info

# If a display below is disabled, the appropriate part above will be overriden.
# The values below can also be changed during gameplay by just calling the
# "Call script" event command and changing the values like below
# DO NOT SET EVERYTHING TO true! THIS WILL BUG YOUR ANALYZE SKILL!

# set to true to disable display of basic info
DISABLE_BASIC = false
# set to true to disable display of basic stats
DISABLE_STATS = false
# set to true to disable display of extended stats
DISABLE_EXTSTATS = false
# set to true to disable display of extreme elemental weakness
DISABLE_XTRWEAK = false
# set to true to disable display of elemental weakness
DISABLE_WEAK = false
# set to true to disable display of elemental resistance
DISABLE_RESIST = false
# set to true to disable display of elemental nullification
DISABLE_NULLIFY = false
# set to true to disable display of elemental absorbtion
DISABLE_ABSORB = false
# set to true to disable display of extremeal status effect weakness
DISABLE_XTRWEAK_S = false
# set to true to disable display of status effect weakness
DISABLE_WEAK_S = false
# set to true to disable display of status effect resistance
DISABLE_RESIST_S = false
# set to true to disable display of status effect nullification
DISABLE_NULLIFY_S = false
# set to true to disable display of status effect absorbtion
DISABLE_ABSORB_S = false
# set to false to enable custom display
DISABLE_CUSTOM_ANALYZE = false

#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

if $DUMMY_ELEMENTS == nil
  $DUMMY_ELEMENTS = ELM_DUMMIES.clone
else
  $DUMMY_ELEMENTS |= ELM_DUMMIES
end
ELM_DUMMIES = nil
if $DUMMY_STATES == nil
  $DUMMY_STATES = STA_DUMMIES.clone
else
  $DUMMY_STATES |= STA_DUMMIES
end
STA_DUMMIES = nil

$advanced_analyze = 2.3

#==============================================================================
# Game_System
#==============================================================================

class Game_System
  
  attr_accessor :analyze_mode
  attr_accessor :analyzed
  
  def get_analyze_info(id)
    case id
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Custom Analyze Info Database
# 
# Use following template to add custom information about monsters:
# 
#    when ID then return "STRING"
# 
# ID is the enemy ID and STRING is a string with the information that should be
# displayed. Type all the information into one string, the script will slice
# the text by itself. Note that special characters like a " (double quote)
# need the use of the escape character \ (backslash). If you get and error
# with your string or the character doesn't appear right on the screen, try to
# use the escape character (i.e. for a " it would be \" instead of just ").
# The backslash itself needs an escape character (i.e. \\).
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    when 1 then return "And I thought there were no such things as ghosts..."
    when 2 then return "These creatures are said to be able to have the ability to turn anything they glaze at into stone. If this rumor is true, these creatures can be considered as part of the family of \"Gorgons\"."
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Custom Analyze Info Database
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    end
    return 'Unknown'
  end

  alias init_aas_later initialize
  def initialize
    init_aas_later
    @analyze_mode = 0
    # bestiary support
    @analyzed = []
  end
  
end

#==============================================================================
# Game_Battler
#==============================================================================

class Game_Battler
  
  alias skill_effect_aas_later skill_effect
  def skill_effect(user, skill)
    last_sr = self.sr if $crls && self.is_a?(Game_Actor)
    last_hp = self.hp
    result = skill_effect_aas_later(user, skill)
    if ANALYZE_IDS.include?(skill.id)
      self.damage = nil
      self.sr = last_sr if $crls && self.is_a?(Game_Actor)
      self.hp = last_hp
    end
    return result
  end

end

#==============================================================================
# Bitmap
#==============================================================================

class Bitmap
  
  def slice_text(text, width)
    words = text.split(' ')
    return words if words.size == 1
    result, current_text = [], words.shift
    words.each_index {|i|
        if self.text_size("#{current_text} #{words[i]}").width > width
          result.push(current_text)
          current_text = words[i]
        else
          current_text = "#{current_text} #{words[i]}"
        end
        result.push(current_text) if i >= words.size - 1}
    return result
  end
  
end

#==============================================================================
# Window_Analyze
#==============================================================================

class Window_Analyze < Window_Base

  attr_accessor :mode
  
  def initialize
    super(0, 0, 576, 224)
    @index_enemy = @index_page = 0
    @d = [DISABLE_BASIC, DISABLE_STATS, DISABLE_EXTSTATS, DISABLE_XTRWEAK,
          DISABLE_WEAK, DISABLE_RESIST, DISABLE_NULLIFY, DISABLE_ABSORB,
          DISABLE_XTRWEAK_S, DISABLE_WEAK_S, DISABLE_RESIST_S,
          DISABLE_NULLIFY_S, DISABLE_ABSORB_S, DISABLE_CUSTOM_ANALYZE]
    @pages = 14 - ((0..13).find_all {|i| @d[i]}).size
    @mode = $game_system.analyze_mode
    self.contents = Bitmap.new(width - 32, height - 32)
    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
    self.x, self.y = 320 - self.width / 2, 160 - self.height / 2
    self.visible = self.active = false
    refresh
  end
  
  def update
    if Input.trigger?(Input::RIGHT)
      $game_system.se_play($data_system.cursor_se)
      @index_enemy = (@index_enemy + 1) % @enemies.size
      refresh
    elsif Input.trigger?(Input::LEFT)
      $game_system.se_play($data_system.cursor_se)
      @index_enemy = (@index_enemy + @enemies.size - 1) % @enemies.size
      refresh
    elsif Input.trigger?(Input::DOWN)
      $game_system.se_play($data_system.cursor_se)
      @index_page = (@index_page + 1) % @pages
      refresh
    elsif Input.trigger?(Input::UP)
      $game_system.se_play($data_system.cursor_se)
      @index_page = (@index_page + @pages - 1) % @pages
      refresh
    end
  end
  
  def refresh
    case @mode
    when 0 then self.opacity = self.back_opacity = 255
    when 1 then self.back_opacity = 128
    when 2 then self.opacity = 0
    end
    self.contents.clear
    x = 4
    ox = x + 128
    ax = 100
    bx = ax + 144
    @enemies = []
    $game_troop.enemies.each {|enemy| @enemies.push(enemy) if enemy.exist?}
    @enemies.each {|enemy|
        unless $game_system.analyzed.include?(enemy.id)
          $game_system.analyzed.push(enemy.id)
          $game_system.enable(enemy.id) if $bestiary_enabled
        end}
    $game_system.analyzed.sort!
    enemy = @enemies[@index_enemy]
    w = self.width - self.contents.text_size(enemy.name).width
    name = "#{enemy.name}  #{make_battler_state_text(enemy, w, false)}"
    name = "#{@index_enemy+1}.  #{name}" if @enemies.size > 1
    self.contents.draw_text(0, 0, 544, 32, name, 1)
    unless CANT_ANALYZE.include?(enemy.id)
      case @index_page
      when (0 - ((0..0).find_all {|i| @d[i]}).size)
        if enemy.item_id > 0
          drop = $data_items[enemy.item_id]
          t = "#{drop.name} (#{enemy.treasure_prob}% chance)"
        elsif enemy.weapon_id > 0
          drop = $data_weapons[enemy.weapon_id]
          t = "#{drop.name} (#{enemy.treasure_prob}% chance)"
        elsif enemy.armor_id > 0
          drop = $data_armors[enemy.armor_id]
          t = "#{drop.name} (#{enemy.treasure_prob}% chance)"
        end
        self.contents.draw_text(ax, 32, 128, 32, $data_system.words.hp, 2)
        self.contents.draw_text(ax, 64, 128, 32, $data_system.words.sp, 2)
        self.contents.draw_text(ax, 96, 128, 32, 'EXP', 2)
        self.contents.draw_text(ax, 128, 128, 32, $data_system.words.gold, 2)
        self.contents.draw_text(ax, 160, 128, 32, 'Drops', 2)
        unless CANT_ANALYZE_BASIC.include?(enemy.id)
          self.contents.draw_text(bx, 32, 256, 32, "#{enemy.hp} / #{enemy.maxhp}")
          self.contents.draw_text(bx, 64, 256, 32, "#{enemy.sp} / #{enemy.maxsp}")
          self.contents.draw_text(bx, 96, 256, 32, enemy.exp.to_s)
          self.contents.draw_text(bx, 128, 256, 32, enemy.gold.to_s)
          self.contents.draw_text(bx, 160, 256, 32, (drop != nil ? t : 'nothing'))
        else
          (0...5).each {|i|
              self.contents.draw_text(bx, 32 + i*32, 544, 32, 'Cannot analyze this')}
        end
      when (1 - ((0..1).find_all {|i| @d[i]}).size)
        self.contents.draw_text(ax, 32, 128, 32, $data_system.words.str, 2)
        self.contents.draw_text(ax, 64, 128, 32, $data_system.words.dex, 2)
        self.contents.draw_text(ax, 96, 128, 32, $data_system.words.agi, 2)
        self.contents.draw_text(ax, 128, 128, 32, $data_system.words.int, 2)
        unless CANT_ANALYZE_STATS.include?(enemy.id)
          self.contents.draw_text(bx, 32, 256, 32, enemy.str.to_s)
          self.contents.draw_text(bx, 64, 256, 32, enemy.dex.to_s)
          self.contents.draw_text(bx, 96, 256, 32, enemy.agi.to_s)
          self.contents.draw_text(bx, 128, 256, 32, enemy.int.to_s)
        else
          (0...4).each {|i|
              self.contents.draw_text(bx, 32 + i*32, 544, 32, 'Cannot analyze this')}
        end
      when (2 - ((0..2).find_all {|i| @d[i]}).size)
        self.contents.draw_text(ax, 32, 128, 32, $data_system.words.atk, 2)
        self.contents.draw_text(ax, 64, 128, 32, $data_system.words.pdef, 2)
        self.contents.draw_text(ax, 96, 128, 32, $data_system.words.mdef, 2)
        self.contents.draw_text(ax, 128, 128, 32, EVASION, 2)
        unless CANT_ANALYZE_EXTSTATS.include?(enemy.id)
          self.contents.draw_text(bx, 32, 256, 32, enemy.atk.to_s)
          self.contents.draw_text(bx, 64, 256, 32, enemy.pdef.to_s)
          self.contents.draw_text(bx, 96, 256, 32, enemy.mdef.to_s)
          self.contents.draw_text(bx, 128, 256, 32, enemy.eva.to_s)
        else
          (0...4).each {|i|
              self.contents.draw_text(bx, 32 + i*32, 544, 32, 'Cannot analyze this')}
        end
      when (3 - ((0..3).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Extremely efficient elements:')
        draw_elements(enemy, x, 1, CANT_ANALYZE_XTRWEAK.include?(enemy.id))
      when (4 - ((0..4).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Efficient elements:')
        draw_elements(enemy, x, 2, CANT_ANALYZE_WEAK.include?(enemy.id))
      when (5 - ((0..5).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Elemental resistances:')
        draw_elements(enemy, x, 4, CANT_ANALYZE_RESIST.include?(enemy.id))
      when (6 - ((0..6).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Elemental nullifications:')
        draw_elements(enemy, x, 5, CANT_ANALYZE_NULLIFY.include?(enemy.id))
      when (7 - ((0..7).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Elemental absorbtions:')
        draw_elements(enemy, x, 6, CANT_ANALYZE_ABSORB.include?(enemy.id))
      when (8 - ((0..8).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Extremely efficient status effects:')
        draw_states(enemy, x, 1, CANT_ANALYZE_XTRWEAK_S.include?(enemy.id))
      when (9 - ((0..9).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Efficient status effects:')
        draw_states(enemy, x, 2, CANT_ANALYZE_WEAK_S.include?(enemy.id))
      when (10 - ((0..10).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Status effect resistances:')
        draw_states(enemy, x, 4, CANT_ANALYZE_RESIST_S.include?(enemy.id))
      when (11 - ((0..11).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Strong status effect resistances:')
        draw_states(enemy, x, 5, CANT_ANALYZE_NULLIFY_S.include?(enemy.id))
      when (12 - ((0..12).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Status effect immunities:')
        draw_states(enemy, x, 6, CANT_ANALYZE_ABSORB_S.include?(enemy.id))
      when (13 - ((0..13).find_all {|i| @d[i]}).size)
        self.contents.draw_text(x, 32, 544, 32, 'Information:')
        draw_info(enemy, x, CANT_ANALYZE_CUSTOM.include?(enemy.id))
      end
    else
      self.contents.draw_text(0, 64, 544, 32, 'Cannot analyze this enemy', 1)
    end
  end
  
  def draw_elements(enemy, x, index, check)
    unless check
      elements = []
      (1...$data_system.elements.size).each {|id|
          if !$DUMMY_ELEMENTS.include?(id) &&
              index == $data_enemies[@enemies[@index_enemy].id].element_ranks[id]
            elements.push($data_system.elements[id])
          end}
      elements = ['Nothing'] if elements.size == 0
      elements.each_index {|i|
          self.contents.draw_text(x + i/4*180, 64 + i%4*32, 176, 32, elements[i])}
    else
      self.contents.draw_text(x, 64, 544, 32, 'Cannot analyze this')
    end
  end
    
  def draw_states(enemy, x, index, check)
    unless check
      states = []
      (1...$data_states.size).each {|id|
          if !$DUMMY_STATES.include?(id) &&
              index == $data_enemies[@enemies[@index_enemy].id].state_ranks[id]
            states.push($data_states[id].name)
          end}
      states = ['Nothing'] if states.size == 0
      states.each_index {|i|
          self.contents.draw_text(x + i/4*180, 64 + i%4*32, 176, 32, states[i])}
    else
      self.contents.draw_text(x, 64, 544, 32, 'Cannot analyze this')
    end
  end
    
  def draw_info(enemy, x, check)
    unless check
      text = self.contents.slice_text($game_system.get_analyze_info(enemy.id), 528)
      text.each_index {|i|
          self.contents.draw_text(x, 64 + i*32, 544, 32, text[i])}
    else
      self.contents.draw_text(x, 64, 544, 32, 'Cannot analyze this')
    end
  end
    
end

#==============================================================================
# Scene_Battle
#==============================================================================

class Scene_Battle
  
  
  alias make_skill_action_result_aas_later make_skill_action_result
  def make_skill_action_result
    make_skill_action_result_aas_later
    @analyze_window = Window_Analyze.new if ANALYZE_IDS.include?(@skill.id)
  end
  
  alias update_phase4_step5_aas_later update_phase4_step5
  def update_phase4_step5
    update_phase4_step5_aas_later
    if @analyze_window != nil
      Graphics.freeze
      @analyze_window.visible = true
      Graphics.transition(10)
      loop do
        Graphics.update
        Input.update
        @analyze_window.update
        @spriteset.update
        $game_screen.update
        if Input.trigger?(Input::A) || Input.trigger?(Input::C)
          $game_system.se_play($data_system.cursor_se)
          Graphics.freeze
          case @analyze_window.mode
          when 0 then @analyze_window.back_opacity = 128
          when 1 then @analyze_window.opacity = 0
          when 2 then @analyze_window.opacity = @analyze_window.back_opacity = 255
          end
          $game_system.analyze_mode = ($game_system.analyze_mode+1) % 3
          @analyze_window.mode = $game_system.analyze_mode
          Graphics.transition(5)
        end
        break if Input.trigger?(Input::B)
      end
      Graphics.freeze
      $game_system.se_play($data_system.cancel_se)
      @analyze_window.dispose
      @analyze_window = nil
      Graphics.transition(10)
    end
  end
  
end
