じ☆ve冰风 发表于 2026-7-11 21:55:51

Advanced Scopes - More target options for battlers

Introduction

This script defines new scope types for items and skills in battle.
More specifically, it separates the scope into distinct properties you can define independently.

Those properties are:
- Affects allies
- Affects enemies
- Affects the entire group or only one
- Selects one randomly (new)
- Includes the user
- Only affects battlers that are alive
- Only affects battlers that are dead

You can also define completely custom restrictions by block, for example skills that can't target ghost enemies, or items that can only target allies that have a state, or more than 50% HP, etc.

Author: Wecoc
First Release: January 2017
Last Version: November 2018

Terms of use
- Giving credits (Wecoc) is optional, but appreciated.
- You can repost this code.
- You can edit this code freely, and distribute the edits as well.
- This code can be used on commercial games.

Demo
You can download a basic demo here: Advanced Scope.zip

Code
There are two versions, a normal one and a version compatible with Data File Save.

Normal version (independent)
Spoiler: Code                 Ruby:        
#==============================================================================
# ** Advanced Scope v1.1
#------------------------------------------------------------------------------
# Author: Wecoc (credits are optional)
#------------------------------------------------------------------------------
# Defines new types of scope for items and skills in battle
#------------------------------------------------------------------------------
# $data_items and $data_skills work exactly the same way
# To define the target use:
# $data_items.scope_ally   = true | false # Ally
# $data_items.scope_enemy= true | false # Enemy
# $data_items.scope_all    = true | false # Entire group / Only one
# $data_items.scope_random = true | false # Pick one randomly
# $data_items.scope_user   = true | false # Include user
# $data_items.scope_alive= true | false # Only alive members
# $data_items.scope_dead   = true | false # Only dead members
#------------------------------------------------------------------------------
# $data_items.restriction(&block) # Set custom restriction
# $data_items.restrictions      # Get all custom restrictions
# $data_items.clear_restrictions# Clear all custom restrictions
#==============================================================================

#==============================================================================
# ** Scope Configuration
#==============================================================================

module Scope
#----------------------------------------------------------------------------
# Default Dead Select
#----------------------------------------------------------------------------
# By default if an item only affects members that are alive you can still
# select a dead member, but the item won't have any effect.
# The same happens with items that only affect dead members.
# Set to false if you want to disable that and apply a strict restriction.
#----------------------------------------------------------------------------

DEFAULT_DEAD_SELECT = true

end

#==============================================================================
# ** Array
#==============================================================================

class Array
#--------------------------------------------------------------------------
# * Select!
#--------------------------------------------------------------------------
unless self.respond_to?(:select!)
    def select!(&block)
      result = self.select(&block)
      self.replace(result)
    end
end
end

#==============================================================================
# ** RPG
#==============================================================================

for Klass in
class Klass
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_writer :scope_ally, :scope_enemy, :scope_all, :scope_random
    attr_writer :scope_user, :scope_alive, :scope_dead
    #--------------------------------------------------------------------------
    # * For Allies
    #--------------------------------------------------------------------------
    def scope_ally
      @scope_ally = .include?(@scope) if @scope_ally == nil
      return @scope_ally
    end
    #--------------------------------------------------------------------------
    # * For Enemies
    #--------------------------------------------------------------------------
    def scope_enemy
      @scope_enemy = .include?(@scope) if @scope_enemy == nil
      return @scope_enemy
    end
    #--------------------------------------------------------------------------
    # * For All Party/Troop Members
    #--------------------------------------------------------------------------
    def scope_all
      @scope_all = .include?(@scope) if @scope_all == nil
      return @scope_all
    end
    #--------------------------------------------------------------------------
    # * Random Pick
    #--------------------------------------------------------------------------
    def scope_random
      @scope_random = false if @scope_random == nil
      return @scope_random
    end
    #--------------------------------------------------------------------------
    # * User included
    #--------------------------------------------------------------------------
    def scope_user
      if Scope::DEFAULT_DEAD_SELECT == true
      @scope_user = .include?(@scope) if @scope_user == nil
      else
      @scope_user = .include?(@scope) if @scope_user == nil
      end
      return @scope_user
    end
    #--------------------------------------------------------------------------
    # * Only Alive
    #--------------------------------------------------------------------------
    def scope_alive
      @scope_alive = .include?(@scope) if @scope_alive == nil
      return @scope_alive
    end
    #--------------------------------------------------------------------------
    # * Only Dead
    #--------------------------------------------------------------------------
    def scope_dead
      @scope_dead = .include?(@scope) if @scope_dead == nil
      return @scope_dead
    end
    #--------------------------------------------------------------------------
    # * Define Scope
    #--------------------------------------------------------------------------
    def set_scope(ally,enemy,all,random=false,user=true,alive=true,dead=false)
      self.scope_ally   = ally
      self.scope_enemy= enemy
      self.scope_all    = all
      self.scope_random = random
      self.scope_user   = user
      self.scope_alive= alive
      self.scope_dead   = dead
    end
    #--------------------------------------------------------------------------
    # * Special Restrictions
    #--------------------------------------------------------------------------
    def scope_rest
      @scope_rest = [] if @scope_rest == nil
      return @scope_rest
    end
    def restriction(&block)self.scope_rest.push(block)end
    def restrictions()       self.scope_rest            end
    def clear_restrictions() self.scope_rest.clear      end
    #--------------------------------------------------------------------------
end
end

#==============================================================================
# ** Arrow_Base
#==============================================================================

