解決済み)反撃スキル

faida
記事: 272
登録日時: 2015年12月17日(木) 16:44

Re: 解決済み)反撃スキル

投稿記事by faida » 2022年10月26日(水) 22:42

こんばんは。

反撃が全体/ランダムのケースがあり、そのターゲット指定のために使用していた方式が原因でした。
ただ、これはこれで需要が万に一つあったら困るので、設定項目という形でご用意しました。
一応デフォルトのtrueの状態で空振りとなるはずなので、お試しください。

コード: 全て選択

=begin
◆概要
特殊な反撃を作成します。

◆機能
・メモ欄に<通常反撃 a, b, c, ..., n%>と記入すると、n%の確率で敵の物理攻撃を
キャンセルし、a, b, c, ...のスキルのどれかを発動します。
上記仕様に伴い、デフォルトの反撃率の設定は<通常反撃 1 n%>とほぼ同じになります。
・メモ欄に<攻撃前反撃 a, b, c, ..., n%>と記入すると、敵の行動前にn%の確率で
a, b, c, ...のスキルのどれかを発動します。
・メモ欄に<攻撃後反撃 a, b, c, ..., n%>と記入すると、敵の攻撃後にn%の確率で
a, b, c, ...のスキルのどれかを発動します。
・メモ欄に<回避反撃 a, b, c, ..., n%>と記入すると、敵の攻撃回避後にn%の確率で
a, b, c, ...のスキルのどれかを発動します。
・a, b, c, ...を負にするとアイテムになります。
例:<攻撃後反撃 1, 50%> やられたらやり返すかもしれない
  <攻撃前反撃 2, 50%> やられる前に身を守るかもしれない
  <攻撃後反撃 -1, -2, -3, 100%> オートポーション
・メモ欄に<条件付反撃 str>と記入すると、「直後に」設定した反撃は
strを満たす場合のみ発動します。strは条件式を入れます。
・メモ欄に<全条件付反撃 str>と記入すると、「以降、このメモ欄に」設定した反撃は全て
strを満たす場合のみ発動します。strは条件式を入れます。
例:敵の攻撃力が自分の攻撃力より上→user.atk > self.atk
   ID3の属性攻撃に対しての反撃→item.damage.element_id == 3
   「この」スキルを指定する場合の例→s.tp_cost <= self.tp / 2
   適当に設定項目作れば簡略化も可→eval(FAI_CNT_EX::CND_CNT_LIST[1])
・メモ欄に<反撃不可>と記入すると、そのバトラーが行う攻撃に対して一切の反撃が
できなくなります。これはスキル系・ステート系のどちらでも有効です。
・メモ欄に<反撃不可 :normal>と記入すると、通常の反撃ができなくなります。
・メモ欄に<反撃不可 :attack>と記入すると、ダメージを与える反撃ができなくなり
ます。これらと以下のスクリプトでだいたい察してください。

◆仕様
・攻撃前って書いてるけど攻撃じゃなくても反応します。
・味方には反撃しません。
・デフォルトの反撃率の設定は<通常反撃 1 n%>と同じですが、他の反撃率とは違い
反撃率設定が複数ある場合は<通常反撃 1 n%>のn%が上昇するのみです。
また、別のスクリプトで通常攻撃スキルが変更されている場合、デフォルトの反撃も
通常攻撃スキルを発動します。
例:<通常反撃 1 20%>を持つ武具を3つ装備すると、この発動率は理論上
   100 - (100-20) ^ 3 = 48.8 %となりますが、
   デフォルトの反撃率20%を持つ武具を3つ装備すると、この発動率は理論も何もなく
   20 * 3 = 60 % となります。
・<全条件付反撃 str>を設定中に<条件付反撃 str>を設定すると、直後の反撃のみ
<条件付反撃 str>が適用されます。それ以外は<全条件付反撃 str>が適用されます。

◆使用上の注意
・★……エイリアス ●……再定義 ○……新規定義

◆作者:faida @faida3983

◆更新履歴
ver1.0 : 公開
ver2.0 : 全体的に構造を見直したので一気にバージョンが上がりました。
ver2.1 : 反撃が敵単体対象の場合は行動した敵にのみ反撃する設定項目を追加しました。

