#-------------------------------------------------------------------------- #●ちょっと賢い敵AIスクリプト。 # +行動直前でアクションを決定 # # Ver1.01 # 混乱、暴走時に冷静にスキルを駆使してくるバグを修正しました。 # #敵が無駄な行動を取らなくなります。 #具体的には、既にかかっているステートを重ねがけしなくなり、 #また絶対にかからないステートや、ノーダメージ、吸収される攻撃はなるべく避けたり #HPが満タンな敵に対して回復魔法を使ったりという行動をしなくなります。 # #仕様としては、行動パターンの条件を満たしていても #『誰に使っても効果がない』場合は、行動パターンから除外されます。 #『一部の相手に使うと効果がある』場合は、その行動は行動パターンに適応されて #効果がある相手にのみ使用します。 # #具体的には、このスクリプトを導入して賢くなったAIは #例えばヒール:優先度5、攻撃:優先度4にすれば、 #HPが減った仲間がいる時にHPが減ったモンスターに対してのみ #ヒールを優先して使うようになり #ヒールを使っても効果がないときは通常攻撃のみを行います。 # # #また、このスクリプトには行動直前でアクションを決定する処理が同梱されています。 #これは、賢いAIをより有用に使うための処置ですが、 #ATBやCTBシステムを採用している方には必要ないと思われます。 #(本来の処理だと、ターン最初に行動を決定する) #▼即時反応スクリプトここから〜ここまで #と書かれた部分が、該当するスクリプトになるので、 #不要だと思われるなら、適宜消去してください。 # # 名前の衝突による競合を避けるために、新しく定義したメソッドには # 接頭語として er_ をつけています。 # 再定義してるメソッドはありませんが、 # でもやっぱいろいろ競合する可能性は多少はあると思います。 # どちらかというと、スクリプトの上のほうに配置すると、 # 競合が起きにくくなるんじゃないかなーと思います。 # # ●このスクリプトは、それぞれre_wisely_enemy、re_flexes_enemyに # エネミーIDを指定する事で効果を表します。 # #加工、二次配布等、ご自由にどうぞ。 #-------------------------------------------------------------------------- class Game_Enemy < Game_Battler #賢くする敵をIDで指定 def re_wisely_enemy case @enemy_id when 1 return true end return false end #-------------------------------------------------------------------------- # ● アクションが有効かどうか判定。 #-------------------------------------------------------------------------- def re_action_usable?(act) action = Game_BattleAction.new(self) action.kind = act.kind action.basic = act.basic action.skill_id = act.skill_id case action.kind when 0 case action.basic when 0 #通常攻撃の場合、ダメージが通る相手がいるなら有効 return action.re_gain_attack_usable? else #防御、逃走、待機の場合、無条件で有効 return true end when 1 #スキルの場合 return action.re_gain_skill_usable? when 2 #アイテムの場合、念のためとりあえず有効って事で。 return true end #念のため、何の処理もない場合は有効で。 return true end alias base_make_action make_action def make_action return re_make_wisely_action if self.re_wisely_enemy base_make_action end def re_make_wisely_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 # 効果の得られない行動な場合、行動候補から除外します next if not re_action_usable?(action) 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 class Game_BattleAction def re_gain_attack_usable? targets = re_gain_attack_targets for target in targets next if not target.attack_effective?(battler) #念のため通常攻撃できるか判定 next if not target.re_attack_test(battler) return true end return false end def re_gain_skill_usable? return if skill == nil for_friend = (for_friend? or for_dead_friend?) targets = re_gain_obj_targets(skill) for target in targets next if not target.re_skill_test(battler,skill,for_friend) return true end return false end #-------------------------------------------------------------------------- # ● 通常攻撃のターゲット候補取得 #-------------------------------------------------------------------------- def re_gain_attack_targets if battler.confusion? return friends_unit.existing_members elsif battler.berserker? return opponents_unit.existing_members else return opponents_unit.existing_members end return [] end #-------------------------------------------------------------------------- # ● スキルまたはアイテムのターゲット候補取得 #  攻撃できる対象を全員取得するだけなので、 #  単体か全体かなどの判定はやりません。 # obj : スキルまたはアイテム #-------------------------------------------------------------------------- def re_gain_obj_targets(obj) targets = [] return targets if obj == nil if obj.for_opponent? return opponents_unit.existing_members elsif obj.for_user? # 使用者 return [battler] elsif obj.for_dead_friend? return friends_unit.dead_members elsif obj.for_friend? return friends_unit.existing_members end return [] end #-------------------------------------------------------------------------- # ● ランダムターゲット # 賢い場合は、対象の中から有効な相手のみを選び出し、 # その中でランダムに対象を決めます。 #-------------------------------------------------------------------------- alias base_decide_random_target decide_random_target def decide_random_target if battler.re_wisely_enemy result = [] case @kind when 0 targets = re_gain_attack_targets for target in targets next if not target.re_attack_test(battler) result.push(target) end re_decide_select_random_target(result) return when 1 targets = re_gain_obj_targets(self.skill) for_friend = (for_friend? or for_dead_friend?) for target in targets next if not target.re_skill_test(battler,self.skill,for_friend) result.push(target) end re_decide_select_random_target(result) return end end base_decide_random_target end def re_decide_select_random_target(targets) roulette = [] for member in targets member.odds.times do roulette.push(member) end end target = (roulette.size > 0 ? roulette[rand(roulette.size)] : nil) if target == nil clear else @target_index = target.index end end end class Game_Battler #-------------------------------------------------------------------------- # ● 通常攻撃の適用テスト # attacker : スキルの使用者 # ダメージ結果が0でないか、状態変化があるなら適応。 #-------------------------------------------------------------------------- def re_attack_test(attacker) tester = self.clone tester.make_attack_damage_value(attacker) #tester.apply_state_changes(attacker) if tester.hp_damage > 0 return true# if tester.hp < tester.maxhp end if tester.mp_damage > 0 return true #if tester.mp < tester.maxmp end return true if tester.re_state_test(attacker) return false end #-------------------------------------------------------------------------- # ● スキルの適用テスト # friend : 仲間に対して行うスキルならtrue。 # tester.hp_damage < 0 と相同性をチェックして、有効かどうか判断します。 # ダメージ吸収を有効行動と判定しないようにするために行っています。 # 再定義ではありませんが、元のskill_testメソとはちょっと違っています。 #-------------------------------------------------------------------------- def re_skill_test(user, skill,friend) tester = self.clone tester.make_obj_damage_value(user, skill) #tester.apply_state_changes(skill) if tester.hp_damage != 0 return true if (tester.hp < tester.maxhp or tester.hp_damage > 0) and (friend == (tester.hp_damage < 0 )) end if tester.mp_damage != 0 return true if (tester.mp < tester.maxmp or tester.mp_damage > 0) and (friend == (tester.mp_damage < 0 )) end return true if tester.re_state_test(skill) #return true unless tester.added_states.empty? #return true unless tester.removed_states.empty? return false end #-------------------------------------------------------------------------- # ● ステートの適用テスト # 有意義なステートかバステなのかの判定はしていません。 #removed_states関連を全て取り除けば、 #ステート解除の行動は有効無効に関与しなくなると思います。(未確認 #-------------------------------------------------------------------------- def re_state_test(obj) added_states = [] removed_states = [] plus = obj.plus_state_set # ステート変化(+) を取得 minus = obj.minus_state_set # ステート変化(-) を取得 for i in plus # ステート変化 (+) next if state_resist?(i) # 無効化されている? next if dead? # 戦闘不能? next if i == 1 and @immortal # 不死身? if state?(i) # すでに付加されている? #remained_states.push(i) # 変化しなかったステートを記録 next end if state_probability(i) != 0 # 確率判定が少しでも付加の可能性があるなら有効 #add_state(i) # ステートを付加 added_states.push(i) # 付加したステートを記録 end end for i in minus # ステート変化 (-) next unless state?(i) # 付加されていない? #remove_state(i) # ステートを解除 removed_states.push(i) # 解除したステートを記録する end for i in added_states & removed_states added_states.delete(i) # 付加と解除の両方に記録されている removed_states.delete(i) # ステートがあれば両方削除する end return (added_states.size + removed_states.size > 0) end end #=====▼即時反応スクリプトここから================ class Game_Enemy < Game_Battler #行動直前に行動を決定するタイプの敵をIDで指定 def re_flexes_enemy case @enemy_id when 1 return true end return false end end class Game_BattleAction alias base_prepare prepare def prepare if battler.is_a?(Game_Enemy) #バトラーが即時反応をするかどうかの判定。 #ただしエネミーのみ。 if not @basic == 1 and battler.re_flexes_enemy #防御状態から行動を変化させるのはズルなので除外 battler.make_action end end base_prepare end end #=====▲即時反応スクリプトここまで================