class Arrow_Base < Sprite
attr_reader :user
attr_reader :item
attr_reader :target
attr_reader :targets
#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------
def initialize(viewport, user, item)
    super(viewport)
    self.bitmap = RPG::Cache.windowskin($game_system.windowskin_name)
    self.ox = 16
    self.oy = 64
    self.z = 2500
    @blink_count = 0
    @index = 0
    @help_window = nil
    @user = user
    @item = item
    @targets = target_battlers
    @target = @targets
    update_sprite
end
#--------------------------------------------------------------------------
# * Get index
#--------------------------------------------------------------------------
def index
    return @targets.index(@target) rescue -1
end
#--------------------------------------------------------------------------
# * Set index
#--------------------------------------------------------------------------
def index=(index)
    @target = @targets
end
#--------------------------------------------------------------------------
# * Get selectable targets
#--------------------------------------------------------------------------
def target_battlers
    if @user.is_a?(Game_Actor)
      allies = $game_party.actors.clone
      enemies = $game_troop.enemies.clone
    else
      allies = $game_troop.enemies.clone
      enemies = $game_party.actors.clone
    end
    allies.delete_if {|target| target.hidden}
    enemies.delete_if{|target| target.hidden}
    if @item == nil
      enemies.delete_if {|target| !target.exist? }
      return enemies
    end
    result = []
    if @item.scope_ally == true
      for target in allies
      result.push(target)
      end
    end
    if @item.scope_enemy == true
      for target in enemies
      result.push(target)
      end
    end
    if @item.scope_user == true
      if !result.include?(@user)
      result.push(@user)
      end
    end
    if @item.scope_user == false
      result.delete(@user)
    end
    if @item.scope_alive == true && Scope::DEFAULT_DEAD_SELECT == false
      result.select!{|target| !target.dead?}
    end
    if @item.scope_dead == true && Scope::DEFAULT_DEAD_SELECT == false
      result.select!{|target| target.dead?}
    end
    for r in @item.restrictions
      if r.arity == 1
      result.select!{|target| r.call(target) == true} rescue nil
      else
      result.select!{|target| r.call == true} rescue nil
      end
    end
    return result
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
    update_sprite
    if @help_window != nil
      update_help
    end
    if @target == nil
      self.visible = false
      return
    end
    self.visible = true
    # Next target
    if Input.repeat?(Input::RIGHT)
      $game_system.se_play($data_system.cursor_se)
      self.index = (self.index + 1) % @targets.size
    end
    # Previous target
    if Input.repeat?(Input::LEFT)
      $game_system.se_play($data_system.cursor_se)
      self.index = (self.index - 1) % @targets.size
    end
    # Place arrow over target
    if @target != nil
      self.x = @target.screen_x
      self.y = @target.screen_y
    end
end
#--------------------------------------------------------------------------
# * Update Sprite
#--------------------------------------------------------------------------
def update_sprite
    @blink_count = (@blink_count + 1) % 8
    if @blink_count < 4
      self.src_rect.set(128, 96, 32, 32)
    else
      self.src_rect.set(160, 96, 32, 32)
    end
end
#--------------------------------------------------------------------------
# * Update Help
#--------------------------------------------------------------------------
def update_help
    if @target == nil
      @help_window.set_text("")
      return
    end
    if @target.is_a?(Game_Actor)
      @help_window.set_actor(@target)
    else
      @help_window.set_enemy(@target)
    end
end
end

#==============================================================================
# ** Game_Battler
#==============================================================================

class Game_Battler
#--------------------------------------------------------------------------
# * Check if the skill can be used
#--------------------------------------------------------------------------
alias wecoc_scope_skill_use? skill_can_use? unless $@
def skill_can_use?(skill_id)
    skill = $data_skills
    return false if skill.nil?   # Skill doesn't exist
    return false if !self.exist? # User is hidden or dead
    if self.is_a?(Game_Actor)
      members = $game_party.actors.clone
    else
      members = $game_troop.enemies.clone
    end
    if members.size == 1 # User is the only member and requires an ally
      if skill.user == false && skill.ally == false && skill.enemy == false
      return false
      end
    end
    for r in skill.restrictions
      if r.arity == 1
      members.select!{|target| r.call(target) == true} rescue nil
      else
      members.select!{|target| r.call == true} rescue nil
      end
    end
    return false if members.size == 0
    return wecoc_scope_skill_use?(skill_id)
end
#--------------------------------------------------------------------------
# * Check if the item can be used
#--------------------------------------------------------------------------
def item_can_use?(item_id)
    item = $data_items
    return false if item.nil?    # Item doesn't exist
    return false if !self.exist? # User is hidden or dead
    if self.is_a?(Game_Actor)
      # Party doesn't contain that item
      return false if $game_party.item_number(item_id) == 0
      # Item restrictions (Only menu / battle)
      return false if $game_temp.in_battle&& item.occasion == 2
      return false if !$game_temp.in_battle && item.occasion == 1
      members = $game_party.actors.clone
    else
      members = $game_troop.enemies.clone
    end
    if members.size == 1 # User is the only member and requires an ally
      if item.user == false && item.ally == false && item.enemy == false
      return false
      end
    end
    for r in item.restrictions
      if r.arity == 1
      members.select!{|target| r.call(target) == true} rescue nil
      else
      members.select!{|target| r.call == true} rescue nil
      end
    end
    return false if members.size == 0
    return true
end
end

#==============================================================================
# ** Game_Party
#==============================================================================

class Game_Party
#--------------------------------------------------------------------------
# * Check if the party can use an item
#--------------------------------------------------------------------------
def item_can_use?(item_id)
    for member in $game_party.actors
      if member.item_can_use?(item_id)
      return true
      end
    end
    return false