=end

module FAI_CNT_EX
  # 設定項目:反撃が敵単体対象の場合は、行動した敵にのみ反撃する
  # ランダムや全体の場合はその制約はありません。
  ONLY_SUBJECT_CNT_FOR_ONE = true
 
  # 設定項目:魔法とか必中攻撃とかでも反撃する
  # 普通の反撃は魔法とか必中攻撃とかでは反撃できません。
  BEF_CNT_FOR_CERT = true
  HIT_CNT_FOR_CERT = true
  EVA_CNT_FOR_CERT = false
  BEF_CNT_FOR_MAG = true
  HIT_CNT_FOR_MAG = true
  EVA_CNT_FOR_MAG = false
 
  NOT_CNT_TYPE = {}
  NOT_CNT_TYPE[:all] = [[:normal, :before, :hit, :evade], []]
  NOT_CNT_TYPE[:normal] = [[:normal], []]
  NOT_CNT_TYPE[:before] = [[:before], []]
  NOT_CNT_TYPE[:hit] = [[:hit], []]
  NOT_CNT_TYPE[:evade] = [[:evade], []]
  NOT_CNT_TYPE[:attack] = [[:normal, :before, :hit, :evade],
    ["s.for_opponent?"]]
  NOT_CNT_TYPE[:defence] = [[:normal, :before, :hit, :evade],
    ["s.for_friend?"]]
 
  CND_CNT_LIST = []
  CND_CNT_LIST[0] = "[3,4,5,6,7,8,9,10].include?(item.damage.element_id)"
 
  CND_CNT = /<条件付反撃\s*(.+)>/
  ACND_CNT = /<全条件付反撃\s*(.+)>/
  NOR_CNT = /<通常反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  BEF_CNT = /<攻撃前反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  HIT_CNT = /<攻撃後反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  EVA_CNT = /<回避反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  NOT_CNT = /<反撃不可\s*(?:\:(.+))*>/
  NOR_CNT_PLUS = /<通常反撃率\s*([\+\-]?\d+)[%%]>/
  BEF_CNT_PLUS = /<攻撃前反撃率\s*([\+\-]?\d+)[%%]>/
  HIT_CNT_PLUS = /<攻撃後反撃率\s*([\+\-]?\d+)[%%]>/
  EVA_CNT_PLUS = /<回避反撃率\s*([\+\-]?\d+)[%%]>/
end

class RPG::BaseItem
  #--------------------------------------------------------------------------
  # ○ メモ取得
  #--------------------------------------------------------------------------
  def fai_cnt_ex_note
    @normal_counter = []
    @before_counter = []
    @hit_counter = []
    @evade_counter = []
    @forbid_counter = []
    @_condition_counter = nil
    @_condition_counter_all = nil
    note.each_line{|line|
      case line
      when FAI_CNT_EX::CND_CNT
        next @_condition_counter = $1
      when FAI_CNT_EX::ACND_CNT
        @_condition_counter_all = $1
      when FAI_CNT_EX::NOR_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @normal_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::BEF_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @before_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::HIT_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @hit_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::EVA_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @evade_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::NOT_CNT
        @forbid_counter <<  ($1 || "all").to_sym
      when FAI_CNT_EX::NOR_CNT_PLUS
        @normal_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      when FAI_CNT_EX::BEF_CNT_PLUS
        @before_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      when FAI_CNT_EX::HIT_CNT_PLUS
        @hit_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      when FAI_CNT_EX::EVA_CNT_PLUS
        @evade_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      end
      @_condition_counter = nil
    }
    @_condition_counter_all = nil
  end
  def fai_cnt_note_ex_cnd
    if @_condition_counter; @_condition_counter
    elsif @_condition_counter_all; @_condition_counter_all
    else; "true"
    end
  end
  def fai_cnt_note_ex_arr(skill_id, rate)
    [skill_id, rate / 100.0, fai_cnt_note_ex_cnd]
  end
  #--------------------------------------------------------------------------
  # ○ パラメータ
  #--------------------------------------------------------------------------
  def normal_counter
    fai_cnt_ex_note if !@normal_counter
    @normal_counter
  end
  def before_counter
    fai_cnt_ex_note if !@before_counter
    @before_counter
  end
  def hit_counter
    fai_cnt_ex_note if !@hit_counter
    @hit_counter
  end
  def evade_counter
    fai_cnt_ex_note if !@evade_counter
    @evade_counter
  end
  def forbid_counter
    fai_cnt_ex_note if !@forbid_counter
    @forbid_counter
  end
