#==============================================================================| # ** DoubleX RMVXA Targeting AI v1.01c | #------------------------------------------------------------------------------| # * Changelog | # v1.01c(GMT 1500 14-7-2015): | # - Increased this script's efficiency and readability | # v1.01b(GMT 0200 23-3-2014): | # - Compatible with DoubleX RMVXA Confusion Edit v1.02b+ | # v1.01a(GMT 0600 13-3-2014): | # - Added resisting notetags | # - Changed the hierarchy of different types of notetags | # - Changed the definition of the avoid filtering notetags | # v1.00a(GMT 1100 12-3-2014): | # - 1st version of this script finished | #------------------------------------------------------------------------------| # * Author | # DoubleX | #------------------------------------------------------------------------------| # * Terms of use | # None other than not claiming this script as created by anyone except | # DoubleX or his alias | #------------------------------------------------------------------------------| # * Prerequisites | # Scripts: | # - none | # Knowledge: | # - Use of notetags with boolean logic | # - Some scripting knowledge to use this script to its full potential | #------------------------------------------------------------------------------| # * Functions | # Allows users to have greater control on single non random target | # selections of skills used by enemies or autobattle or confused actors | #------------------------------------------------------------------------------| # * Manual | # To use this script, open the script editor and put this script into an | # open slot between ▼ Materials and ▼ Main. Save to take effect. | #------------------------------------------------------------------------------| # * Compatibility | # Scripts aliasing method: | # - self.load_database under module DataManager | # - targets_for_opponents or targets_for_friends under class Game_Action | # may have compatibility issues with this script | # Place this script above those aliasing any of these methods if possible | #==============================================================================| ($imported ||= {})["DoubleX RMVXA Targeting AI"] = true #==============================================================================| # ** Resisting notetags for skills | #------------------------------------------------------------------------------| # * Note | # - Resisting notetags work on all targets and are checked first | # - If there's any of these notetags, working targets not included by any of| # them will be excluded | # - If all working targets are excluded, those excluded by this check will | # be included back | #------------------------------------------------------------------------------| # * Notetag <resist state: a1, a2, a3, ..., an> | # Includes targets not resisting any state with respective id in this | # notetag | #------------------------------------------------------------------------------| # * Notetag <resist debuff: param, param, param, ..., param> | # Includes targets not resisting any debuff with respective param in this | # notetag | #==============================================================================| # ** Filtering notetags for skills | #------------------------------------------------------------------------------| # * Note | # - Filtering notetags only work on non-excluded targets and are checked | # second | # - If there's any of these notetags, working targets not included by any of| # them will be excluded | # - If all working targets are excluded, those excluded by this check will | # be included back | #------------------------------------------------------------------------------| # * Notetag <target state: a1, a2, a3, ..., an> | # Includes targets having all states with respective id in this notetag | #------------------------------------------------------------------------------| # * Notetag <avoid state: a1, a2, a3, ..., an> | # Includes targets not having any state with respective id in this notetag | #------------------------------------------------------------------------------| # * Notetag <target buff: param, lv, param, lv, param, lv, ..., param, lv> | # Includes targets having all buffs with respective param and level(or | # above) in this notetag | #------------------------------------------------------------------------------| # * Notetag <avoid buff: param, lv, param, lv, param, lv, ..., param, lv> | # Includes targets not having any buff with respective param and level(or | # above) in this notetag | #------------------------------------------------------------------------------| # * Notetag <target debuff: param, lv, param, lv, param, lv, ..., param, lv> | # Includes targets having all debuffs with respective param and level(or | # above) in this notetag | #------------------------------------------------------------------------------| # * Notetag <avoid debuff: param, lv, param, lv, param, lv, ..., param, lv> | # Includes targets not having any debuff with respective param and level(or | # above) in this notetag | #==============================================================================| # ** Sorting notetags for skills | #------------------------------------------------------------------------------| # * Note | # - Sorting notetags only work on non-excluded targets and are checked last | # - If there's any of these notetags, working targets not included by any of| # them will be excluded | # - If all working targets are excluded, those excluded by this check will | # be included back | #------------------------------------------------------------------------------| # * Notetag <sort param: param, ord, param, ord, param, ord, ..., param, ord> | # - param can be Parameter, Ex-Parameter, Sp-Parameter, hp, mp, tp, level, | # hp_rate, mp_rate, tp_rate, element_rate(element_id), | # debuff_rate(param_id) or state_rate(state_id) | # - (Needs scripting knowledge)param can also be some other methods under | # class Game_BattlerBase, Game_Battler, Game_Actor or Game_Enemy | # These methods need to be comparable | # - ord can be high or low(pick the highest or lowest param respectively) | #==============================================================================| #==============================================================================| # ** You need not edit this part as it's about how this script works | #------------------------------------------------------------------------------| module DoubleX_RMVXA module REGEXP module SKILL RESIST_STATE = /<(?:RESIST_STATE|resist state):[ ](\w+(?:\s*,\s*\w+)*)>/i RESIST_DEBUFF = /<(?:RESIST_DEBUFF|resist debuff):[ ](\w+(?:\s*,\s*\w+)*)>/i TARGET_STATE = /<(?:TARGET_STATE|target state):[ ](\w+(?:\s*,\s*\w+)*)>/i AVOID_STATE = /<(?:AVOID_STATE|avoid state):[ ](\w+(?:\s*,\s*\w+)*)>/i TARGET_BUFF = /<(?:TARGET_BUFF|target buff):[ ](\w+(?:\s*,\s*\w+)*)>/i AVOID_BUFF = /<(?:AVOID_BUFF|avoid buff):[ ](\w+(?:\s*,\s*\w+)*)>/i TARGET_DEBUFF = /<(?:TARGET_DEBUFF|target debuff):[ ](\w+(?:\s*,\s*\w+)*)>/i AVOID_DEBUFF = /<(?:AVOID_DEBUFF|avoid debuff):[ ](\w+(?:\s*,\s*\w+)*)>/i SORT_PARAM = /<(?:SORT_PARAM|sort param):[ ](\w+(?:\s*,\s*\w+)*)>/i TARGETING_AI = ["resist_state", "resist_debuff", "target_state", "avoid_state", "target_buff", "avoid_buff", "target_debuff", "avoid_debuff", "sort_param"] end # SKILL end # REGEXP end # DoubleX_RMVXA class << DataManager #----------------------------------------------------------------------------| # Alias method: load_database | #----------------------------------------------------------------------------| alias load_database_targeting_ai load_database def load_database load_database_targeting_ai # Added to load targeting ai notetags load_notetags_targeting_ai # end # load_database #----------------------------------------------------------------------------| # New method: load_notetags_targeting_ai | #----------------------------------------------------------------------------| def load_notetags_targeting_ai $data_skills.each { |obj| obj.load_notetags_targeting_ai if obj } end # load_notetags_targeting_ai end # DataManager class RPG::Skill < RPG::UsableItem #----------------------------------------------------------------------------| # New public instance variables | #----------------------------------------------------------------------------| DoubleX_RMVXA::REGEXP::SKILL::TARGETING_AI.each { |note| eval("attr_accessor :#{note}") eval("attr_accessor :#{note}s") } #----------------------------------------------------------------------------| # New method: load_notetags_targeting_ai | #----------------------------------------------------------------------------| def load_notetags_targeting_ai DoubleX_RMVXA::REGEXP::SKILL::TARGETING_AI.each { |note| eval("@#{note} = false") eval("@#{note}s = {}") eval("@#{note}s[:index] = []") } @note.split(/[\r\n]+/).each_with_index { |line, num| DoubleX_RMVXA::REGEXP::SKILL::TARGETING_AI.each_with_index { |note, i| eval("@#{note}s[num] = []") case line when eval("DoubleX_RMVXA::REGEXP::SKILL::#{note.upcase}") $1.scan(/\w+/).each_with_index { |input, index| if i > 3 && i < 8 next store_notetags_targeting_ai(num, store_param_targeting_ai(input), note, :to_i) if index % 2 == 0 elsif i == 1 next store_notetags_targeting_ai(num, store_param_targeting_ai(input), note, :to_i) elsif i < 4 next store_notetags_targeting_ai(num, input, note, :to_i) end store_notetags_targeting_ai(num, input, note, :to_s) } end } } DoubleX_RMVXA::REGEXP::SKILL::TARGETING_AI.each { |note| eval("@#{note}s[:index].uniq if @#{note}") } end # load_notetags_targeting_ai #----------------------------------------------------------------------------| # New method: store_notetags_targeting_ai | #----------------------------------------------------------------------------| def store_notetags_targeting_ai(num, input, note, store) eval("@#{note}s")[num] << input.send(store) eval("@#{note}s")[:index] << num eval("@#{note} = true") end # store_notetags_targeting_ai #----------------------------------------------------------------------------| # New common cache: store_param_targeting_ai | #----------------------------------------------------------------------------| def store_param_targeting_ai(input) case input when "mhp" 0 when "mmp" 1 when "atk" 2 when "def" 3 when "mat" 4 when "mdf" 5 when "agi" 6 when "luk" 7 end end # store_param_targeting_ai end # RPG::Skill class Game_Action #----------------------------------------------------------------------------| # Alias method: targets_for_opponents | #----------------------------------------------------------------------------| alias targets_for_opponents_targeting_ai targets_for_opponents def targets_for_opponents targeting_ai_targets("opponents") end # targets_for_opponents #----------------------------------------------------------------------------| # Alias method: targets_for_friends | #----------------------------------------------------------------------------| alias targets_for_friends_targeting_ai targets_for_friends def targets_for_friends targeting_ai_targets("friends") end # targets_for_friends #----------------------------------------------------------------------------| # New method: targeting_ai_targets | #----------------------------------------------------------------------------| def targeting_ai_targets(targets) unless item.is_a?(RPG::Skill) && item.for_one? && (subject.enemy? || subject.auto_battle? || subject.confusion?) return send("targets_for_#{targets}_targeting_ai".to_sym) end if targeting_ai_dead_targets(targets).size <= 1 return targeting_ai_dead_targets(targets) end ai_resist_target = [] ai_filter_target = [] ai_sort_target = [] DoubleX_RMVXA::REGEXP::SKILL::TARGETING_AI.each { |note| if (note == "resist_state" || note == "resist_debuff") && item.send(note.to_sym) && send("#{note}_ai(targets)".to_sym).size > 0 ai_resist_target.concat(send("#{note}_ai(targets)".to_sym)) elsif note == "sort_param" if ai_resist_target.empty? ai_resist_target = targeting_ai_dead_targets(targets) end ai_filter_target.delete_if { |t| !ai_resist_target.include?(t) } ai_filter_target = ai_resist_target if ai_filter_target.empty? next unless item.send(note.to_sym) ai_sort_target = sort_param_ai(ai_filter_target) elsif item.send(note.to_sym) && send("#{note}_ai(targets)".to_sym).size > 0 ai_filter_target.concat(send("#{note}_ai(targets)".to_sym)) end } ai_sort_target = ai_filter_target if ai_sort_target.empty? targeting_ai_random_targets(ai_sort_target) end # targeting_ai_targets #----------------------------------------------------------------------------| # New method: targeting_ai_random_targets | #----------------------------------------------------------------------------| def targeting_ai_random_targets(targets) num = 1 num += subject.atk_times_add.to_i if attack? return [targets[0]] * num if targets.size == 1 tgr_rand = rand * targets.inject(0) {|r, mem| r + mem.tgr } targets.each { |target| tgr_rand -= target.tgr return [target] * num if tgr_rand < 0 } [targets[0]] * num end # targeting_ai_random_targets #----------------------------------------------------------------------------| # New method: targeting_ai_dead_targets | #----------------------------------------------------------------------------| def targeting_ai_dead_targets(targets) if item.for_dead_friend? target = friends_unit.dead_members elsif $imported["DoubleX RMVXA Confusion Edit"] && subject.exclude_self?(subject.states) target = opponents_unit.alive_members + friends_unit.alive_members else target = send("#{targets}_unit".to_sym).alive_members end if $imported["DoubleX RMVXA Confusion Edit"] && subject.exclude_self?(subject.states) && target.include?(subject) target.delete(subject) end target end # targeting_ai_dead_targets #----------------------------------------------------------------------------| # New method: ai_target_uniq | #----------------------------------------------------------------------------| def ai_target_uniq(targets) targets.uniq if targets.size > 1 targets end # ai_target_uniq #----------------------------------------------------------------------------| # New method: notetag_targeting_ai | #----------------------------------------------------------------------------| def notetag_targeting_ai(targets, notetag) notetags = [:target_buffs, :avoid_buffs, :target_debuffs, :avoid_debuffs] ai_target = [] item_index = item.send(notetag)[:index] item_index.each { |index| index_item = item.send(notetag)[index] target = targeting_ai_dead_targets(targets) param_id = nil if include = notetags.include?(notetag) index_item.each_with_index { |note, num| next param_id = note if include && num % 2 == 0 target.delete_if { |t| yield(param_id, note, t) } break if target.empty? } ai_target.concat(target) unless target.empty? } ai_target_uniq(ai_target) end # notetag_targeting_ai #----------------------------------------------------------------------------| # New method: resist_state_ai | #----------------------------------------------------------------------------| def resist_state_ai(targets) notetag_targeting_ai(targets, :resist_states) { |p, n, t| t.state_resist?(n) || t.state_rate(n) * t.luk_effect_rate(subject) <= 0 } end # resist_state_ai #----------------------------------------------------------------------------| # New method: resist_debuff_ai | #----------------------------------------------------------------------------| def resist_debuff_ai(targets) notetag_targeting_ai(targets, :resist_debuffs) { |p, n, t| t.debuff_rate(n) * t.luk_effect_rate(subject) <= 0 } end # resist_state_ai #----------------------------------------------------------------------------| # New method: target_state_ai | #----------------------------------------------------------------------------| def target_state_ai(targets) notetag_targeting_ai(targets, :target_states) { |p, n, t| !t.state?(n) } end # target_state_ai #----------------------------------------------------------------------------| # New method: avoid_state_ai | #----------------------------------------------------------------------------| def avoid_state_ai(targets) notetag_targeting_ai(targets, :avoid_states) { |p, n, t| t.state?(n) } end # avoid_state_ai #----------------------------------------------------------------------------| # New method: target_buff_ai | #----------------------------------------------------------------------------| def target_buff_ai(targets) notetag_targeting_ai(targets, :target_buffs) { |p, n, t| t.buffs[p] < n } end # target_buff_ai #----------------------------------------------------------------------------| # New method: avoid_buff_ai | #----------------------------------------------------------------------------| def avoid_buff_ai(targets) notetag_targeting_ai(targets, :avoid_buffs) { |p, n, t| t.buffs[p] >= n } end # avoid_buff_ai #----------------------------------------------------------------------------| # New method: target_debuff_ai | #----------------------------------------------------------------------------| def target_debuff_ai(targets) notetag_targeting_ai(targets, :target_debuffs) { |p, n, t| t.buffs[p] > -n } end # target_debuff_ai #----------------------------------------------------------------------------| # New method: avoid_debuff_ai | #----------------------------------------------------------------------------| def avoid_debuff_ai(targets) notetag_targeting_ai(targets, :avoid_debuffs) { |p, n, t| t.buffs[p] <= -n } end # avoid_debuff_ai #----------------------------------------------------------------------------| # New method: sort_param_ai | #----------------------------------------------------------------------------| def sort_param_ai(ai_target) targets = [] item.sort_params[:index].each { |index| target = [] param = nil item.sort_params[index].each_with_index { |note, num| next param = note if num % 2 == 0 param = param.to_sym case note when "high" t = ai_target.sort { |a, b| b.send(param) <=> a.send(param) } target << t[0] when "low" t = ai_target.sort { |a, b| a.send(param) <=> b.send(param) } target << t[0] end target.uniq if target.size > 1 break if target.size > 1 } targets.concat(target) if target.size == 1 } ai_target_uniq(targets) end # sort_param_ai end # Game_Action class Game_Battler < Game_BattlerBase #----------------------------------------------------------------------------| # (v1.01c+)New public instance_variable | #----------------------------------------------------------------------------| attr_reader :buffs end # Game_Battler #==============================================================================|