=begin
===============================================================================
Skill Damage Over Time (Blizz ABS add-on) Ver. 1.02
- By KK20 [8/12/12]
===============================================================================
[Change Log]
Version
1.02 :
<> If the battler increased or decreased its stats after applying a DoT
state, the DoT damage was adjusted to this change. This has been fixed
1.01 :
<> If DoT state was applied through an event, Nil Error was thrown
<> Added the option to make DoT damage pop up
===============================================================================
[Description]
States that applied damage over time (DoT) always dealt damage that was equal
to some percentage amount of the player's HP. In Blizz ABS, any state that had
'slip damage' checked as true would always do damage equal to 2% of the
battler's max HP every second (40 frames).
This script modifies that and allows some customizable DoT amounts. States
with 'slip damage' will now be associated with a skill. In other words, every
time DoT takes place, the affected battler will now take damage as if it was
attacked by a skill. Essentially, you can make a DoT state called "Burn" and
assign it to the skill "Fire". Instead of the battler taking 2% of max HP
damage, it will now take damage as if it were being hit by "Fire".
Also, you can assign how many times DoT will take place during the duration of
the state. No longer will DoT have to take place every second of gameplay. You
can make DoT take place once every 3 seconds, only once in 20 seconds, or even
3 times every second.
[Features]
- Assign skills to states that deal DoT
- Customize how many times DoT takes place
- Maintains Blizz ABS's original slip_damage_effect, just in case you want to
use the original "2% of max HP damage every second" somewhere
- Can display DoT damage as pop up damage
[Instructions]
> In order for skills to deal damage over time, check the box "Slip Damage"
> If you want the state to wear off after so many seconds, check the box
"Release at the end of battle".
If you want the state to remain forever until it is cured, don't check it.
> How frequent DoT takes place is based on the following formula:
FREQUENCY = TURNS / TICKS
where TURNS is the value you put in "After [ x ] turns" in the database
and TICKS is the number of times you want DoT to take place (config below)
===============================================================================
[Credits]
KK20 : Writing the script
sasofrass : For requesting
===============================================================================
=end
#~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
# B E G I N C O N F I G U R A T I O N
#~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
module Skills_DoT
#-----------------------------------------------------------------------------
# DISPLAY_DOT_DAMAGE - Set to true if you want the damage values to pop up
# during battle when affected by a DoT state.
#-----------------------------------------------------------------------------
DISPLAY_DOT_DAMAGE = true
def self.dot_states(state_id)
return nil unless $data_states[state_id].slip_damage
case state_id
#--------------------------------------------------------------------------
# self.dot_states(state_id)
# Configure what skill you would like to associate to the DoT state here.
# Also, configure how frequent the DoT takes place during the duration of
# the state.
# Format:
# When STATE_ID then return [SKILL_ID, TICKS]
#
# STATE_ID: The state's ID value located within the database
# SKILL_ID: The skill's ID value located within the database
# TICKS : The number of times DoT will take place
#--------------------------------------------------------------------------
when 3 then return [7, 5] # when Venom, then use skill 'Fire' 5 times
when 8 then return [13, 1] # when Paralyzed, then use skill 'Thunder' 1 time
else
return nil
end
end
end
#~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
# E N D C O N F I G U R A T I O N
#~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
#=============================================================================
# Map_Battler < Game_Character (Blizz ABS class)
# Aliased:
# slip_damage_effect
# Rewrite:
# count_states
# additional_states
#=============================================================================
class Map_Battler < Game_Character
#----------------------------------------------------------------------------
# count_states
# Changes the state time counters.
#----------------------------------------------------------------------------
def count_states
# check each state
battler.state_time.each_key {|id|
# decrease counter if fading state
battler.state_time[id] -= 1
# if 1 second has passed and probability that the state gets removed
### ADDED '$data_states[id].battle_only' CONDITION ###
if $data_states[id].battle_only && battler.state_time[id] <= 0 &&
battler.state_time[id] % 40 == 0 && rand(100) < $data_states[id].auto_release_prob
# remove state and counter
battler.remove_state(id)
battler.state_time.delete(id)
# If this state cannot be removed after a while and reached end of timer
elsif !$data_states[id].battle_only && battler.state_time[id] <= 0
# Reset the state's timer
battler.state_time[id] = $data_states[id].hold_turn * 40
end
}
end
#----------------------------------------------------------------------------
# additional_states
# Handles poison and paralyze effects as well as additional status effects.
#
# This method has been REWRITTEN by KK20.
#----------------------------------------------------------------------------
def additional_states
# temporary variable
slip_damage = battler.slip_damage?
# if Tons of Add-ons is there and using Regen Status
if $tons_version != nil && $tons_version >= 5.98 &&
$game_system.REGEN_STATUS
# modify slip damage flag
slip_damage |= (HP_REGEN_IDS + SP_REGEN_IDS + SP_POISON_IDS).any? {|i|
battler.states.include?(i)}
end
# if not dead and getting slip damage
### MOVED THE 'PER SECOND' CONDITION TO 'slip_damage_effect' ###
if valid? && slip_damage
# apply the slip damage
slip_damage_effect
end
# if old direction fix was stored
if @old_direction_fix != nil
# if able to move again
if self.restriction < 4
# reset everything
@direction_fix, @old_direction_fix = @old_direction_fix, nil
end
# if paralyzed
elsif self.restriction == 4
# store old direction fix and set new direction fix
@direction_fix, @old_direction_fix = true, @direction_fix
# reset movement
@force_move = []
# reset action if valid and not charging
self.reset_action if self.valid? && !self.charging?(BlizzABS::CHARGEFreeze)
end
end
#----------------------------------------------------------------------------
# slip_damage_effect
#
# This method has been EDITTED by KK20. (but only slightly)
#----------------------------------------------------------------------------
def slip_damage_effect
# store hpdamage and spdamage
hpdamage, spdamage = battler.hpdamage, battler.spdamage
# store current hp and sp
old_hp, old_sp = battler.hp, battler.sp
# if Tons of Add-ons is there and using Regen Status
if $tons_version != nil && $tons_version >= 5.98 &&
$game_system.REGEN_STATUS
# calculate HP damage
damage_hp = battler.maxhp / 50
damage_hp = 1 if damage_hp < 1
# if HP damaging state
if !(HP_REGEN_IDS.any? {|i| battler.states.include?(i)}) &&
battler.slip_damage?
# decrease HP by 2%
battler.hp -= damage_hp
# if HP regenarating state
elsif HP_REGEN_IDS.any? {|i| battler.states.include?(i)} &&
!battler.slip_damage?
# increase HP by 2%
battler.hp += damage_hp
end
# calculate SP damage
damage_sp = battler.maxsp / 50
damage_sp = 1 if damage_sp < 1
# if SP damaging state
if SP_POISON_IDS.any? {|i| battler.states.include?(i)}
# decrease SP by 2%
battler.sp -= damage_sp
end
# if SP regenarating state
if SP_REGEN_IDS.any? {|i| battler.states.include?(i)}
# increase SP by 2%
battler.sp += damage_sp
end
else
# decrease HP by 2%
dam = battler.maxhp / 50
dam = 1 if dam < 1
battler.hp -= dam
# set attacker and target data
end
# request damage sprite
$BlizzABS.util.request_damage_sprite(@body == nil ? self : @body) if Skills_DoT::DISPLAY_DOT_DAMAGE
# set last hit by
if (@battler.hp < old_hp || @battler.sp < old_sp)
slip_atk_size = @battler.last_slip_attackers.size
slip_atk_size > 0
@battler.last_hit_by = @battler.last_slip_attackers[slip_atk_size - 1]
end
# restore hpdamage and spdamage
battler.hpdamage, battler.spdamage = hpdamage, spdamage
end
#----------------------------------------------------------------------------
# slip_damage_effect
# Applies slip damage effect.
#
# This method has been ALIASED and EDITTED by KK20.
#----------------------------------------------------------------------------
alias babs_slip_damage_effect_original slip_damage_effect
def slip_damage_effect
ids = []
@battler.states.each{|state_id|
# skip this state if it isn't a slip_damage or configured
next unless Skills_DoT.dot_states(state_id) != nil
# Calculate on what frame to apply the DoT
frame = ($data_states[state_id].hold_turn * 40) / Skills_DoT.dot_states(state_id)[1]
# Only do DoT damage if correct frame
next if battler.state_time[state_id] % frame != 0
# Prepare to calculate damage
user = @battler.states_caused_by_characters_list[state_id]
skill = $data_skills[Skills_DoT.dot_states(state_id)[0]]
# Begin DoT damage calculation...
unless user.nil?
# Calculate power
power = skill.power + user.atk * skill.atk_f / 100
if power > 0
power -= @battler.pdef * skill.pdef_f / 200
power -= @battler.mdef * skill.mdef_f / 200
power = [power, 1].max
end
# Calculate rate
rate = 20
rate += (user.str * skill.str_f / 100)
rate += (user.dex * skill.dex_f / 100)
rate += (user.agi * skill.agi_f / 100)
rate += (user.int * skill.int_f / 100)
# Calculate basic damage
damage = power * rate / 20
else
# Calculate damage if no battler caused this status ailment
power = skill.power
if power > 0
power -= @battler.pdef * skill.pdef_f / 200
power -= @battler.mdef * skill.mdef_f / 200
power = [power, 1].max
end
damage = power
end
# Element correction
damage *= @battler.elements_correct(skill.element_set)
damage /= 100
# Dispersion
if skill.variance > 0 and damage.abs > 0
amp = [damage.abs * skill.variance / 100, 1].max
damage += rand(amp+1) + rand(amp+1) - amp
end
# Damage will always do at least 1 HP
damage = (damage <= 0 ? 1 : damage)
# Apply the damage
@battler.hp -= damage
# request damage sprite
$BlizzABS.util.request_damage_sprite(@body == nil ? self : @body) if Skills_DoT::DISPLAY_DOT_DAMAGE
}
# Call BABS original slip damage method afterwards
if Graphics.frame_count % 40 == 0
@battler.states.each{|state_id|
if $data_states[state_id].slip_damage and Skills_DoT.dot_states(state_id) == nil
babs_slip_damage_effect_original
break
end
}
end
end
end
#=============================================================================
# Game_Battler
# Aliased:
# initialize
# attack_effect
# skill_effect
# Rewrite:
# add_state
# remove_state
#=============================================================================
class Game_Battler
#-----------------------
# Create 'set' and 'get'
#-----------------------
attr_accessor :state_giver_attacker
attr_accessor :states_caused_by_characters_list
#---------------------------------------------------------------------------
# The following three methods have been ALIASED and EDITTED by KK20.
#---------------------------------------------------------------------------
alias call_orig_init_again initialize
def initialize
@state_giver_attacker ||= nil
@states_caused_by_characters_list ||= {}
call_orig_init_again
end
alias call_original_attack_effect attack_effect
def attack_effect(attacker)
@state_giver_attacker = attacker
call_original_attack_effect(attacker)
end
alias call_original_skill_effect skill_effect
def skill_effect(user, skill)
@state_giver_attacker = user
call_original_skill_effect(user, skill)
end
#--------------------------------------------------------------------------
# Add State
#
# This method has been EDITTED by KK20.
#--------------------------------------------------------------------------
def add_state(state_id, force = false)
# For an ineffective state
if $data_states[state_id] == nil
# End Method
return
end
# If not forcefully added
unless force
# A state loop already in existance
for i in @states
# If a new state is included in the state change (-) of an existing
# state, and that state is not included in the state change (-) of
# a new state (example: an attempt to add poison during dead)
if $data_states[i].minus_state_set.include?(state_id) and
not $data_states[state_id].minus_state_set.include?(i)
# End Method
return
end
end
end
# If this state is not added
unless state?(state_id)
# Add state ID to @states array
@states.push(state_id)
# If this state does Skill DoT, find the actor that caused this state
if Skills_DoT.dot_states(state_id) != nil
if @state_giver_attacker.nil?
@states_caused_by_characters_list[state_id] = nil
else
@states_caused_by_characters_list[state_id] = Battler_Stats_Array.new(@state_giver_attacker)
end
end
# If option [regarded as HP 0]is effective
if $data_states[state_id].zero_hp
# Change HP to 0
@hp = 0
end
# All state loops
for i in 1...$data_states.size
# Dealing with a state change (+)
if $data_states[state_id].plus_state_set.include?(i)
add_state(i)
end
# Dealing with a state change (-)
if $data_states[state_id].minus_state_set.include?(i)
remove_state(i)
end
end
# line change to a large rating order (if value is the same, then a
# strong restriction order)
@states.sort! do |a, b|
state_a = $data_states[a]
state_b = $data_states[b]
if state_a.rating > state_b.rating
-1
elsif state_a.rating < state_b.rating
+1
elsif state_a.restriction > state_b.restriction
-1
elsif state_a.restriction < state_b.restriction
+1
else
a <=> b
end
end
end
# If added forcefully
if force
# Set the natural removal's lowest number of turns to -1
@states_turn[state_id] = -1
end
# If not added forcefully
unless @states_turn[state_id] == -1
# Set the natural removal's lowest number of turns
@states_turn[state_id] = $data_states[state_id].hold_turn
end
# If unable to move
unless movable?
# Clear action
@current_action.clear
end
# Check the maximum value of HP and SP
@hp = [@hp, self.maxhp].min
@sp = [@sp, self.maxsp].min
end
#--------------------------------------------------------------------------
# Remove State
#
# This method has been EDITTED by KK20.
#--------------------------------------------------------------------------
def remove_state(state_id, force = false)
# If this state is added
if state?(state_id)
# If a forcefully added state is not forcefully removed
if @states_turn[state_id] == -1 and not force
# End Method
return
end
# If current HP is at 0 and options are effective [regarded as HP 0]
if @hp == 0 and $data_states[state_id].zero_hp
# Determine if there's another state [regarded as HP 0] or not
zero_hp = false
for i in @states
if i != state_id and $data_states[i].zero_hp
zero_hp = true
end
end
# Change HP to 1 if OK to remove incapacitation.
if zero_hp == false
@hp = 1
end
end
# Delete state ID from @states and @states_turn hash array
@states.delete(state_id)
@states_turn.delete(state_id)
# Clear the state-causing-actor value from hash
@states_caused_by_characters_list.delete(state_id)
end
# Check maximum value for HP and SP
@hp = [@hp, self.maxhp].min
@sp = [@sp, self.maxsp].min
end
#--------------------------------------------------------------------------
# State Change (+) Application
#
# This method has yet been EDITTED by KK20.
#--------------------------------------------------------------------------
def states_plus(plus_state_set)
# Clear effective flag
effective = false
# Loop (added state)
for i in plus_state_set
# If this state is not guarded
unless self.state_guard?(i)
# Set effective flag if this state is not full
effective |= self.state_full?(i) == false
# If states offer [no resistance]
if $data_states[i].nonresistance
# Set state change flag
@state_changed = true
# Add a state
add_state(i)
# If this state is not full
elsif self.state_full?(i) == false
# Convert state effectiveness to probability,
# compare to random numbers
if rand(100) < [0,100,80,60,40,20,0][self.state_ranks[i]]
# Set state change flag
@state_changed = true
# Add a state
add_state(i)
end
end
end
end
# Reset variable
@state_giver_attacker = nil
# End Method
return effective
end
end
#=============================================================================
# * Battler_Stats_Array
# This class was added as of Version 1.02
#
# Created to fix DoT damage when the state-giving battler changed its stats
#=============================================================================
class Battler_Stats_Array
def initialize(battler)
@array = [battler.atk, battler.str, battler.dex, battler.agi, battler.int]
end
def atk; return @array[0]; end;
def str; return @array[1]; end;
def dex; return @array[2]; end;
def agi; return @array[3]; end;
def int; return @array[4]; end;
end