end

#==============================================================================
# ■ Game_BattlerBase
#==============================================================================

class Game_BattlerBase
  #--------------------------------------------------------------------------
  # ○ パラメータ
  #--------------------------------------------------------------------------
  def normal_counter
    arr = cnt > 0 ? [[[attack_skill_id], cnt, "true"]] : []
    arr + feature_objects.collect{|a|a.normal_counter}.flatten(1)
  end
  def ncr # normal_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.normal_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def before_counter
    feature_objects.collect{|a|a.before_counter}.flatten(1)
  end
  def bcr # before_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.before_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def hit_counter
    feature_objects.collect{|a|a.hit_counter}.flatten(1)
  end
  def hcr # hit_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.hit_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def evade_counter
    feature_objects.collect{|a|a.evade_counter}.flatten(1)
  end
  def ecr # evade_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.evade_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def forbid_counter(item)
    (feature_objects+[item]).inject([]){|r, a| r | a.forbid_counter }
  end
  #--------------------------------------------------------------------------
  # ○ IDからオブジェクトを取得
  #--------------------------------------------------------------------------
  def use_cnt_item(id)
    id >= 0 ? $data_skills[id] : $data_items[-id]
  end
end

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

class Game_Battler < Game_BattlerBase
  attr_reader :set_counter_skills
  #--------------------------------------------------------------------------
  # ○ 反撃可能かチェック
  #--------------------------------------------------------------------------
  def counterable?(type, user, item, cnt_skill_id, str)
    s = use_cnt_item(cnt_skill_id)
    return false if !usable?(s) || !eval(str)
    user.forbid_counter(item).each{|symbol|
      cond = FAI_CNT_EX::NOT_CNT_TYPE[symbol]
      return false if cond[0].include?(type) && (cond[1].empty? ||
      cond[1].any?{|st|eval(st)})
    }
  end
  #--------------------------------------------------------------------------
  # ★ スキル/アイテムの反撃率計算
  #--------------------------------------------------------------------------
  alias fai_cnt_ex_item_cnt item_cnt
  def item_cnt(user, item)
    @set_counter_skills = nil
    return 0 unless opposite?(user) && item.physical?
    ids = (normal_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:normal, user, item, i, arr[2])} && arr[1] + bcr >= rand
      } || [0]
    )[0]
    @set_counter_skills = ids == 0 ? nil : ids
    return @set_counter_skills ? 1.0 : 0.0
    fai_cnt_ex_item_cnt(user, item)
  end
  #--------------------------------------------------------------------------
  # ○ 反撃スキルとか確率とか
  #--------------------------------------------------------------------------
  def item_bef_cnt(user, item)
    return nil if !opposite?(user)
    return nil if !FAI_CNT_EX::BEF_CNT_FOR_CERT && item.certain?
    return nil if !FAI_CNT_EX::BEF_CNT_FOR_MAG && item.magical?
    (before_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:before, user, item, i, arr[2])} && arr[1] + bcr >= rand
      } || [0]
    )[0]
  end
  def item_hit_cnt(user, item)
    return nil if !@result.hit? || !opposite?(user)
    return nil if !FAI_CNT_EX::HIT_CNT_FOR_CERT && item.certain?
    return nil if !FAI_CNT_EX::HIT_CNT_FOR_MAG && item.magical?
    (hit_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:hit, user, item, i, arr[2])} && arr[1] + hcr >= rand
      } || [0]
    )[0]
  end
  def item_eva_cnt(user, item)
    return nil if !@result.evaded || !opposite?(user)
    return nil if !FAI_CNT_EX::EVA_CNT_FOR_CERT && item.certain?
    return nil if !FAI_CNT_EX::EVA_CNT_FOR_MAG && item.magical?
    (evade_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:evade, user, item, i, arr[2])} && arr[1] + ecr >= rand
      } || [0]
    )[0]
  end