end
end

#==============================================================================
# ** Scene_Battle
#==============================================================================

class Scene_Battle
#--------------------------------------------------------------------------
# * Select enemy
#--------------------------------------------------------------------------
def start_enemy_select
    item = nil
    if @active_battler.current_action.kind == 1
      item = @skill if @skill != nil
    end
    if @active_battler.current_action.kind == 2
      item = @itemif @item != nil
    end
    @enemy_arrow = Arrow_Base.new(@spriteset.viewport2, @active_battler, item)
    @enemy_arrow.help_window = @help_window
    @actor_command_window.active = false
    @actor_command_window.visible = false
end
#--------------------------------------------------------------------------
# * Select actor
#--------------------------------------------------------------------------
def start_actor_select
    item = nil
    if @active_battler.current_action.kind == 1
      item = @skill if @skill != nil
    end
    if @active_battler.current_action.kind == 2
      item = @itemif @item != nil
    end
    @actor_arrow = Arrow_Base.new(@spriteset.viewport2, @active_battler, item)
    @actor_arrow.index = @actor_index
    @actor_arrow.help_window = @help_window
    @actor_command_window.active = false
    @actor_command_window.visible = false
end
#--------------------------------------------------------------------------
# * Apply skill
#--------------------------------------------------------------------------
def make_skill_action_result
    @skill = $data_skills[@active_battler.current_action.skill_id]
    unless @active_battler.current_action.forcing
      unless @active_battler.skill_can_use?(@skill.id)
      $game_temp.forcing_battler = nil
      @phase4_step = 1
      return
      end
    end
    @active_battler.sp -= @skill.sp_cost
    @status_window.refresh
    @help_window.set_text(@skill.name, 1)
    @animation1_id = @skill.animation1_id
    @animation2_id = @skill.animation2_id
    @common_event_id = @skill.common_event_id
    @target_battlers.clear
    @target_battlers = set_target_battlers(@skill)
    for target in @target_battlers
      target.skill_effect(@active_battler, @skill)
    end
end
#--------------------------------------------------------------------------
# * Apply item
#--------------------------------------------------------------------------
def make_item_action_result
    @item = $data_items[@active_battler.current_action.item_id]
    unless @active_battler.item_can_use?(@item.id)
      @phase4_step = 1
      return
    end
    if @item.consumable
      $game_party.lose_item(@item.id, 1)
    end
    @help_window.set_text(@item.name, 1)
    @animation1_id = @item.animation1_id
    @animation2_id = @item.animation2_id
    @common_event_id = @item.common_event_id
    index = @active_battler.current_action.target_index
    target = $game_party.smooth_target_actor(index)
    @target_battlers.clear
    @target_battlers = set_target_battlers(@item)
    for target in @target_battlers
      target.item_effect(@item)
    end
end
#--------------------------------------------------------------------------
# * Get available targets for an item or skill
#--------------------------------------------------------------------------
def set_target_battlers(item)
    if @active_battler.is_a?(Game_Actor)
      allies = $game_party.actors.clone
      enemies = $game_troop.enemies.clone
    else
      allies = $game_troop.enemies.clone
      enemies = $game_party.actors.clone
    end
    index = @active_battler.current_action.target_index
    result = []
    if item.scope_ally == true
      for target in allies
      result.push(target)
      end
    end
    if item.scope_enemy == true
      for target in enemies
      result.push(target)
      end
    end
    if item.scope_user == true
      if !result.include?(@active_battler)
      result.push(@active_battler)
      end
    end
    if item.scope_user == false
      result.delete(@active_battler)
    end
    if item.scope_all == false
      if item.scope_random == true
      result.select!{|target| !target.dead?} if item.scope_alive == true
      result.select!{|target| target.dead?} if item.scope_alive == false
      else
      if Scope::DEFAULT_DEAD_SELECT == false
          result.select!{|target| !target.dead?} if item.scope_alive == true
          result.select!{|target| target.dead?} if item.scope_alive == false
      end
      end
    end
    result.select!{|target| !target.dead?} if item.scope_alive == true
    result.select!{|target| target.dead?} if item.scope_alive == false
    for r in item.restrictions
      if r.arity == 1
      result.select!{|target| r.call(target) == true } rescue nil
      else
      result.select!{|target| r.call == true } rescue nil
      end
    end
    if item.scope_all == false
      if item.scope_random == true
      result = ]
      else
      result = ]
      end
    end
    return result
end
end


DFS version
Spoiler: Code                 Ruby:        
#==============================================================================
# ** Advanced Scope v1.1
# This version is compatible with Data File Save, use it only if you're
# using that script. This script must be placed BELOW Data File Save.
#------------------------------------------------------------------------------
# Author: Wecoc (credits are optional)
#------------------------------------------------------------------------------
# Defines new types of scope for items and skills in battle
#------------------------------------------------------------------------------
# $data_items and $data_skills work exactly the same way
# To define the target use:
# $data_items.scope_ally   = true | false # Ally
# $data_items.scope_enemy= true | false # Enemy
# $data_items.scope_all    = true | false # Entire group / Only one
# $data_items.scope_random = true | false # Pick one randomly
# $data_items.scope_user   = true | false # Include user
# $data_items.scope_alive= true | false # Only alive members
# $data_items.scope_dead   = true | false # Only dead members
#------------------------------------------------------------------------------
# $data_items.restriction(&block) # Set custom restriction
# $data_items.restrictions      # Get all custom restrictions
# $data_items.clear_restrictions# Clear all custom restrictions
#==============================================================================

