#==============================================================================
# ☆ RGSS2(VX)専用 「変身」ステート&スキル Ver 1.02
#------------------------------------------------------------------------------
# 河原 つつみ
#  連絡先 :『アクマの脳髄』http://www.akunou.com/
#------------------------------------------------------------------------------
#  Original 桜雅 在土 様
#------------------------------------------------------------------------------
#  かつてスクリプトシェルフ様で配布されていた
# 『XRXS27. 特殊効果 SuperEX「変身」』をVX向けに
# 移植&大幅に機能変更/追加したものです。
#  このスクリプトについて、原作者である桜雅 在土 様に問い合わせたり
# しないで下さい。
#
#  ◆主なオリジナルとの相違点
#   変身中、属性修正値とステートの付加成功率は、変身対象のものを
#   参照するようになります。
#   変身中は、自分が元々習得していたスキルは使用できなくなり、
#   変身対象のスキルを使用できるようになります(敵味方問わず)。
#   変身状態をステート化したことで、変身時メッセージや解除条件などを
#   データベース上で自由に設定できます。
#
#  ◆準備
#   変身状態用にステートを一つ用意し、『戦闘終了時に解除』オプションを
#   付けて下さい。
#   『この状態になったときのメッセージ』内に「MN」と入力することで、
#   変身対象の名前を表示できます。
#
#    例 : はMNに変身した!
#    表示: ラルフはスライムに変身した!
#
#   その他の項目はお好みで。
#   また、戦闘不能ステートの『解除するステート』の項で
#   この変身状態用ステートにチェックを入れるのも忘れずに。
#   次に変身用のスキルを用意し、『使用可能時』を『バトルのみ』として
#   『ステート変化』の項で変身状態用ステートを『+』に設定して下さい。
#
#  ◆仕様
#   あくまでもスキルのみです。変身アイテムなどは作れません。
#   変身用スキルは戦闘中専用のスキルです。
#   変身状態は戦闘終了後や戦闘不能時に解除されます。
#   変身中は、変身スキルを再度使用することで変身が解除されます。
#   変身中バトラーが致死ダメージを受けてコラプスエフェクトに移行する直前、
#   バトラーグラフィックが元のものに戻るのは仕様です。
#
#==============================================================================

#==============================================================================
# □ AKUNOU
#------------------------------------------------------------------------------
#  カスタマイズポイント
#==============================================================================

module AKUNOU
  # 『変身』したことにするステートID
  METAMOR_STATE_ID = 17
  # 変身中、変身解除用に変身スキルを習得させるか?
  METAMOR_LEARN_ACTOR = true # アクター側の設定
  METAMOR_LEARN_ENEMY = true # エネミー側の設定
  # 変身解除用の変身スキルのID
  METAMOR_SKILL_ID = 83
  # エネミーがアクターに変身した際のバトラーグラフィック
  ACTOR_BATTLER_NAME = {
  # アクターID => "バトラーグラフィック名"
  # といった感じで記述して下さい
  # 他スクリプト等でアクタースプライトを導入している場合は
  # この設定は必要ありません。以下4行を全てコメントアウト
  # (数値 => の前に『#』を付ける)して下さい
    1 => "Captain",
    2 => "Swordman",
    3 => "Priest",
    4 => "Fanatic"
  }
end

#==============================================================================
# ■ RPG
#==============================================================================

module RPG
  class Skill < UsableItem
    def metamorphose?
      return self.plus_state_set.include?(AKUNOU::METAMOR_STATE_ID)
    end
  end
  class State
    def metamor?
      return (self.id == AKUNOU::METAMOR_STATE_ID)
    end
  end
end

#==============================================================================
# ■ Game_Battler
#==============================================================================