end

#==============================================================================
# ■ Scene_Battle
#==============================================================================

class Scene_Battle < Scene_Base
  #--------------------------------------------------------------------------
  # ★ スキル/アイテムの効果を適用
  #--------------------------------------------------------------------------
  alias fai_cnt_ex_apply_item_effects apply_item_effects
  def apply_item_effects(target, item)
    process_counter_ex(target, target.item_bef_cnt(@subject, item))
    fai_cnt_ex_apply_item_effects(target, item)
    process_counter_ex(target, target.item_hit_cnt(@subject, item))
    process_counter_ex(target, target.item_eva_cnt(@subject, item))
  end
  #--------------------------------------------------------------------------
  # 〇 特殊反撃の共通処理
  #--------------------------------------------------------------------------
  def process_counter_ex(target, arr)
    return if !arr || arr == 0
    id = arr.find{|i|target.usable?(target.use_cnt_item(i))}
    return if !id || id == 0
    item = target.use_cnt_item(id)
    action = Game_Action.new(target)
    item.is_a?(RPG::Item) ? action.set_item(item.id) : action.set_skill(item.id)
    if item.need_selection?
      action.target_index = item.for_friend? ? target.index : @subject.index
    end
    ts = action.make_targets.compact
    if FAI_CNT_EX::ONLY_SUBJECT_CNT_FOR_ONE && item.need_selection?
      ts = (item.for_friend? ? [target] : [@subject]) * ts.size
    end
    if id == target.attack_skill_id
      @log_window.display_counter(target, item)
    else
      @log_window.display_use_item(target, item)
      subject, @subject = @subject, target
      show_animation(ts, item.animation_id)
      @subject = subject
    end
    target.use_item(item)
    refresh_status
    ts.each{|t|
      item.repeats.times {
        t.item_apply(target, item)
        refresh_status
        @log_window.display_action_results(t, item)
      }
    }
  end
  #--------------------------------------------------------------------------
  # ● 反撃の発動
  #--------------------------------------------------------------------------
  def invoke_counter_attack(target, item)
    process_counter_ex(target, target.set_counter_skills)
  end
end

------------------------------------------------------------------
自作の(改造でない)スクリプト、プラグイン素材に
関しては、リードミーもしくは作中に
「faida」と記名していただければ
利用可能です。
土曜日
記事: 21
登録日時: 2017年11月18日(土) 19:22

Re: 解決済み)反撃スキル

投稿記事by 土曜日 » 2022年10月29日(土) 23:30

ありがとうございます。
希望通りに設定することができました。
遅まきな要望にも関わらずご対応いただき誠に感謝いたします。
土曜日
記事: 21
登録日時: 2017年11月18日(土) 19:22

Re: 解決済み)反撃スキル

投稿記事by 土曜日 » 2022年11月26日(土) 17:38

たびたび恐れ入ります。
前回とは違ったケースで困った事態が起こりました。

反撃として使用するスキルが「使用者」対象だった場合で
反撃状態にあるアクター・エネミーが混乱などの「敵か味方を攻撃する」行動制約だった場合。
反撃条件で指定した条件を満たし反撃を発動すると「なぜか敵側の方を対象にスキルを発動してしまう」事態が起こる模様です。

具体的に説明しますと、「通常物理攻撃をくらったら自身の攻撃力が5ターン強化される」というスキルを、反撃条件で設定しておくとします。
通常なら、敵から通常攻撃を受けると、ダメージ計算のあとで、その被弾者の攻撃力が強化されます。
しかし、この反撃持ちの者が混乱中の場合、通常攻撃を受けると、攻撃してきた相手の方の攻撃力が強化されてしまいます。

混乱時、行動制約のところの設定に何かヒントがあるとは思うのですが、もしよければこちらの対応は可能でしょうか?
faida
記事: 272
登録日時: 2015年12月17日(木) 16:44

Re: 解決済み)反撃スキル