#==============================================================================
# ** Scope Configuration
#==============================================================================

module Scope
#----------------------------------------------------------------------------
# Default Dead Select
#----------------------------------------------------------------------------
# By default if an item only affects members that are alive you can still
# select a dead member, but the item won't have any effect.
# The same happens with items that only affect dead members.
# Set to false if you want to disable that and apply a strict restriction.
#----------------------------------------------------------------------------

DEFAULT_DEAD_SELECT = true

end

#==============================================================================
# ** Array
#==============================================================================

class Array
#--------------------------------------------------------------------------
# * Select!
#--------------------------------------------------------------------------
unless self.respond_to?(:select!)
    def select!(&block)
      result = self.select(&block)
      self.replace(result)
    end
end
end

#==============================================================================
# ** RPG
#==============================================================================

for Klass in
class Klass
   
    ALLY=
    ENEMY =
    ALL   =
    ALIVE =
    DEAD=
    USER=
   
    define_method(:scope_ally)   { @scope_ally |= ALLY.include?(@scope) }
    define_method(:scope_enemy){ @scope_enemy |= ENEMY.include?(@scope) }
    define_method(:scope_all)    { @scope_all |= ALL.include?(@scope) }
    define_method(:scope_random) { @scope_random |= false }
    define_method(:scope_alive){ @scope_alive |= ALIVE.include?(@scope) }
    define_method(:scope_dead)   { @scope_dead |= DEAD.include?(@scope) }
    define_method(:scope_user)   { @scope_user |= USER.include?(@scope) }
    define_method(:scope_rest)   { @scope_rest = [] }
    define_method(:restrictions) { @scope_rest = [] }
   
    def restriction(&block)
      @scope_rest.push(block)
    end
   
    def clear_restrictions
      @scope_rest.clear
    end
   
    def set_scope(ally,enemy,all,random=false,user=true,alive=true,dead=false)
      @scope_ally   = ally
      @scope_enemy= enemy
      @scope_all    = all
      @scope_random = random
      @scope_user   = user
      @scope_alive= alive
      @scope_dead   = dead
    end
end
end

#==============================================================================
# ** Arrow_Base
#==============================================================================

class Arrow_Base < Sprite
attr_reader :user
attr_reader :item
attr_reader :target
attr_reader :targets
#--------------------------------------------------------------------------
# * Initialize
#--------------------------------------------------------------------------
def initialize(viewport, user, item)
    super(viewport)
    self.bitmap = RPG::Cache.windowskin($game_system.windowskin_name)
    self.ox = 16
    self.oy = 64
    self.z = 2500
    @blink_count = 0
    @index = 0
    @help_window = nil
    @user = user
    @item = item
    @targets = target_battlers
    @target = @targets
    update_sprite
end
#--------------------------------------------------------------------------
# * Get index
#--------------------------------------------------------------------------
def index
    return @targets.index(@target) rescue -1
end
#--------------------------------------------------------------------------
# * Set index
#--------------------------------------------------------------------------
def index=(index)
    @target = @targets
end
#--------------------------------------------------------------------------
# * Get selectable targets
#--------------------------------------------------------------------------
def target_battlers
    if @user.is_a?(Game_Actor)
      allies = $game_party.actors.clone
      enemies = $game_troop.enemies.clone
    else
      allies = $game_troop.enemies.clone
      enemies = $game_party.actors.clone
    end
    allies.delete_if {|target| target.hidden}
    enemies.delete_if{|target| target.hidden}
    if @item == nil
      enemies.delete_if {|target| !target.exist?}
      return enemies
    end
    result = []
    if @item.scope_ally == true
      for target in allies
      result.push(target)
      end
    end
    if @item.scope_enemy == true
      for target in enemies
      result.push(target)
      end
    end
    if @item.scope_user == true
      if !result.include?(@user)
      result.push(@user)
      end
    end
    if @item.scope_user == false
      result.delete(@user)
    end
    if @item.scope_alive == true && Scope::DEFAULT_DEAD_SELECT == false
      result.select!{|target| !target.dead?}
    end
    if @item.scope_dead == true && Scope::DEFAULT_DEAD_SELECT == false
      result.select!{|target| target.dead?}
    end
    for r in @item.restrictions
      if r.arity == 1
      result.select!{|target| r.call(target) == true} rescue nil
      else
      result.select!{|target| r.call == true} rescue nil
      end
    end
    return result
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
    update_sprite
    if @help_window != nil
      update_help
    end
    if @target == nil
      self.visible = false
      return
    end
    self.visible = true
    # Next target
    if Input.repeat?(Input::RIGHT)
      $game_system.se_play($data_system.cursor_se)
      self.index = (self.index + 1) % @targets.size
    end
    # Previous target
    if Input.repeat?(Input::LEFT)
      $game_system.se_play($data_system.cursor_se)
      self.index = (self.index - 1) % @targets.size
    end
    # Place arrow over target
    if @target != nil
      self.x = @target.screen_x
      self.y = @target.screen_y
    end
end
#--------------------------------------------------------------------------
# * Update Sprite
#--------------------------------------------------------------------------
def update_sprite
    @blink_count = (@blink_count + 1) % 8
    if @blink_count < 4
      self.src_rect.set(128, 96, 32, 32)
    else
      self.src_rect.set(160, 96, 32, 32)
    end