class Game_Battler
  #--------------------------------------------------------------------------
  # ● 公開インスタンス変数
  #--------------------------------------------------------------------------
  attr_accessor :battler_name             # バトラーグラフィック
  attr_accessor :battler_hue              # バトラー色調
  attr_accessor :metamor_target           # 変身対象
  attr_reader   :battler_name_original    # バトラーグラフィック初期値
  attr_reader   :battler_hue_original     # バトラー色調初期値
  #--------------------------------------------------------------------------
  # ● 変身ターゲットの初期化
  #--------------------------------------------------------------------------
  def clear_metamor
    @metamor_target = nil
    @battler_name_original = self.actor? ? body_name : @battler_name
    @battler_hue_original  = @battler_hue
  end
  #--------------------------------------------------------------------------
  # ● MaxHP の取得
  #--------------------------------------------------------------------------
  alias akunou2_maxhp maxhp
  def maxhp(original = false)
    return @metamor_target.maxhp(true) if metamor_check(original)
    akunou2_maxhp
  end
  #--------------------------------------------------------------------------
  # ● MaxMP の取得
  #--------------------------------------------------------------------------
  alias akunou2_maxmp maxmp
  def maxmp(original = false)
    return @metamor_target.maxmp(true) if metamor_check(original)
    akunou2_maxmp
  end
  #--------------------------------------------------------------------------
  # ● 攻撃力の取得
  #--------------------------------------------------------------------------
  alias akunou2_atk atk
  def atk(original = false)
    return @metamor_target.atk(true) if metamor_check(original)
    akunou2_atk
  end
  #--------------------------------------------------------------------------
  # ● 防御力の取得
  #--------------------------------------------------------------------------
  alias akunou2_def def
  def def(original = false)
    return @metamor_target.def(true) if metamor_check(original)
    akunou2_def
  end
  #--------------------------------------------------------------------------
  # ● 精神力の取得
  #--------------------------------------------------------------------------
  alias akunou2_spi spi
  def spi(original = false)
    return @metamor_target.spi(true) if metamor_check(original)
    akunou2_spi
  end
  #--------------------------------------------------------------------------
  # ● 敏捷性の取得
  #--------------------------------------------------------------------------
  alias akunou2_agi agi
  def agi(original = false)
    return @metamor_target.agi(true) if metamor_check(original)
    akunou2_agi
  end
  #--------------------------------------------------------------------------
  # ● ステートの解除
  #     state_id : ステート ID
  #--------------------------------------------------------------------------
  alias akunou2_remove_state remove_state
  def remove_state(state_id)
    if $data_states[state_id].metamor?
      return unless state?(state_id)        # このステートが付加されていない?
      if state_id == 1 and @hp == 0         # 戦闘不能 (ステート 1 番) なら
        @hp = 1                             # HP を 1 に変更する
      end
      @battler_name = @battler_name_original
      @battler_hue  = @battler_hue_original
      @metamor_target = nil
      # HP/MP最大値変更への対応
      self.hp = self.hp
      self.mp = self.mp
      @states.delete(state_id)              # ID を @states 配列から削除
      @state_turns.delete(state_id)         # ターン数記憶用ハッシュから削除
    else
      # 呼び戻す
      akunou2_remove_state(state_id)
    end
  end
  #--------------------------------------------------------------------------
  # ● スキルの効果適用
  #     user  : スキルの使用者
  #     skill : スキル
  #--------------------------------------------------------------------------
  alias akunou2_skill_effect skill_effect
  def skill_effect(user, skill, target = nil)
    akunou2_skill_effect(user, skill)
    metamor_effect(target) if skill.metamorphose?
  end
  #--------------------------------------------------------------------------
  # ○ 変身のチェック
  #--------------------------------------------------------------------------
  def metamor_check(original)
    if !@metamor_target.nil? and @metamor_target != self and original == false
      return true
    end
    return false
  end
  #--------------------------------------------------------------------------
  # ○ 変身の効果適用
  #--------------------------------------------------------------------------
  def metamor_effect(target)
    return if !state?(AKUNOU::METAMOR_STATE_ID)
    reverse = false
    if target != nil and @metamor_target == nil
      if target.metamor_target == nil
        if target == self
          reverse = true
        else
          # 変身状態で無い場合、変身
          @metamor_target = target
        end
      else
        if target.metamor_target == self
          reverse = true
        else
          # 対象が変身状態の場合、対象の変身対象に変身する。
          @metamor_target = target.metamor_target
        end
      end
    else
      reverse = true
      remove = true if target != nil
    end
    if reverse
      # 変身状態の場合、変身を解除する
      remove_state(AKUNOU::METAMOR_STATE_ID)
      # 解除したステートを記録する
      if remove or (target != self and target.metamor_target != self)
        @removed_states.push(AKUNOU::METAMOR_STATE_ID)
      end
      @added_states.delete(AKUNOU::METAMOR_STATE_ID)
    else
      metamor_actions_setup if !actor?
    end
    # HP/MP最大値変更への対応
    self.hp = self.hp
    self.mp = self.mp
  end