投稿記事by faida » 2022年12月11日(日) 10:33

大変遅くなりました。申し訳ございません。

ご指摘の通り混乱時の制約のところに原因がありましたが、
「でも混乱しているんだから反撃しようとしてへんなターゲットに投げるのは正常では?」という
偏見と、普通の反撃のターゲットの調査に時間がかかりました。
よく考えたら普通の反撃のターゲットは混乱かどうかにかかわらず攻撃してきた相手に反撃しますね。

というわけでその点について修正しました。
他のスクリプトでmake_targetsをエイリアス等していなければ不具合は出ないはずです。
(もし、そういうスクリプトを使用しておられるのであれば、また考えます。)

あと前のバージョンのほうがいいという方のために前のものはそのまま残しておきます。

コード: 全て選択

=begin
◆概要
特殊な反撃を作成します。

◆機能
・メモ欄に<通常反撃 a, b, c, ..., n%>と記入すると、n%の確率で敵の物理攻撃を
キャンセルし、a, b, c, ...のスキルのどれかを発動します。
上記仕様に伴い、デフォルトの反撃率の設定は<通常反撃 1 n%>とほぼ同じになります。
・メモ欄に<攻撃前反撃 a, b, c, ..., n%>と記入すると、敵の行動前にn%の確率で
a, b, c, ...のスキルのどれかを発動します。
・メモ欄に<攻撃後反撃 a, b, c, ..., n%>と記入すると、敵の攻撃後にn%の確率で
a, b, c, ...のスキルのどれかを発動します。
・メモ欄に<回避反撃 a, b, c, ..., n%>と記入すると、敵の攻撃回避後にn%の確率で
a, b, c, ...のスキルのどれかを発動します。
・a, b, c, ...を負にするとアイテムになります。
例:<攻撃後反撃 1, 50%> やられたらやり返すかもしれない
  <攻撃前反撃 2, 50%> やられる前に身を守るかもしれない
  <攻撃後反撃 -1, -2, -3, 100%> オートポーション
・メモ欄に<条件付反撃 str>と記入すると、「直後に」設定した反撃は
strを満たす場合のみ発動します。strは条件式を入れます。
・メモ欄に<全条件付反撃 str>と記入すると、「以降、このメモ欄に」設定した反撃は全て
strを満たす場合のみ発動します。strは条件式を入れます。
例:敵の攻撃力が自分の攻撃力より上→user.atk > self.atk
   ID3の属性攻撃に対しての反撃→item.damage.element_id == 3
   「この」スキルを指定する場合の例→s.tp_cost <= self.tp / 2
   適当に設定項目作れば簡略化も可→eval(FAI_CNT_EX::CND_CNT_LIST[1])
・メモ欄に<反撃不可>と記入すると、そのバトラーが行う攻撃に対して一切の反撃が
できなくなります。これはスキル系・ステート系のどちらでも有効です。
・メモ欄に<反撃不可 :normal>と記入すると、通常の反撃ができなくなります。
・メモ欄に<反撃不可 :attack>と記入すると、ダメージを与える反撃ができなくなり
ます。これらと以下のスクリプトでだいたい察してください。

◆仕様
・攻撃前って書いてるけど攻撃じゃなくても反応します。
・味方には反撃しません。
・混乱時でも正常なターゲットに反撃します。
・デフォルトの反撃率の設定は<通常反撃 1 n%>と同じですが、他の反撃率とは違い
反撃率設定が複数ある場合は<通常反撃 1 n%>のn%が上昇するのみです。
また、別のスクリプトで通常攻撃スキルが変更されている場合、デフォルトの反撃も
通常攻撃スキルを発動します。
例:<通常反撃 1 20%>を持つ武具を3つ装備すると、この発動率は理論上
   100 - (100-20) ^ 3 = 48.8 %となりますが、
   デフォルトの反撃率20%を持つ武具を3つ装備すると、この発動率は理論も何もなく
   20 * 3 = 60 % となります。
・<全条件付反撃 str>を設定中に<条件付反撃 str>を設定すると、直後の反撃のみ
<条件付反撃 str>が適用されます。それ以外は<全条件付反撃 str>が適用されます。