end
#--------------------------------------------------------------------------
# * Update Help
#--------------------------------------------------------------------------
def update_help
    if @target == nil
      @help_window.set_text("")
      return
    end
    if @target.is_a?(Game_Actor)
      @help_window.set_actor(@target)
    else
      @help_window.set_enemy(@target)
    end
end
end

#==============================================================================
# ** Game_Battler
#==============================================================================

class Game_Battler
#--------------------------------------------------------------------------
# * Check if the skill can be used
#--------------------------------------------------------------------------
alias wecoc_scope_skill_use? skill_can_use? unless $@
def skill_can_use?(skill_id)
    skill = $data_skills
    return false if skill.nil?   # Skill doesn't exist
    return false if !self.exist? # User is hidden or dead
    if self.is_a?(Game_Actor)
      members = $game_party.actors.clone
    else
      members = $game_troop.enemies.clone
    end
    if members.size == 1 # User is the only member and requires an ally
      if skill.user == false && skill.ally == false && skill.enemy == false
      return false
      end
    end
    for r in skill.restrictions
      if r.arity == 1
      members.select!{|target| r.call(target) == true} rescue nil
      else
      members.select!{|target| r.call == true} rescue nil
      end
    end
    return false if members.size == 0
    return wecoc_scope_skill_use?(skill_id)
end
#--------------------------------------------------------------------------
# * Check if the item can be used
#--------------------------------------------------------------------------
def item_can_use?(item_id)
    item = $data_items
    return false if item.nil?    # Item doesn't exist
    return false if !self.exist? # User is hidden or dead
    if self.is_a?(Game_Actor)
      # Party doesn't contain that item
      return false if $game_party.item_number(item_id) == 0
      # Item restrictions (Only menu / battle)
      return false if $game_temp.in_battle&& item.occasion == 2
      return false if !$game_temp.in_battle && item.occasion == 1
      members = $game_party.actors.clone
    else
      members = $game_troop.enemies.clone
    end
    if members.size == 1 # User is the only member and requires an ally
      if item.user == false && item.ally == false && item.enemy == false
      return false
      end
    end
    for r in item.restrictions
      if r.arity == 1
      members.select!{|target| r.call(target) == true} rescue nil
      else
      members.select!{|target| r.call == true} rescue nil
      end
    end
    return false if members.size == 0
    return true
end
end

#==============================================================================
# ** Game_Party
#==============================================================================

class Game_Party
#--------------------------------------------------------------------------
# * Check if the party can use an item
#--------------------------------------------------------------------------
def item_can_use?(item_id)
    for member in $game_party.actors
      if member.item_can_use?(item_id)
      return true
      end
    end
    return false
end
end

#==============================================================================
# ** Scene_Battle
#==============================================================================

class Scene_Battle
#--------------------------------------------------------------------------
# * Select enemy
#--------------------------------------------------------------------------
def start_enemy_select
    item = nil
    if @active_battler.current_action.kind == 1
      item = @skill if @skill != nil
    end
    if @active_battler.current_action.kind == 2
      item = @itemif @item != nil
    end
    @enemy_arrow = Arrow_Base.new(@spriteset.viewport2, @active_battler, item)
    @enemy_arrow.help_window = @help_window
    @actor_command_window.active = false
    @actor_command_window.visible = false
end
#--------------------------------------------------------------------------
# * Select actor
#--------------------------------------------------------------------------
def start_actor_select
    item = nil
    if @active_battler.current_action.kind == 1
      item = @skill if @skill != nil
    end
    if @active_battler.current_action.kind == 2
      item = @itemif @item != nil
    end
    @actor_arrow = Arrow_Base.new(@spriteset.viewport2, @active_battler, item)
    @actor_arrow.index = @actor_index
    @actor_arrow.help_window = @help_window
    @actor_command_window.active = false
    @actor_command_window.visible = false
end
#--------------------------------------------------------------------------
# * Apply skill
#--------------------------------------------------------------------------
def make_skill_action_result
    @skill = $data_skills[@active_battler.current_action.skill_id]
    unless @active_battler.current_action.forcing
      unless @active_battler.skill_can_use?(@skill.id)
      $game_temp.forcing_battler = nil
      @phase4_step = 1
      return
      end
    end
    @active_battler.sp -= @skill.sp_cost
    @status_window.refresh
    @help_window.set_text(@skill.name, 1)
    @animation1_id = @skill.animation1_id
    @animation2_id = @skill.animation2_id
    @common_event_id = @skill.common_event_id
    @target_battlers.clear
    @target_battlers = set_target_battlers(@skill)
    for target in @target_battlers
      target.skill_effect(@active_battler, @skill)
    end
end
#--------------------------------------------------------------------------
# * Apply item
#--------------------------------------------------------------------------
def make_item_action_result
    @item = $data_items[@active_battler.current_action.item_id]
    unless @active_battler.item_can_use?(@item.id)
      @phase4_step = 1
      return
    end
    if @item.consumable
      $game_party.lose_item(@item.id, 1)
    end
    @help_window.set_text(@item.name, 1)
    @animation1_id = @item.animation1_id
    @animation2_id = @item.animation2_id
    @common_event_id = @item.common_event_id
    index = @active_battler.current_action.target_index
    target = $game_party.smooth_target_actor(index)
    @target_battlers.clear
    @target_battlers = set_target_battlers(@item)
    for target in @target_battlers
      target.item_effect(@item)
    end
