public

Rpg Maker Developers Group

Simple enough for a child, powerful enough for a developer

2 Followers

XPAdvanced Scopes - More target options for battlers

BMM Archive · July 16, 2026

Preserved forum archive. This topic stores the original first post and locally mirrored RPG Maker Web attachments when available. It is posted by the BMMPlay archive account, not by the original creator.

Original Source

  • Original title: Advanced Scopes - More target options for battlers
  • Original author: Wecoc
  • Original date: August 20, 2021
  • Source thread: https://forums.rpgmakerweb.com/threads/advanced-scopes-more-target-options-for-battlers.139759/
  • Source forum path: Game Development Engines > Ruby Game System (RGSS) Scripts > RGSS Scripts (RMXP)

Summary

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:

Archived First Post

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)
Ruby:
#==============================================================================
# ** [XP] Advanced Scope v1.1
#------------------------------------------------------------------------------
# Author: Wecoc (credits are optional)
#------------------------------------------------------------------------------
# Defines new types of scope for items and skills in battle
#------------------------------------------------------------------------------
# $data_items[ID] and $data_skills[ID] work exactly the same way
# To define the target use:
# $data_items[ID].scope_ally   = true | false # Ally
# $data_items[ID].scope_enemy  = true | false # Enemy
# $data_items[ID].scope_all    = true | false # Entire group / Only one
# $data_items[ID].scope_random = true | false # Pick one randomly
# $data_items[ID].scope_user   = true | false # Include user
# $data_items[ID].scope_alive  = true | false # Only alive members
# $data_items[ID].scope_dead   = true | false # Only dead members
#------------------------------------------------------------------------------
# $data_items[ID].restriction(&block) # Set custom restriction
# $data_items[ID].restrictions        # Get all custom restrictions
# $data_items[ID].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 [RPG::Item, RPG::Skill]
  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 = [3, 4, 5, 6].include?(@scope) if @scope_ally == nil
      return @scope_ally
    end
    #--------------------------------------------------------------------------
    # * For Enemies
    #--------------------------------------------------------------------------
    def scope_enemy
      @scope_enemy = [1, 2].include?(@scope) if @scope_enemy == nil
      return @scope_enemy
    end
    #--------------------------------------------------------------------------
    # * For All Party/Troop Members
    #--------------------------------------------------------------------------
    def scope_all
      @scope_all = [2, 4, 6].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 = [3, 4, 5, 6, 7].include?(@scope) if @scope_user == nil
      else
        @scope_user = [3, 4, 7].include?(@scope) if @scope_user == nil
      end
      return @scope_user
    end
    #--------------------------------------------------------------------------
    # * Only Alive
    #--------------------------------------------------------------------------
    def scope_alive
      @scope_alive = [1, 2, 3, 4, 7].include?(@scope) if @scope_alive == nil
      return @scope_alive
    end
    #--------------------------------------------------------------------------
    # * Only Dead
    #--------------------------------------------------------------------------
    def scope_dead
      @scope_dead = [5, 6].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[0]
    update_sprite
  end
  #--------------------------------------------------------------------------
  # * Get index
  #--------------------------------------------------------------------------
  def index
    return @targets.index(@target) rescue -1
  end
  #--------------------------------------------------------------------------
  # * Set index
  #--------------------------------------------------------------------------
  def index=(index)
    @target = @targets[index]
  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[skill_id]
    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[item_id]
    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 = @item  if @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 = @item  if @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 = [result[rand(result.size)]]
      else
        result = [result[index]]
      end
    end
    return result
  end
end

DFS version
Ruby:
#==============================================================================
# ** [XP] 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[ID] and $data_skills[ID] work exactly the same way
# To define the target use:
# $data_items[ID].scope_ally   = true | false # Ally
# $data_items[ID].scope_enemy  = true | false # Enemy
# $data_items[ID].scope_all    = true | false # Entire group / Only one
# $data_items[ID].scope_random = true | false # Pick one randomly
# $data_items[ID].scope_user   = true | false # Include user
# $data_items[ID].scope_alive  = true | false # Only alive members
# $data_items[ID].scope_dead   = true | false # Only dead members
#------------------------------------------------------------------------------
# $data_items[ID].restriction(&block) # Set custom restriction
# $data_items[ID].restrictions        # Get all custom restrictions
# $data_items[ID].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 [RPG::Item, RPG::Skill]
  class Klass
    
    ALLY  = [3, 4, 5, 6]
    ENEMY = [1, 2]
    ALL   = [2, 4, 6]
    ALIVE = [1, 2, 3, 4, 7]
    DEAD  = [5, 6]
    USER  = [3, 4, 5, 6, 7]
    
    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[0]
    update_sprite
  end
  #--------------------------------------------------------------------------
  # * Get index
  #--------------------------------------------------------------------------
  def index
    return @targets.index(@target) rescue -1
  end
  #--------------------------------------------------------------------------
  # * Set index
  #--------------------------------------------------------------------------
  def index=(index)
    @target = @targets[index]
  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[skill_id]
    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[item_id]
    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 = @item  if @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 = @item  if @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 = [result[rand(result.size)]]
      else
        result = [result[index]]
      end
    end
    return result
  end
end

Advanced Instructions

Targets must have a specific class ID
$data_items[1].restriction {|target| target.is_a?(Game_Actor) && target.class_id == 3}

Target only certain enemy IDs
$data_items[1].restriction {|target| target.is_a?(Game_Enemy) && [20, 23, 30, 31].include?(target.id) }

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

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

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

Target enemies that know a certain skill
$data_items[1].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

- 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[ID].restriction { |target| (ACTION) }

but you can separate it like this
Code:
$data_items[ID].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[1].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)
Ruby:
#==============================================================================
# ** [XP] 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 [1,2].include?($data_skills[skill_id].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 [1,2].include?($data_items[item_id].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[target.id].is_a?(Array)
        e = Monster_Scope::SCOPE_CONDITION[target.id][kind]
      else
        e = Monster_Scope::SCOPE_CONDITION[target.id]
      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[target.id].is_a?(Array)
          e = Monster_Scope::SCOPE_CONDITION[target.id][kind]
        else
          e = Monster_Scope::SCOPE_CONDITION[target.id]
        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
Ruby:
#==============================================================================
# ** [XP] Monster-based Scope v1.1 [Advanced Scope]
#------------------------------------------------------------------------------
# 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[skill_id].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[item_id].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[0]
      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[target.id].is_a?(Array)
        e = Monster_Scope::SCOPE_CONDITION[target.id][kind]
      else
        e = Monster_Scope::SCOPE_CONDITION[target.id]
      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[target.id].is_a?(Array)
          e = Monster_Scope::SCOPE_CONDITION[target.id][kind]
        else
          e = Monster_Scope::SCOPE_CONDITION[target.id]
        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 = [result[rand(result.size)]]
      else
        result = [result[index]]
      end
    end
    return result
  end
end

I hope you like this. It's insane how long my posts tend to be

Downloads / Referenced Files

Log in to download

Log in, then follow the RPG Maker Developers Group to see these download links.

Log in to download

License / Terms Note

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.

Creator Claims / Removal

If you are the original creator and want this listing reassigned, edited, or removed, join BMMPlay and contact the moderators with proof that matches the original RPG Maker Web profile, linked GitHub, itch.io page, or another public creator identity.

#rgss#script-archive

Replies (0)

No replies yet.

0 replies 2 views

Log in to reply.

User Avatar