◆使用上の注意
・★……エイリアス ●……再定義 ○……新規定義

◆作者:faida @faida3983

◆更新履歴
ver1.0 : 公開
ver2.0 : 全体的に構造を見直したので一気にバージョンが上がりました。
ver2.1 : 反撃が敵単体対象の場合は行動した敵にのみ反撃する設定項目を追加しました。
ver2.2 : 混乱時の反撃が混乱時ターゲットを参照する不具合を修正しました。

=end

module FAI_CNT_EX
  # 設定項目:反撃が敵単体対象の場合は、行動した敵にのみ反撃する
  # ランダムや全体の場合はその制約はありません。
  ONLY_SUBJECT_CNT_FOR_ONE = true
 
  # 設定項目:魔法とか必中攻撃とかでも反撃する
  # 普通の反撃は魔法とか必中攻撃とかでは反撃できません。
  BEF_CNT_FOR_CERT = true
  HIT_CNT_FOR_CERT = true
  EVA_CNT_FOR_CERT = false
  BEF_CNT_FOR_MAG = true
  HIT_CNT_FOR_MAG = true
  EVA_CNT_FOR_MAG = false
 
  NOT_CNT_TYPE = {}
  NOT_CNT_TYPE[:all] = [[:normal, :before, :hit, :evade], []]
  NOT_CNT_TYPE[:normal] = [[:normal], []]
  NOT_CNT_TYPE[:before] = [[:before], []]
  NOT_CNT_TYPE[:hit] = [[:hit], []]
  NOT_CNT_TYPE[:evade] = [[:evade], []]
  NOT_CNT_TYPE[:attack] = [[:normal, :before, :hit, :evade],
    ["s.for_opponent?"]]
  NOT_CNT_TYPE[:defence] = [[:normal, :before, :hit, :evade],
    ["s.for_friend?"]]
 
  CND_CNT_LIST = []
  CND_CNT_LIST[0] = "[3,4,5,6,7,8,9,10].include?(item.damage.element_id)"
 
  CND_CNT = /<条件付反撃\s*(.+)>/
  ACND_CNT = /<全条件付反撃\s*(.+)>/
  NOR_CNT = /<通常反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  BEF_CNT = /<攻撃前反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  HIT_CNT = /<攻撃後反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  EVA_CNT = /<回避反撃\s*(\-?\d+(?:\,\s*\-?\d+)*)\s*\,\s*(\d+)[%%]>/
  NOT_CNT = /<反撃不可\s*(?:\:(.+))*>/
  NOR_CNT_PLUS = /<通常反撃率\s*([\+\-]?\d+)[%%]>/
  BEF_CNT_PLUS = /<攻撃前反撃率\s*([\+\-]?\d+)[%%]>/
  HIT_CNT_PLUS = /<攻撃後反撃率\s*([\+\-]?\d+)[%%]>/
  EVA_CNT_PLUS = /<回避反撃率\s*([\+\-]?\d+)[%%]>/
end