end
#--------------------------------------------------------------------------
# * Get available targets for an item or skill
#--------------------------------------------------------------------------
def set_target_battlers(item)
    if @active_battler.is_a?(Game_Actor)
      allies = $game_party.actors.clone
      enemies = $game_troop.enemies.clone
    else
      allies = $game_troop.enemies.clone
      enemies = $game_party.actors.clone
    end
    index = @active_battler.current_action.target_index
    result = []
    if item.scope_ally == true
      for target in allies
      result.push(target)
      end
    end
    if item.scope_enemy == true
      for target in enemies
      result.push(target)
      end
    end
    if item.scope_user == true
      if !result.include?(@active_battler)
      result.push(@active_battler)
      end
    end
    if item.scope_user == false
      result.delete(@active_battler)
    end
    if item.scope_all == false
      if item.scope_random == true
      result.select!{|target| !target.dead?} if item.scope_alive == true
      result.select!{|target| target.dead?} if item.scope_alive == false
      else
      if Scope::DEFAULT_DEAD_SELECT == false
          result.select!{|target| !target.dead?} if item.scope_alive == true
          result.select!{|target| target.dead?} if item.scope_alive == false
      end
      end
    end
    result.select!{|target| !target.dead?} if item.scope_alive == true
    result.select!{|target| target.dead?} if item.scope_alive == false
    for r in item.restrictions
      if r.arity == 1
      result.select!{|target| r.call(target) == true} rescue nil
      else
      result.select!{|target| r.call == true} rescue nil
      end
    end
    if item.scope_all == false
      if item.scope_random == true
      result = ]
      else
      result = ]
      end
    end
    return result
end
end


Advanced Instructions

Spoiler: Custom restriction examplesTargets must have a specific class ID
$data_items.restriction {|target| target.is_a?(Game_Actor) && target.class_id == 3}

Target only certain enemy IDs
$data_items.restriction {|target| target.is_a?(Game_Enemy) && .include?(target.id) }

Target battlers with more than 50% HP
$data_items.restriction {|target| target.hp >= (target.maxhp * 50 / 100) }

Target battlers that have a certain state
$data_items.restriction {|target| target.state?(2) }

Target actors that know a certain skill
$data_items.restriction {|target| target.skill_learn?(50) }

Target enemies that know a certain skill
$data_items.restriction {|target| target.actions.any?{|action| action.skill_id == 50 }}

Those should be defined both when creating a new game and when loading, but if you're using DFS you only have to define this once wherever you want.
FAQ

Spoiler: FAQ- I want to apply a new restriction from an event script call, but those lines are too long.
Yeah, all my examples are like this
                Code:        
$data_items.restriction { |target| (ACTION) }


but you can separate it like this
                Code:        
$data_items.restriction do |target|
(ACTION)
end


- I want to make a "Random Ally" skill, but when there's only one actor (alive) I don't want that skill to be active, since that wouldn't be random at all.

Good point. You can do that with a custom restriction like this
                Code:        
$data_items.restriction do
n = 0 ; for target in $game_party.actors
    n += 1 if target.exist?
end
(n > 1)
end


Monster-based Scope (AddOn)

This AddOn allows to make some enemies untargetable based on a specific condition. That condition can be the ID of the attacker, his equipment, a switch or any other condition. The fact it cannot be selected implies that if neither meets the condition, the attack and offensive abilities will be directly deactivated for the actor in question.

The only configurable part is the module Monster_Scope, and I made some examples on the instructions of the script.

Normal version (independent)
Spoiler: Code                 Ruby:        
#==============================================================================
# ** Monster-based Scope v1.1
#------------------------------------------------------------------------------
# Author: Wecoc (no credits required)
#------------------------------------------------------------------------------
# This script allows to make some enemies untargetable based on a specific
# condition. That condition can be the ID of the attacker, his equipment,
# a switch or any other condition. The fact it cannot be selected implies
# that if neither meets the condition, the attack and offensive abilities
# will be directly deactivated for the actor in question.
#------------------------------------------------------------------------------
# It allows multiple conditions, simply define them as an array
#   1 => ["actor.id == 1", "actor.weapon_id == 1", "actor.id == 1"]
# When defined by string, the condition is the same
# When defined by array, the first one is for attack, second for skills and
# third for items.
#------------------------------------------------------------------------------
# To use this you only have to define the conditions as an eval on the constant
# SCOPE_CONDITION in the very start of the script.
#   ID monster => "condition"
# Condition examples
#   # Can only be attacked by the actor with ID 1
#   actor.id == 1
#   # Can only be attacked if the attacker has weapon with ID 1 equipped
#   actor.weapon_id == 1
# Conditions accept two shortcuts; 'actor' and 'target'
#==============================================================================

module Monster_Scope
# Set here the condition for each enemy ID
SCOPE_CONDITION = {
    1 => "actor.id == 1",
    2 => "actor.weapon_id == 1"
}
end

class Game_Actor
alias monster_scope_skill_use? skill_can_use? unless $@
def skill_can_use?(skill_id)
    if .include?($data_skills.scope)
      if $scene.is_a?(Scene_Battle) && !$scene.can_select_any_enemy?(1)
      return false
      end
    end
    monster_scope_skill_use?(skill_id)
end
end

class Game_Party
alias monster_scope_item_use? item_can_use? unless $@
def item_can_use?(item_id)
    if .include?($data_items.scope)
      if $scene.is_a?(Scene_Battle) && !$scene.can_select_any_enemy?(2)
      return false
      end
    end
    monster_scope_item_use?(item_id)
end
end