end

#==============================================================================
# ■ Game_Actor
#==============================================================================

class Game_Actor < Game_Battler
  #--------------------------------------------------------------------------
  # ● セットアップ
  #     actor_id : アクター ID
  #--------------------------------------------------------------------------
  alias akunou2_setup setup
  def setup(actor_id)
    akunou2_setup(actor_id)
    clear_metamor
    recover_all
  end
  #--------------------------------------------------------------------------
  # ◎ 属性修正値の取得
  #     element_id : 属性 ID
  #--------------------------------------------------------------------------
  def element_rate(element_id)
    if !@metamor_target.nil? and @metamor_target != self
      if @metamor_target.actor?
        rank = @metamor_target.class.element_ranks[element_id]
      else
        rank = @metamor_target.enemy.element_ranks[element_id]
      end
    else
      rank = self.class.element_ranks[element_id]
    end
    result = [0,200,150,100,50,0,-100][rank]
    for armor in armors.compact
      result /= 2 if armor.element_set.include?(element_id)
    end
    for state in states
      result /= 2 if state.element_set.include?(element_id)
    end
    return result
  end
  #--------------------------------------------------------------------------
  # ● ステートの付加成功率の取得
  #     state_id : ステート ID
  #--------------------------------------------------------------------------
  alias akunou2_state_probability state_probability
  def state_probability(state_id, original = false)
    return @metamor_target.state_probability(state_id, true) if metamor_check(original)
    akunou2_state_probability(state_id)
  end
  #--------------------------------------------------------------------------
  # ● 命中率の取得
  #--------------------------------------------------------------------------
  alias akunou2_hit hit
  def hit(original = false)
    return @metamor_target.hit(true) if metamor_check(original)
    akunou2_hit
  end
  #--------------------------------------------------------------------------
  # ● 回避率の取得
  #--------------------------------------------------------------------------
  alias akunou2_eva eva
  def eva(original = false)
    return @metamor_target.eva(true) if metamor_check(original)
    akunou2_eva
  end
  #--------------------------------------------------------------------------
  # ● クリティカル率の取得
  #--------------------------------------------------------------------------
  alias akunou2_cri cri
  def cri(original = false)
    return @metamor_target.cri(true) if metamor_check(original)
    akunou2_cri
  end
  #--------------------------------------------------------------------------
  # ◎ スキルの使用可能判定
  #     skill : スキル
  #--------------------------------------------------------------------------
  def skill_can_use?(skill)
    return super
  end
  #--------------------------------------------------------------------------
  # ○ アクターに変身用のグラフィック
  #--------------------------------------------------------------------------
  def body_name
    if AKUNOU::ACTOR_BATTLER_NAME[self.id] != nil
      return AKUNOU::ACTOR_BATTLER_NAME[self.id]
    end
    return @battler_name
  end
end

#==============================================================================
# ■ Game_Enemy
#==============================================================================

