10-08-2024, 02:11 PM
(This post was last modified: 10-08-2024, 02:13 PM by DerVVulfman.)
Collateral Attacks
Version: 1
Introduction
This system is designed to allow an attack to apply damage to one (or more) additional targets. The targets may be random, all encompassing, or fixed to the same principle target attacked. Likewise, the secondary strikes may be limited to random chance, or require that the initial attack succeed.
And then there's an option whereby the secondary strikes are at half damage.
This script was inspired by Bennerdeben of Save-Point who requested advice on how to generate additional random strikes for a given attack.
Script
Content Hidden
Code:
#==============================================================================
# ** Collateral Attacks
#------------------------------------------------------------------------------
# version 1.0
# by DerVVulfman
# 07-15-2020 (MM-DD-YYYY)
# RGSS / RPGMaker XP
#==============================================================================
#
# INTRODUCTION:
#
# This system is designed to allow an attack to apply damage to one (or more)
# additional targets. The targets may be random, all encompassing, or fixed to
# the same principle target attacked. Likewise, the secondary strikes may be
# limited to random chance, or require that the initial attack succeed.
#
# And then there's an option whereby the secondary strikes are at half damage.
#
# This script was inspired by Bennerdeben of Save-Point who requested advice
# on how to generate additional random strikes for a given attack.
#
#
#------------------------------------------------------------------------------
#
# INSTALLATION:
#
# Place this script below Scene_Debug and above Main. And place it below any
# script that alters any battlesystem script.
#
# If you want to use the 'half' collateral damage option, small edits need to
# be made to your Game_Battler code (described further below)
#
#
#------------------------------------------------------------------------------
#
# USAGE:
#
# Collateral attacks are essentially a secondary strike against another enemy
# target. However, it can also be a secondary bonus given to a fellow member
# of the party if the initial target was an ally. The script does recognize
# target scopes. And target scopes 1 (one enemy) and 2 (all enemies) are the
# only ones that perform collateral strikes on enemy troops. Surprise!
#
# Within the Collateral module, you can define if a collateral strike is per-
# formed when using a defined WEAPON, SKILL or an ITEM. And collateral strikes
# of a melee sort may be performed by a defined ACTOR or ENEMY in general. Do
# know that an actor defined to deliver collateral strikes of one variety will
# be subject to the collateral strikes of weapons, skills or items if defined.
#
# Example: Margie is set to deliver a 2nd strike on all targets, but is using
# a sword defined to deliver a 2nd strike on one victim. The sword's
# collateral attack supercedes the one defined for Margie.
#
# Note: ENEMY collateral strikes are melee only. Enemies using skills do
# not deliver skill collateral strikes unless the skill is defined.
#
# * * *
#
# When you define a Skill, Item or the like that delivers a collateral attack,
# you reference said content by its ID within their related database. By that,
# you would refer to the default 'Greater Thunder' as ID #17 within the Skills
# database.
#
# EX: SKILL[17]
#
# Each of the defined collateral attack objects is defined the same way, only
# differing between which database they belong. Likewise, each collateral at-
# tack object is assigned an array with one(1) to four(4) parameters. The syn-
# tax for any object and the paramters are as follows:
#
# EX: Object[ID] = [ Type, Chance, Must-Hit, Halved ]
#
# * Object: Defined array of ACTOR, ENEMY, WEAPON, SKILL, ITEM
# * ID: Database ID for a given collateral attack Object
#
# * Type: Type of collateral attack responce
# * Chance: (Optional) The chance that a collateral attack will occur
# * Must-Hit: (Optional) Defines if the initial strike must succeed
# * Halved: (Optional) Defines if collateral strikes give half-damage
#
# * Type
# ----
# The type of collateral attack relates to who is attacked after the initial
# strike. It can be the same target(s), or all others of the party. You have
# four options shown below:
# 0 = Identical target(s) as the initial attack
# 1 = One random target separate from initial attack
# 2 = All targets other than those of the initial attack
# 3 = All targets
#
# * Chance
# ------
# (Optional) This determines the chance of a collateral attack taking place
# in a range of (0-100). Granted, defining a 0 chance makes no sense. If the
# value is left out, the default chance is 100 (ergo 100%).
#
# If you have values (Must-Hit and/or Halved) defined, the chance value must
# be defined.
#
# * Must-Hit
# --------
# (Optional) This is a boolean (or true/false) value that indicates if the
# initial attack must succeed to go any further. If it is set to false, even
# a 'miss' will trigger collateral damage. But if set to true, then the ini-
# tial attack must succeed. Please be aware that changes to a target's state
# does count as a hit. And if the must-hit value is left out, the default
# setting assumes 'false' and allows collateral strikes even after a miss.
#
# If you have a Halved value defined, the Must-Hit value must also be set.
#
# * Halved
# ------
# (Optional) This is a boolean (or true/false) value that indicates if the
# damage resulting from a collateral attack would only be half of what it
# it would normally have been. Damage is individually calculated before this
# option takes place. And if the Halved value is left out, the default value
# for this setting is 'false' and assumes full damage.
#
# For this option to function, you must apply edits to Game_Battler itself.
#
#
#------------------------------------------------------------------------------
#
# HALVED-DAMAGE - DIRECT EDITS INTO GAME_BATTLER:
#
# Most every method within RPGMaker XP are small and concise. Sadly, some of
# the methods are large. And inserting code to affect how certain factors are
# calculated cannot be performed without direct edits or full-blown rewrites.
#
# And among these methods, the 'effect' calculations within Game_Battler fall
# into that category. Fortunately, the edits to be described are very rudimen-
# tary and small.
#
# Edits for melee damage
# ----------------------
#
# To allow collateral damage to be halved with regard to melee damage, you'll
# need to examine the 'attack_effect' script in "Game_Battler 3". Once you get
# past line 71 of the 'dispersion' effect (where it adds random values and bo-
# nuses), you will add the following lines:
#
# if attacker.collateral_performed
# if attacker.collateral_halved
# self.damage /= 2
# end
# end
#
# Ergo, it should appear like this in your default 'attack_effect" method:
#
# . . . . .
# # Dispersion
# if self.damage.abs > 0
# amp = [self.damage.abs * 15 / 100, 1].max
# self.damage += rand(amp+1) + rand(amp+1) - amp
# end
# if attacker.collateral_performed
# if attacker.collateral_halved
# self.damage /= 2
# end
# end
# # Second hit detection
# eva = 8 * self.agi / attacker.dex + self.eva
# . . . . .
#
# I would suggest adding extra comments around the addition so it can be found
# if the need arises.
#
#
# Edits for skill damage
# ----------------------
#
# To allow collateral damage to be halved with regard to skill damage, you'll
# need to examine the 'skill_effect' script in "Game_Battler 3". Once you get
# past line 156 of the 'dispersion' effect (where it adds bonuses and random
# values), you will add the following lines:
#
# if user.collateral_performed
# if user.collateral_halved
# self.damage /= 2
# end
# end
#
# Ergo, it should appear like this in your default 'skill_effect" method:
#
# . . . . .
# # Dispersion
# if skill.variance > 0 and self.damage.abs > 0
# amp = [self.damage.abs * skill.variance / 100, 1].max
# self.damage += rand(amp+1) + rand(amp+1) - amp
# end
# if user.collateral_performed
# if user.collateral_halved
# self.damage /= 2
# end
# end
# # Second hit detection
# eva = 8 * self.agi / user.dex + self.eva
# . . . . .
#
# The edit doesn't look much different than the edit for melee attacks, with
# 'user' being given rather than 'attacker'. Do realize the line number given
# is based on an unedited version of Game_Battler 3.
#
# I would suggest adding extra comments around the addition so it can be found
# if the need arises.
#
#
# Edits for item damage
# ---------------------
#
# To allow collateral damage to be halved with regard to item damage, you will
# need to examine the 'item_effect' script in "Game_Battler 3". Just like the
# other edits, it can be placed after the 'dispersion' effect. But it may look
# cleaner for the below edit to be placed after line 257 of Game_Battler 3's
# 'negative recovery' test:
#
# if item.collateral_halved
# recover_hp /= 2
# recover_sp /= 2
# end
#
# Ergo, it should appear like this in your default 'item_effect" method:
#
# . . . . .
# # If recovery code is negative
# if recover_hp < 0
# # Guard correction
# if self.guarding?
# recover_hp /= 2
# end
# end
# if item.collateral_halved
# recover_hp /= 2
# recover_sp /= 2
# end
# # Set damage value and reverse HP recovery amount
# self.damage = -recover_hp
# . . . . .
#
# This edit is slightly different as items allow for the recovery of damage to
# SP as well as HP scores. And the condition being checked is if the item has
# a collateral_halved flag set to true. Item damage resulting from RPGMaker XP
# is not attributed to any one actor, so an addition was made to the innate
# RPG::Item class itself, adding this flag.
#
# And again, I would suggest adding extra comments for tracking purposes.
#
#
#------------------------------------------------------------------------------
#
# COMPATIBILITY:
#
# Fairly compatible for RPGMaker XP systems other than the optional direct
# edits described. However, said edits are not necessary IF you choose not
# to employ half-damage from collateral strikes.
#
#
#==============================================================================
#
# TERMS AND CONDITIONS:
#
# Free to use, even in commercial projects. However, I will need some form
# of due credit for both myself and Bennerdeben... even if but a mere men-
# tion in some end titles.
#
#==============================================================================
module Collateral
#--------------------------------------------------------------------------
ENEMY, ACTOR, WEAPON, SKILL, ITEM = {}, {}, {}, {}, {} # DO NOT TOUCH
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# TYPE:
# 0 = Identical target(s) as the initial attack
# 1 = One random target separate from initial attack
# 2 = All targets other than those of the initial attack
# 3 = All targets
#--------------------------------------------------------------------------
# ENEMIES
# ------------------------------------------
# ID Type Chance Must Hit Halved
#======== ==== ====== ======== ======
ENEMY[1] = [ 1, 100, true] # Ghost do 2nd atk on good hit
# ACTORS
# ------------------------------------------
# ID Type Chance Must Hit Halved
#======== ==== ====== ======== ======
ACTOR[7] = [ 0, 99, false, true ] # Gloria gets 2nd hit at 1/2
# WEAPONS
# ------------------------------------------
# ID Type Chance Must Hit Halved
#======== ==== ====== ======== ======
WEAPON[1] = [ 0 ] # Sword1 gets 2nd hit
WEAPON[2] = [ 0, 50 ] # Sword2 has 50% for 2nd hit
# SKILLS
# ------------------------------------------
# ID Type Chance Must Hit Halved
#======== ==== ====== ======== ======
SKILL[1] = [ 3, 50, true, true ] # Heal all 50% chance at 1/2
SKILL[57] = [ 1, 99, false, true ] # CrossCut hits another halved
SKILL[58] = [ 2, 99, false, false ] # Feint hits all others
# ITEMS
# ------------------------------------------
# ID Type Chance Must Hit Halved
#======== ==== ====== ======== ======
ITEM[8] = [ 3, 50, false, true ] # 50% heal others at 1/2 power
ITEM[11] = [ 2, 100, false ] # Antidote works on all others
end
#==============================================================================
# ** Game_Battler
#------------------------------------------------------------------------------
# This class deals with battlers. It's used as a superclass for the Game_Actor
# and Game_Enemy classes.
#==============================================================================
class Game_Battler
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias collateral_initialize initialize
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_reader :state_changed # State changed
attr_accessor :collateral_flag # Collateral damage flag
attr_accessor :collateral_type # Collateral responce type
attr_accessor :collateral_hit # Collateral must hit flag
attr_accessor :collateral_halved # Collateral damage halved
attr_accessor :collateral_performed # Collateral prevent looping
attr_accessor :collateral_missed # Collateral damage prevented
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
#
# Perform the original method
collateral_initialize
#
# New flags in play
@collateral_flag = false
@collateral_type = 0
@collateral_hit = false
@collateral_halved = false
@collateral_performed = false
@collateral_missed = false
#
end
end
#==============================================================================
# ** RPG::Item
#------------------------------------------------------------------------------
# This class contains the RPGXP data structure for items.
#==============================================================================
class RPG::Item
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias collateral_rpg_item_initialize initialize
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
attr_accessor :collateral_halved # Collateral damage halved
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
#
# Perform the original method
collateral_rpg_item_initialize
#
# New flags in play
@collateral_halved = false
#
end
end
#==============================================================================
# ** Scene_Battle
#------------------------------------------------------------------------------
# This class performs battle screen processing.
#==============================================================================
class Scene_Battle
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias collateral_update_phase4_step2 update_phase4_step2
alias collateral_make_basic_action_result make_basic_action_result
alias collateral_make_skill_action_result make_skill_action_result
alias collateral_make_item_action_result make_item_action_result
alias collateral_update_phase4_step3 update_phase4_step3
alias collateral_update_phase4_step6 update_phase4_step6
#--------------------------------------------------------------------------
# * Frame Update (main phase step 2 : start action)
#--------------------------------------------------------------------------
def update_phase4_step2
#
@active_battler.collateral_flag = false # Clear the flags
@active_battler.collateral_type = 0 # at battle attack start
@active_battler.collateral_hit = false
@active_battler.collateral_halved = false
@active_battler.collateral_performed = false
@active_battler.collateral_missed = false
#
collateral_update_phase4_step2 # Perform the original
#
end
#--------------------------------------------------------------------------
# * Make Basic Action Results
#--------------------------------------------------------------------------
def make_basic_action_result
#
unless @active_battler.collateral_performed # Only if not performed
if @active_battler.is_a?(Game_Actor) # If Actor attacker
if @active_battler.current_action.basic == 0 # Only if melee attack
id = @active_battler.id # Get the enemy ID
collateral_result(Collateral::ACTOR, id) # Generate damage Result
id = @active_battler.weapon_id # Get the weapon ID
if Collateral::WEAPON.has_key?(id) # If valid for collateral
collateral_result(Collateral::WEAPON, id) # Generate damage result
end
end
else # Else if Enemy attacker
id = @active_battler.id # Get the enemy ID
collateral_result(Collateral::ENEMY, id) # Generate damage result
end
end
#
collateral_make_basic_action_result # Perform the original
missed_collateral_action_result # Get if attack missed
#
end
#--------------------------------------------------------------------------
# * Make Skill Action Results
#--------------------------------------------------------------------------
def make_skill_action_result
#
unless @active_battler.collateral_performed # Only if not performed
id = @active_battler.current_action.skill_id # Get the Item ID
collateral_result(Collateral::SKILL, id) # Generate damage result
end
#
collateral_make_skill_action_result # Perform the original
missed_collateral_action_result # Get if attack missed
#
end
#--------------------------------------------------------------------------
# * Make Item Action Results
#--------------------------------------------------------------------------
def make_item_action_result
#
id = @active_battler.current_action.item_id # Get the Item ID
@item = $data_items[id] # Get the item
@item.collateral_halved = false # Clear halved stat
#
unless @active_battler.collateral_performed # Only if not performed
id = @active_battler.current_action.item_id # Get the Item ID
collateral_result(Collateral::ITEM, id) # Generate damage result
end
#
collateral_make_item_action_result # Perform the original
missed_collateral_action_result # Get if attack missed
#
end
#--------------------------------------------------------------------------
# * Make Skill Action Results
#--------------------------------------------------------------------------
def missed_collateral_action_result
#
effective = false # Assume no damage
for target in @target_battlers # Cycle all targets
unless target.state_changed == true # if not status applying
next if target.damage.nil? # Skip any nil damage
next if (target.damage).to_i == 0 # Skip any non-numeric
end
effective = true # Found actual damage
break # Break out of cycle
end
#
@active_battler.collateral_missed = !effective # Set flag missed
#
end
#--------------------------------------------------------------------------
# * Make Collateral Action Result
# array_list : configured list of collateral tagged attacks
# id : attack ID
#--------------------------------------------------------------------------
def collateral_result(array_list, id)
#
return unless array_list.has_key?(id) # Exit if not in list
#
responce = array_list[id][0] # Get response type
chance = array_list[id][1] # Get chance of response
must_hit = array_list[id][2] # Get chance of response
halved = array_list[id][3] # Get if damage halved
#
chance = 100 if chance.nil? # Chance default is 100
must_hit = false if must_hit.nil? # Hit default is false
halved = false if halved.nil? # Halved default is false
#
roll = rand(100) # Generate percent chance
return if chance < roll # Exit if chance fails
#
@active_battler.collateral_flag = true # Set collateral flag
@active_battler.collateral_hit = must_hit
@active_battler.collateral_halved = halved # Set if damage is halved
@active_battler.collateral_type = responce # Set collateral responce
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase step 3 : animation for action performer)
#--------------------------------------------------------------------------
def update_phase4_step3
#
if @active_battler.collateral_performed == true # If performed collateral
@phase4_step = 4 # Shift to phase 4
return # Exit method
end
#
collateral_update_phase4_step3 # Perform the original
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase step 6 : refresh)
#--------------------------------------------------------------------------
def update_phase4_step6
#
if @active_battler.collateral_flag == true # If collateral flag
@target_battlers = collateral_gather # Get collateral targets
end
#
@target_battlers.compact! # Remove Nil entries
#
if @active_battler.collateral_flag == true # If collateral flag
if @target_battlers != [] # If valid targets
collateral_action # Perform action
@phase4_step = 3 # Shift to step 3
return # Exit method
end
end
#
@active_battler.collateral_flag = false # Clear Flag
#
collateral_update_phase4_step6 # Perform the original
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets)
#--------------------------------------------------------------------------
def collateral_gather
#
# Return empty array if must hit target and missed
if @active_battler.collateral_hit
return [] if @active_battler.collateral_missed
end
#
# Determine target of collateral based on active battler's action scope
targets_are_enemies = collateral_gather_scope
target_group = collateral_gather_group(targets_are_enemies)
#
# Make temp copy of all previous battlers targeted
old_battlers = @target_battlers
#
# Branch on collateral response type
case @active_battler.collateral_type
when 0 ; battler_return = collateral_gather_identical(target_group)
when 1 ; battler_return = collateral_gather_other(target_group)
when 2 ; battler_return = collateral_gather_all_other(target_group)
when 3 ; battler_return = collateral_gather_all(target_group)
end
#
# Exit with return array
return battler_return
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets : get attack scope)
#--------------------------------------------------------------------------
def collateral_gather_scope
#
# Branch according to each action
case @active_battler.current_action.kind
when 2 ; return (@item.scope == 1 || @item.scope == 2) # Items
when 1 ; return (@skill.scope == 1 || @skill.scope == 2) # Skill
end
#
# Exit method true (assume Basic)
return true
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets : get target group)
# enemy_targets : if targets are battler's enemies or allies
#--------------------------------------------------------------------------
def collateral_gather_group(enemy_targets=true)
#
# If action battler is actor
if @active_battler.is_a?(Game_Actor)
# group is 'troop' if true, otherwise group is 'party'
group = (enemy_targets) ? $game_troop.enemies : $game_party.actors
else
# group is 'party' if true, otherwise group is 'troop'
group = (enemy_targets) ? $game_party.actors : $game_troop.enemies
end
#
# Return group member list
return group
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets: all identical)
# group : party or troop member list
#--------------------------------------------------------------------------
def collateral_gather_identical(group)
#
battler_return = [] # Make returning array
old_battlers = @target_battlers # Copy old targets
#
for target in group # Cycle through group
if old_battlers.include?(target) # If previously targeted
battler_return.push(target) if target.exist? # Add if valid target
end
end
#
return battler_return # Exit with return array
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets: random other)
# group : party or troop member list
#--------------------------------------------------------------------------
def collateral_gather_other(group)
#
target_list = [] # Make temp array
battler_return = [] # Make returning array
old_battlers = @target_battlers # Copy old targets
#
for target in group # Cycle through group
next if old_battlers.include?(target) # Skip if it was targeted
target_list.push(target) if target.exist? # Add to list if valid
end
#
id = rand(target_list.size) # Choose target in list
new_target = target_list[id] # Acquire target from ID
battler_return.push(new_target) # Add valid target
#
return battler_return # Exit with return array
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets: all other targets)
# group : party or troop member list
#--------------------------------------------------------------------------
def collateral_gather_all_other(group)
#
battler_return = [] # Make returning array
old_battlers = @target_battlers # Copy old targets
#
for target in group # Cycle through group
next if old_battlers.include?(target) # Skip if it was targeted
battler_return.push(target) if target.exist? # Add if valid target
end
#
return battler_return # Exit with return array
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase gather collateral targets: all targets)
# group : party or troop member list
#--------------------------------------------------------------------------
def collateral_gather_all(group)
#
battler_return = [] # Make returning array
#
for target in group # Cycle through group
battler_return.push(target) if target.exist? # Add if valid target
end
#
return battler_return # Exit with return array
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase collateral action)
#--------------------------------------------------------------------------
def collateral_action
#
@active_battler.collateral_performed = true # Set action performed
@active_battler.collateral_flag = false # Clear the old flag
@status_window.refresh # Refresh status window
#
case @active_battler.current_action.kind # Branch on action
when 0 ; collateral_action_melee # basic
when 1 ; collateral_action_skill # skill
when 2 ; collateral_action_item # item
end
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase collateral action : melee attack)
#--------------------------------------------------------------------------
def collateral_action_melee
#
@animation1_id = @active_battler.animation1_id # Set attacker animation
@animation2_id = @active_battler.animation2_id # Set target animation
#
for target in @target_battlers # Cycle through targets
next if target.nil? # Skip any invalid
target.attack_effect(@active_battler) # Apply melee result
end
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase collateral action : skill attack)
#--------------------------------------------------------------------------
def collateral_action_skill
#
@help_window.set_text(@skill.name, 1) # Show skill name
@animation1_id = @skill.animation1_id # Set attacker animation
@animation2_id = @skill.animation2_id # Set target animation
#
for target in @target_battlers # Cycle through targets
next if target.nil? # Skip any invalid
target.skill_effect(@active_battler, @skill) # Apply skill result
end
#
end
#--------------------------------------------------------------------------
# * Frame Update (main phase collateral action : item attack)
#--------------------------------------------------------------------------
def collateral_action_item
#
halved = @active_battler.collateral_halved # Get attack halved stat
@item.collateral_halved = halved # Set halved stat to item
#
@help_window.set_text(@item.name, 1) # Display item name
@animation1_id = @item.animation1_id # Set attacker animation
@animation2_id = @item.animation2_id # Set target animation
#
for target in @target_battlers # Cycle through targets
next if target.nil? # Skip any invalid
target.item_effect(@item) # Apply item result
end
#
@item.collateral_halved = false # Remove halved stat
#
end
end
Instructions
All within the script.
Compatibility
Fairly compatible for RPGMaker XP systems other than the optional direct edits described. However, said edits are not necessary IF you choose not to employ half-damage from collateral strikes.
Terms and Conditions
Free to use, even in commercial projects. However, I will need some form of due credit for both myself and Bennerdeben... even if but a mere mention in some end titles.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)
Above are clickable links