class RPG::BaseItem
  #--------------------------------------------------------------------------
  # ○ メモ取得
  #--------------------------------------------------------------------------
  def fai_cnt_ex_note
    @normal_counter = []
    @before_counter = []
    @hit_counter = []
    @evade_counter = []
    @forbid_counter = []
    @_condition_counter = nil
    @_condition_counter_all = nil
    note.each_line{|line|
      case line
      when FAI_CNT_EX::CND_CNT
        next @_condition_counter = $1
      when FAI_CNT_EX::ACND_CNT
        @_condition_counter_all = $1
      when FAI_CNT_EX::NOR_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @normal_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::BEF_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @before_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::HIT_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @hit_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::EVA_CNT
        rate = $2.to_i; skill_ids = $1.scan(/\-?\d+/).map{|n|n.to_i}
        @evade_counter << fai_cnt_note_ex_arr(skill_ids, rate)
      when FAI_CNT_EX::NOT_CNT
        @forbid_counter <<  ($1 || "all").to_sym
      when FAI_CNT_EX::NOR_CNT_PLUS
        @normal_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      when FAI_CNT_EX::BEF_CNT_PLUS
        @before_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      when FAI_CNT_EX::HIT_CNT_PLUS
        @hit_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      when FAI_CNT_EX::EVA_CNT_PLUS
        @evade_counter << fai_cnt_note_ex_arr(0, $1.to_i)
      end
      @_condition_counter = nil
    }
    @_condition_counter_all = nil
  end
  def fai_cnt_note_ex_cnd
    if @_condition_counter; @_condition_counter
    elsif @_condition_counter_all; @_condition_counter_all
    else; "true"
    end
  end
  def fai_cnt_note_ex_arr(skill_id, rate)
    [skill_id, rate / 100.0, fai_cnt_note_ex_cnd]
  end
  #--------------------------------------------------------------------------
  # ○ パラメータ
  #--------------------------------------------------------------------------
  def normal_counter
    fai_cnt_ex_note if !@normal_counter
    @normal_counter
  end
  def before_counter
    fai_cnt_ex_note if !@before_counter
    @before_counter
  end
  def hit_counter
    fai_cnt_ex_note if !@hit_counter
    @hit_counter
  end
  def evade_counter
    fai_cnt_ex_note if !@evade_counter
    @evade_counter
  end
  def forbid_counter
    fai_cnt_ex_note if !@forbid_counter
    @forbid_counter
  end
end

#==============================================================================
# ■ Game_BattlerBase
#==============================================================================

class Game_BattlerBase
  #--------------------------------------------------------------------------
  # ○ パラメータ
  #--------------------------------------------------------------------------
  def normal_counter
    arr = cnt > 0 ? [[[attack_skill_id], cnt, "true"]] : []
    arr + feature_objects.collect{|a|a.normal_counter}.flatten(1)
  end
  def ncr # normal_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.normal_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def before_counter
    feature_objects.collect{|a|a.before_counter}.flatten(1)
  end
  def bcr # before_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.before_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def hit_counter
    feature_objects.collect{|a|a.hit_counter}.flatten(1)
  end
  def hcr # hit_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.hit_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def evade_counter
    feature_objects.collect{|a|a.evade_counter}.flatten(1)
  end
  def ecr # evade_counter_rate
    feature_objects.inject(0.0){|r, a|
      r + (a.evade_counter.find{|arr|arr[0] == 0} || [0, 0])[1]
    }
  end
  def forbid_counter(item)
    (feature_objects+[item]).inject([]){|r, a| r | a.forbid_counter }
  end
  #--------------------------------------------------------------------------
  # ○ IDからオブジェクトを取得
  #--------------------------------------------------------------------------
  def use_cnt_item(id)
    id >= 0 ? $data_skills[id] : $data_items[-id]
  end
end

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

class Game_Battler < Game_BattlerBase
  attr_reader :set_counter_skills
  #--------------------------------------------------------------------------
  # ○ 反撃可能かチェック
  #--------------------------------------------------------------------------
  def counterable?(type, user, item, cnt_skill_id, str)
    s = use_cnt_item(cnt_skill_id)
    return false if !usable?(s) || !eval(str)
    user.forbid_counter(item).each{|symbol|
      cond = FAI_CNT_EX::NOT_CNT_TYPE[symbol]
      return false if cond[0].include?(type) && (cond[1].empty? ||
      cond[1].any?{|st|eval(st)})
    }
  end
  #--------------------------------------------------------------------------
  # ★ スキル/アイテムの反撃率計算
  #--------------------------------------------------------------------------
  alias fai_cnt_ex_item_cnt item_cnt
  def item_cnt(user, item)
    @set_counter_skills = nil
    return 0 unless opposite?(user) && item.physical?
    ids = (normal_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:normal, user, item, i, arr[2])} && arr[1] + bcr >= rand
      } || [0]
    )[0]
    @set_counter_skills = ids == 0 ? nil : ids
    return @set_counter_skills ? 1.0 : 0.0
    fai_cnt_ex_item_cnt(user, item)
  end
  #--------------------------------------------------------------------------
  # ○ 反撃スキルとか確率とか
  #--------------------------------------------------------------------------
  def item_bef_cnt(user, item)
    return nil if !opposite?(user)
    return nil if !FAI_CNT_EX::BEF_CNT_FOR_CERT && item.certain?
    return nil if !FAI_CNT_EX::BEF_CNT_FOR_MAG && item.magical?
    (before_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:before, user, item, i, arr[2])} && arr[1] + bcr >= rand
      } || [0]
    )[0]
  end
  def item_hit_cnt(user, item)
    return nil if !@result.hit? || !opposite?(user)
    return nil if !FAI_CNT_EX::HIT_CNT_FOR_CERT && item.certain?
    return nil if !FAI_CNT_EX::HIT_CNT_FOR_MAG && item.magical?
    (hit_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:hit, user, item, i, arr[2])} && arr[1] + hcr >= rand
      } || [0]
    )[0]
  end
  def item_eva_cnt(user, item)
    return nil if !@result.evaded || !opposite?(user)
    return nil if !FAI_CNT_EX::EVA_CNT_FOR_CERT && item.certain?
    return nil if !FAI_CNT_EX::EVA_CNT_FOR_MAG && item.magical?
    (evade_counter.find{|arr|
      arr[0].any?{|i|
        counterable?(:evade, user, item, i, arr[2])} && arr[1] + ecr >= rand
      } || [0]
    )[0]
  end