class Game_Enemy < Game_Battler
  #--------------------------------------------------------------------------
  # ● オブジェクト初期化
  #     index    : 敵グループ内インデックス
  #     enemy_id : 敵キャラ ID
  #--------------------------------------------------------------------------
  alias akunou2_initialize initialize
  def initialize(index, enemy_id)
    akunou2_initialize(index, enemy_id)
    @metamor_actions = enemy.actions
    clear_metamor
  end
  #--------------------------------------------------------------------------
  # ● 命中率の取得
  #--------------------------------------------------------------------------
  alias akunou2_hit hit
  def hit(original = false)
    return @metamor_target.hit(true) if metamor_check(original)
    akunou2_hit
  end
  #--------------------------------------------------------------------------
  # ● 回避率の取得
  #--------------------------------------------------------------------------
  alias akunou2_eva eva
  def eva(original = false)
    return @metamor_target.eva(true) if metamor_check(original)
    akunou2_eva
  end
  #--------------------------------------------------------------------------
  # ● クリティカル率の取得
  #--------------------------------------------------------------------------
  alias akunou2_cri cri
  def cri(original = false)
    return @metamor_target.cri(true) if metamor_check(original)
    akunou2_cri
  end
  #--------------------------------------------------------------------------
  # ◎ 属性修正値の取得
  #     element_id : 属性 ID
  #--------------------------------------------------------------------------
  def element_rate(element_id)
    if !@metamor_target.nil? and @metamor_target != self
      if @metamor_target.actor?
        rank = @metamor_target.class.element_ranks[element_id]
      else
        rank = @metamor_target.enemy.element_ranks[element_id]
      end
    else
      rank = enemy.element_ranks[element_id]
    end
    result = [0,200,150,100,50,0,-100][rank]
    for state in states
      result /= 2 if state.element_set.include?(element_id)
    end
    return result
  end
  #--------------------------------------------------------------------------
  # ● ステートの付加成功率の取得
  #     state_id : ステート ID
  #--------------------------------------------------------------------------
  alias akunou2_state_probability state_probability
  def state_probability(state_id, original = false)
    return @metamor_target.state_probability(state_id, true) if metamor_check(original)
    akunou2_state_probability(state_id)
  end
  #--------------------------------------------------------------------------
  # ● 変身
  #     enemy_id : 変身先の敵キャラ ID
  #--------------------------------------------------------------------------
  alias akunou2_transform transform
  def transform(enemy_id)
    akunou2_transform(enemy_id)
    @battler_name_original = @battler_name
    @battler_hue_original  = @battler_hue
  end
  #--------------------------------------------------------------------------
  # ○ 行動の配列
  #--------------------------------------------------------------------------
  def enemy_actions(original = false)
    if metamor_check(original)
      if @metamor_target.actor?
        return @metamor_actions
      else        
        if AKUNOU::METAMOR_LEARN_ENEMY
          actions = @metamor_target.enemy.actions.clone
          for action in actions
            return actions if action.skill_id == (AKUNOU::METAMOR_SKILL_ID)
          end
          actions.push(RPG::Enemy::Action.new)
          actions[actions.size - 1].kind = 1
          actions[actions.size - 1].skill_id = (AKUNOU::METAMOR_SKILL_ID)
          return actions
        else
          return @metamor_target.enemy.actions
        end
      end
    end
    return enemy.actions
  end
  #--------------------------------------------------------------------------
  # ○ 変身によるアクション生成
  #--------------------------------------------------------------------------
  def metamor_actions_setup
    return if @metamor_target.nil? or !@metamor_target.actor?
    target_skills = []
    size = [[0, @metamor_target.skills.size].max, 5].min
    if @metamor_target.skills.size > size
      while target_skills.size < size      
        target_skills.push(@metamor_target.skills[rand(@metamor_target.skills.size)].id)
        target_skills.compact!
        target_skills.uniq!
      end
    else
      for i in 0...size
        target_skills.push(@metamor_target.skills[i].id)
      end
    end
    target_skills.push(AKUNOU::METAMOR_SKILL_ID) if AKUNOU::METAMOR_LEARN_ENEMY
    target_skills.uniq!
    @metamor_actions = []
    for i in 0..target_skills.size
      @metamor_actions.push(RPG::Enemy::Action.new)
      if i > 0
        @metamor_actions[i].kind = 1
        @metamor_actions[i].skill_id = target_skills[i - 1]
      end
    end
  end
  #--------------------------------------------------------------------------
  # ◎ 戦闘行動の作成
  #--------------------------------------------------------------------------
  def make_action
    @action.clear
    return unless movable?
    available_actions = []
    rating_max = 0
    for action in enemy_actions
      next unless conditions_met?(action)
      if action.kind == 1
        next unless skill_can_use?($data_skills[action.skill_id])
      end
      available_actions.push(action)
      rating_max = [rating_max, action.rating].max
    end
    ratings_total = 0
    rating_zero = rating_max - 3
    for action in available_actions
      next if action.rating <= rating_zero
      ratings_total += action.rating - rating_zero
    end
    return if ratings_total == 0
    value = rand(ratings_total)
    for action in available_actions
      next if action.rating <= rating_zero
      if value < action.rating - rating_zero
        @action.kind = action.kind
        @action.basic = action.basic
        @action.skill_id = action.skill_id
        @action.decide_random_target
        return
      else
        value -= action.rating - rating_zero
      end
    end
  end