class Scene_Battle
def can_select_any_enemy?(kind=0)
    # Get if any enemy can be selected
    return if @active_battler.nil? || @active_battler.is_a?(Game_Enemy)
    for target in $game_troop.enemies
      return true if !Monster_Scope::SCOPE_CONDITION.keys.include?(target.id)
      if Monster_Scope::SCOPE_CONDITION.is_a?(Array)
      e = Monster_Scope::SCOPE_CONDITION
      else
      e = Monster_Scope::SCOPE_CONDITION
      end
      result = instance_eval("actor = @active_battler;" + e)
      return true if result == true
    end
    return false
end

def get_selectable_enemies(kind=0)
    # Set target battlers based on the monster scope condition
    return if @active_battler.nil? || @active_battler.is_a?(Game_Enemy)
    selectable_enemies = []
    for target in $game_troop.enemies
      index = $game_troop.enemies.index(target)
      if Monster_Scope::SCOPE_CONDITION.keys.include?(target.id)
      if Monster_Scope::SCOPE_CONDITION.is_a?(Array)
          e = Monster_Scope::SCOPE_CONDITION
      else
          e = Monster_Scope::SCOPE_CONDITION
      end
      result = instance_eval("actor = @active_battler;" + e)
      selectable_enemies.push(index) if result == true
      else
      selectable_enemies.push(index)
      end
    end
    return selectable_enemies
end

def start_enemy_select
    targets = get_selectable_enemies(@active_battler.current_action.kind)
    @enemy_arrow = Arrow_Enemy.new(@spriteset.viewport1, targets)
    @enemy_arrow.help_window = @help_window
    @actor_command_window.active = false
    @actor_command_window.visible = false
end

alias monster_scope_next phase3_next_actor unless $@
def phase3_next_actor
    @actor_command_window.refresh
    monster_scope_next
    # Disable Attack command when none enemies can be selected (display)
    if !@active_battler.nil? && !can_select_any_enemy?(0)
      @actor_command_window.disable_item(0)
    end
end

alias monster_scope_prior phase3_prior_actor unless $@
def phase3_prior_actor
    @actor_command_window.refresh
    monster_scope_prior
    # Disable Attack command when none enemies can be selected (display)
    if !@active_battler.nil? && !can_select_any_enemy?(0)
      @actor_command_window.disable_item(0)
    end
end

alias monster_scope_phase3_upd update_phase3_basic_command unless $@
def update_phase3_basic_command
    # Disable Attack command when none enemies can be selected
    if Input.trigger?(Input::C)
      if @actor_command_window.index == 0
      if !@active_battler.nil? && !can_select_any_enemy?(0)
          $game_system.se_play($data_system.buzzer_se)
          return
      end
      end
    end
    monster_scope_phase3_upd
end
end

class Arrow_Enemy < Arrow_Base
def initialize(viewport, targets=nil)
    targets = (0...$game_troop.enemies.size).to_a if targets == nil
    @targets = targets
    super(viewport)
end
def exist?
    return self.enemy.exist? && @targets.include?(self.enemy.index)
end
def update
    super
    $game_troop.enemies.size.times do
      break if self.exist?
      @index += 1
      @index %= $game_troop.enemies.size
    end
    if Input.repeat?(Input::RIGHT)
      $game_system.se_play($data_system.cursor_se)
      $game_troop.enemies.size.times do
      @index += 1
      @index %= $game_troop.enemies.size
      break if self.exist?
      end
    end
    if Input.repeat?(Input::LEFT)
      $game_system.se_play($data_system.cursor_se)
      $game_troop.enemies.size.times do
      @index += $game_troop.enemies.size - 1
      @index %= $game_troop.enemies.size
      break if self.exist?
      end
    end
    if self.enemy != nil
      self.x = self.enemy.screen_x
      self.y = self.enemy.screen_y
    end
end
end


Advanced Scope version
Spoiler: Code                 Ruby:        
#==============================================================================
# ** Monster-based Scope v1.1
#------------------------------------------------------------------------------
# Author: Wecoc (no credits required)
# This version requires the script Advanced Scope
#------------------------------------------------------------------------------
# This script allows to make some enemies untargetable based on a specific
# condition. That condition can be the ID of the attacker, his equipment,
# a switch or any other condition. The fact it cannot be selected implies
# that if neither meets the condition, the attack and offensive abilities
# will be directly deactivated for the actor in question.
#------------------------------------------------------------------------------
# It allows multiple conditions, simply define them as an array
#   1 => ["actor.id == 1", "actor.weapon_id == 1", "actor.id == 1"]
# When defined by string, the condition is the same
# When defined by array, the first one is for attack, second for skills and
# third for items.
#------------------------------------------------------------------------------
# To use this you only have to define the conditions as an eval on the constant
# SCOPE_CONDITION in the very start of the script.
#   ID monster => "condition"
# Condition examples
#   # Can only be attacked by the actor with ID 1
#   actor.id == 1
#   # Can only be attacked if the attacker has weapon with ID 1 equipped
#   actor.weapon_id == 1
# Conditions accept two shortcuts; 'actor' and 'target'
#==============================================================================

module Monster_Scope
# Set here the condition for each enemy ID
SCOPE_CONDITION = {
    1 => "actor.id == 1",
    2 => "actor.weapon_id == 1"
}
end

class Game_Actor
alias monster_scope_skill_use? skill_can_use? unless $@
def skill_can_use?(skill_id)
    if $data_skills.scope_enemy
      if $scene.is_a?(Scene_Battle) && !$scene.can_select_any_enemy?(1)
      return false
      end
    end
    monster_scope_skill_use?(skill_id)
end
end

class Game_Party
alias monster_scope_item_use? item_can_use? unless $@
def item_can_use?(item_id)
    if $data_items.scope_enemy
      if $scene.is_a?(Scene_Battle) && !$scene.can_select_any_enemy?(2)
      return false
      end
    end
    monster_scope_item_use?(item_id)