end

#==============================================================================
# ■ Scene_Battle
#==============================================================================

class Scene_Battle < Scene_Base
  #--------------------------------------------------------------------------
  # ★ スキル/アイテムの効果を適用
  #--------------------------------------------------------------------------
  alias fai_cnt_ex_apply_item_effects apply_item_effects
  def apply_item_effects(target, item)
    process_counter_ex(target, target.item_bef_cnt(@subject, item))
    fai_cnt_ex_apply_item_effects(target, item)
    process_counter_ex(target, target.item_hit_cnt(@subject, item))
    process_counter_ex(target, target.item_eva_cnt(@subject, item))
  end
  #--------------------------------------------------------------------------
  # 〇 特殊反撃の共通処理
  #--------------------------------------------------------------------------
  def process_counter_ex(target, arr)
    return if !arr || arr == 0
    id = arr.find{|i|target.usable?(target.use_cnt_item(i))}
    return if !id || id == 0
    item = target.use_cnt_item(id)
    action = Game_Action.new(target)
    item.is_a?(RPG::Item) ? action.set_item(item.id) : action.set_skill(item.id)
    if item.need_selection?
      action.target_index = item.for_friend? ? target.index : @subject.index
    end
    if item.for_opponent?
      ts = action.targets_for_opponents.compact
    elsif item.for_friend?
      ts = action.targets_for_friends.compact
    else
      ts = []
    end
    if FAI_CNT_EX::ONLY_SUBJECT_CNT_FOR_ONE && item.need_selection?
      ts = (item.for_friend? ? [target] : [@subject]) * ts.size
    end
    if id == target.attack_skill_id
      @log_window.display_counter(target, item)
    else
      @log_window.display_use_item(target, item)
      subject, @subject = @subject, target
      show_animation(ts, item.animation_id)
      @subject = subject
    end
    target.use_item(item)
    refresh_status
    ts.each{|t|
      item.repeats.times {
        t.item_apply(target, item)
        refresh_status
        @log_window.display_action_results(t, item)
      }
    }
  end
  #--------------------------------------------------------------------------
  # ● 反撃の発動
  #--------------------------------------------------------------------------
  def invoke_counter_attack(target, item)
    process_counter_ex(target, target.set_counter_skills)
  end
end
------------------------------------------------------------------
自作の(改造でない)スクリプト、プラグイン素材に
関しては、リードミーもしくは作中に
「faida」と記名していただければ
利用可能です。
土曜日
記事: 21
登録日時: 2017年11月18日(土) 19:22

Re: 解決済み)反撃スキル

投稿記事by 土曜日 » 2022年12月17日(土) 15:21

faida様

ご対応ありがとうございます。
make_targetsに係る不具合はもしかしたら何か出てくるかもしれませんが、ざっとテストしたところは要望の通りに動いてると思います。

ありがとうございます!

“VX / Ace:スクリプト素材のリクエスト” へ戻る