end

#==============================================================================
# ■ Window_Skill
#------------------------------------------------------------------------------
#  スキル画面などで、使用できるスキルの一覧を表示するウィンドウです。
#==============================================================================

class Window_Skill < Window_Selectable
  #--------------------------------------------------------------------------
  # ◎ リフレッシュ
  #--------------------------------------------------------------------------
  def refresh
    @data = []
    if @actor.metamor_target.nil?
      skills = @actor.skills
    else
      if @actor.metamor_target.actor?
        skills = @actor.metamor_target.skills
      else
        skills = []
        for action in @actor.metamor_target.enemy_actions(true)
          skills.push($data_skills[action.skill_id]) if action.skill?
        end
      end
      skills.push($data_skills[AKUNOU::METAMOR_SKILL_ID]) if AKUNOU::METAMOR_LEARN_ACTOR
      skills.uniq!
    end
    for skill in skills
      @data.push(skill)
      if skill.id == @actor.last_skill_id
        self.index = @data.size - 1
      end
    end
    @item_max = @data.size
    create_contents
    for i in 0...@item_max
      draw_item(i)
    end
  end
end

#==============================================================================
# ■ Scene_Battle
#------------------------------------------------------------------------------
#  バトル画面の処理を行うクラスです。
#==============================================================================

class Scene_Battle < Scene_Base
  #--------------------------------------------------------------------------
  # ● 戦闘行動の実行 : スキル
  #--------------------------------------------------------------------------
  alias akunou2_execute_action_skill execute_action_skill
  def execute_action_skill
    skill = @active_battler.action.skill
    if skill.metamorphose?      
      text = @active_battler.name + skill.message1
      @message_window.add_instant_text(text)
      unless skill.message2.empty?
        wait(10)
        @message_window.add_instant_text(skill.message2)
      end
      targets = [@active_battler]
      sub_target = @active_battler.action.make_targets[0]
      display_animation(targets, skill.animation_id)
      @active_battler.mp -= @active_battler.calc_mp_cost(skill)
      $game_temp.common_event_id = skill.common_event_id
      for target in targets
        target.skill_effect(@active_battler, skill, sub_target)
        display_action_effects(target, skill)
      end
    else
      # 呼び戻す
      akunou2_execute_action_skill
    end
  end
  #--------------------------------------------------------------------------
  # ◎ 付加されたステートの表示
  #     target : 対象者
  #     obj    : スキルまたはアイテム
  #--------------------------------------------------------------------------
  def display_added_states(target, obj = nil)
    for state in target.added_states
      if target.actor?
        next if state.message1.empty?
        message1 = state.message1.dup
        if state.metamor?
          message1.gsub!("MN") { @active_battler.metamor_target.name }
        end
        text = target.name + message1
      else
        next if state.message2.empty?
        message2 = state.message2.dup
        if state.metamor?
          message2.gsub!("MN") { @active_battler.metamor_target.name }
        end
        text = target.name + message2
      end
      if state.metamor?
        if @active_battler.metamor_target.actor?
          @active_battler.battler_name = @active_battler.metamor_target.body_name
        else
          @active_battler.battler_name = @active_battler.metamor_target.battler_name
        end
        @active_battler.battler_hue  = @active_battler.metamor_target.battler_hue
      end
      if state.id == 1                      # 戦闘不能
        target.perform_collapse
      end
      @message_window.replace_instant_text(text)
      wait(20)
    end
  end
end