end
end

class Arrow_Base < Sprite
alias monster_scope_ini initialize unless $@
def initialize(viewport, user, item, targets=nil)
    monster_scope_ini(viewport, user, item)
    if item.nil? && !targets.nil?
      @targets = targets
      @target = @targets
      update_sprite
    end
end
end

class Scene_Battle
def can_select_any_enemy?(kind=0)
    # Get if any enemy can be selected
    return if @active_battler.nil? || @active_battler.is_a?(Game_Enemy)
    for target in $game_troop.enemies
      return true if !Monster_Scope::SCOPE_CONDITION.keys.include?(target.id)
      if Monster_Scope::SCOPE_CONDITION.is_a?(Array)
      e = Monster_Scope::SCOPE_CONDITION
      else
      e = Monster_Scope::SCOPE_CONDITION
      end
      result = instance_eval("actor = @active_battler;" + e)
      return true if result == true
    end
    return false
end

def get_selectable_enemies(kind=0)
    # Set target battlers based on the monster scope condition
    return if @active_battler.nil? || @active_battler.is_a?(Game_Enemy)
    selectable_enemies = []
    for target in $game_troop.enemies
      index = $game_troop.enemies.index(target)
      if Monster_Scope::SCOPE_CONDITION.keys.include?(target.id)
      if Monster_Scope::SCOPE_CONDITION.is_a?(Array)
          e = Monster_Scope::SCOPE_CONDITION
      else
          e = Monster_Scope::SCOPE_CONDITION
      end
      result = instance_eval("actor = @active_battler;" + e)
      selectable_enemies.push(target) if result == true
      else
      selectable_enemies.push(target)
      end
    end
    return selectable_enemies
end

alias monster_scope_enemy_select start_enemy_select
def start_enemy_select
    if @active_battler.current_action.kind == 0 # Attack
      targets = get_selectable_enemies(@active_battler.current_action.kind)
      @enemy_arrow = Arrow_Base.new(@spriteset.viewport2,
      @active_battler, nil, targets)
      @enemy_arrow.help_window = @help_window
      @actor_command_window.active = false
      @actor_command_window.visible = false
      return
    end
    monster_scope_enemy_select
end

alias monster_scope_next phase3_next_actor unless $@
def phase3_next_actor
    @actor_command_window.refresh
    monster_scope_next
    # Disable Attack command when none enemies can be selected (display)
    if !@active_battler.nil? && !can_select_any_enemy?(0)
      @actor_command_window.disable_item(0)
    end
end

alias monster_scope_prior phase3_prior_actor unless $@
def phase3_prior_actor
    @actor_command_window.refresh
    monster_scope_prior
    # Disable Attack command when none enemies can be selected (display)
    if !@active_battler.nil? && !can_select_any_enemy?(0)
      @actor_command_window.disable_item(0)
    end
end

alias monster_scope_phase3_upd update_phase3_basic_command unless $@
def update_phase3_basic_command
    # Disable Attack command when none enemies can be selected
    if Input.trigger?(Input::C)
      if @actor_command_window.index == 0
      if !@active_battler.nil? && !can_select_any_enemy?(0)
          $game_system.se_play($data_system.buzzer_se)
          return
      end
      end
    end
    monster_scope_phase3_upd
end

def set_target_battlers(item)
    if @active_battler.is_a?(Game_Actor)
      allies = $game_party.actors.clone
      enemies = $game_troop.enemies.clone
    else
      allies = $game_troop.enemies.clone
      enemies = $game_party.actors.clone
    end
    index = @active_battler.current_action.target_index
    result = []
    if item.scope_ally == true
      for target in allies
      result.push(target)
      end
    end
    if item.scope_enemy == true
      for target in enemies
      result.push(target)
      end
    end
    if item.scope_user == true
      if !result.include?(@active_battler)
      result.push(@active_battler)
      end
    end
    if item.scope_user == false
      result.delete(@active_battler)
    end
    if item.scope_all == false
      if item.scope_random == true
      result.select!{|target| !target.dead?} if item.scope_alive == true
      result.select!{|target| target.dead?} if item.scope_alive == false
      else
      if Scope::DEFAULT_DEAD_SELECT == false
          result.select!{|target| !target.dead?} if item.scope_alive == true
          result.select!{|target| target.dead?} if item.scope_alive == false
      end
      end
    end
    result.select!{|target| !target.dead?} if item.scope_alive == true
    result.select!{|target| target.dead?} if item.scope_alive == false
    for r in item.restrictions
      if r.arity == 1
      result.select!{|target| r.call(target) == true } rescue nil
      else
      result.select!{|target| r.call == true } rescue nil
      end
    end
    # --- Monster Scope ---
    kind = 0 # Default
    kind = 1 if item.is_a?(RPG::Skill); kind = 2 if item.is_a?(RPG::Item)
    selectable_enemies = $scene.get_selectable_enemies(kind)
    for target in result
      if target.is_a?(Game_Enemy) && !selectable_enemies.include?(target)
      result.delete(target)
      end
    end
    # ------
    if item.scope_all == false
      if item.scope_random == true
      result = ]
      else
      result = ]
      end
    end
    return result
end
end


I hope you like this. It's insane how long my posts tend to be
data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7


本贴来自国际rpgmaker官方论坛作者:Wecoc处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/advanced-scopes-more-target-options-for-battlers.139759/
页: [1]
查看完整版本: Advanced Scopes - More target options for battlers