#===============================================================================
# TSBS v1.4 Bugfixes
#-------------------------------------------------------------------------------
# Change Logs :
# 2019.05.19 - Fixed crash, auto re-target from random targetting causing crash
# when the new target dies.
# 2019.03.08 - Fixed crash if boomerang is used together with tag and
# one animation tag
# 2018.07.15 - Fixed bug where random reflect didn't kill victim
# 2015.05.01 - Fixed hide target in animation crash
# - Fixed accessing sprite when escape battle crash (detail below)
# 2015.03.25 - Added patch to work with TSBS in game editor
# 2015.03.06 - Fixed forced act bug for area target
# 2015.02.04 - Fixed Smooth return typo that cause fatal crash
# - Fixed Show icon index
# 2015.01.09 - Added compatibility with YEA Steal Item
# 2015.01.08 - Added compatibility with YEA Party Command
# 2015.01.06 - Added fix for default flip
# - Change how update key work in battler icon
# - Added move to target fix
# 2015.01.01 - Added YEA skill steal compatibility
# 2014.12.25 - Release date
#
#-------------------------------------------------------------------------------
# Known issues :
#-------------------------------------------------------------------------------
# - When using random target, the script auto target another battler if one of
# the original target dies. And if the new target also dies, it did not get
# registered the kill so the script recognize it as alive, this caused crash
# (FIXED!)
#
# - When a skill throws a projectile and combined with boomerang, area, and
# one animation tag, it throws a crash because of reference issuses (FIXED!)
#
# - When a projectile is reflected to friends unit, and it reaches zero didn't
# kill it. If actor is the victim, it may crash. (FIXED!)
#
# - When you set an event in Troop that target all enemies (like change enemy
# HP / MP, hidden enemies will be revealed, but can not be targeted) (FIXED!)
#
# - When using custom collapse sequence, if you change the graphics like
# changing filename from battler_1.png to battler_2.png, your battler will
# suddenly disappear (FIXED!)
#
# - Multiple Animations addon breaks the game if it's played over the animation
# guard. An animation that played over the target when it took damage.(FIXED!)
#
# - Heavy lag issue if you set Looping_Background in config 1 to true and you
# haven't set any background for battleback in map. (FIXED!)
#
# - Revived enemy won't collapsed twice (FIXED!)
#
# - Double resume error when using substitute not followed by yanfly script
# (FIXED!)
#
# - Trying to show weapon icon for enemy causes crash (FIXED!)
#
# - System sound (recovery) played when using item in map/menu (FIXED!)
#
# - small issues on :sm_target and :end_action (FIXED!)
#
# - Enemy Default flip doesn't work (FIXED!)
#
# - Move to target + area tag + flipped battler cause the battler go off screen
# (FIXED!)
#
# - When you're using :sm_return, it will cause crash due to typo (FIXED!)
#
# - When you're using index -3 in icon settings. Unless you give the notetag
# you cant show icon. It should display default icon instead
# of displaying nothing. No wonder some people keep asking me "how to show
# weapon icon?" (FIXED!)
#
# - When you're using [:forced] in area skill, it will produce error (FIXED!)
#
# - When you're going to use hide target in animation. It produces error pointed
# to basic modules (FIXED!)
#
# - When you define your own escape sequence, and you put a command that
# modifies the actor sprite (e.g, [:fadeout]) it produces error (FIXED!)
#-------------------------------------------------------------------------------
# Known incompatibilities :
#-------------------------------------------------------------------------------
# - Incompatibility with YEA Active Chain Skill (FIXED!)
#
# - Incompatibility with YEA Skill Steal (FIXED!)
#
# - Incompatibility with AEA Charge turn battle(?)
#
# - Incompatibility with YEA Party Command (FIXED!)
#
# - Incompatibility with YEA Steal Item (FIXED!)
#
#-------------------------------------------------------------------------------
# To use this patch, simply put this script below implementation
#===============================================================================
#===============================================================================
# ** Game_Battler
#===============================================================================
class Game_Battler
#----------------------------------
# * Weapon icon fix
#----------------------------------
def icon_file(index = 0)
return @icon_file unless @icon_file.empty?
return weapons[index].icon_file if actor? && weapons[index]
return ''
end
#----------------------------------
# * System sound fix
#----------------------------------
def make_base_result(user, item)
tsbs_make_base_result(user, item)
Sound.tsbs_play_recovery if item.damage.recover? && play_sound?
return if user == self
return if busy?
if item.damage.recover? || item.damage.type == 0
self.battle_phase = :idle
# Refresh idle key. In case if there is any state change or
# HP rate change
return
end
self.battle_phase = :hurt if @result.hit?
# Automatically switch to hurt phase
if @result.missed && play_sound?
Sound.tsbs_play_miss
end
if @result.evaded
Sound.tsbs_play_eva if item.physical? && play_sound?
Sound.tsbs_play_magic_eva if item.magical? && play_sound?
self.battle_phase = :evade
# Automatically switch to evade phase
end
end
def play_sound?
SceneManager.in_battle? && PlaySystemSound
end
#----------------------------------
# * End action fix
#----------------------------------
def setup_end_action
@break_action = true
@finish = true
method_wait
end
#----------------------------------
# * Smooth move to target fix
#----------------------------------
def setup_smooth_move_target
if area_flag
size = target_array.size
xpos = target_array.inject(0) {|r,battler| r + battler.x}/size
ypos = target_array.inject(0) {|r,battler| r + battler.y}/size
xpos += @acts[1] * (flip && !@ignore_flip_point ? -1 : 1)
dur = @acts[3] || 25
rev = @acts[4]
rev = true if rev.nil?
smooth_move(xpos, ypos + @acts[2], dur, rev)
return
end
return unless target
tx = @acts[1] + target.x || 0
ty = @acts[2] + target.y || 0
tx *= -1 if flip && !@ignore_flip_point
dur = @acts[3] || 25
rev = @acts[4]
rev = true if rev.nil?
smooth_move(tx,ty,dur,rev)
end
#----------------------------------
# * Move to target flip fix
#----------------------------------
def setup_move_to_target
return TSBS.error(@acts[0], 4, @used_sequence) if @acts.size < 5
stop_all_movements
if area_flag
size = target_array.size
xpos = target_array.inject(0) {|r,battler| r + battler.x}/size
ypos = target_array.inject(0) {|r,battler| r + battler.y}/size
xpos += @acts[1] * (flip && !@ignore_flip_point ? -1 : 1)
# Get the center coordinate of enemies
goto(xpos, ypos + @acts[2], @acts[3], @acts[4])
return
end
xpos = target.x + (flip ? -@acts[1] : @acts[1])
ypos = target.y + @acts[2]
goto(xpos, ypos, @acts[3], @acts[4], @acts[5] || 0)
end
#-----------------------------------
# * Smooth return patch
#-----------------------------------
def setup_smooth_return
tx = @ori_x
ty = @ori_y
dur = @acts[1] || 25
rev = @acts[2]
rev = true if rev.nil?
smooth_move(tx,ty,dur,rev)
end
#-----------------------------------
# * forced acts patch
#-----------------------------------
def setup_force_act
return TSBS.error(@acts[0], 1, @used_sequence) if @acts.size < 2
act_key = @acts[1]
if area_flag
target_array.each do |target|
target.forced_act = act_key
target.force_change_battle_phase(:forced)
end
else
target.forced_act = act_key
target.force_change_battle_phase(:forced)
end
end
#============================================================================
# ** Patch for implementation to work with in game editor
# Some commands that had been fixed
# - [:focus, ...]
# - [:screen, :tone, ...]
# - [:screen, :color, ...]
#============================================================================
def setup_focus
return TSBS.error(@acts[0], 1, @used_sequence) if @acts.size < 2
case @focus_target
when 1; eval_target = lambda{|s|opponents_unit.members.include?(s.battler)};
when 2; eval_target = lambda{|s|friends_unit.members.include?(s.battler)};
when 3; eval_target = lambda{|s|true};
else; eval_target = lambda{|s|target_array.include?(s.battler)};
end
sprset = get_spriteset
rect = sprset.focus_bg.bitmap.rect
color = @acts[2] || Focus_BGColor
color = Color.new(*color) if color.is_a?(Array)
sprset.focus_bg.bitmap.fill_rect(rect,color) # Recolor focus background
sprset.focus_bg.fadein(@acts[1]) # Trigger fadein
sprset.battler_sprites.select do |spr|
!spr.battler.nil? # Select avalaible battler
end.each do |spr|
if spr.battler != self && (spr.battler.actor? ? true : spr.battler.alive?)
check = eval_target.call(spr)
spr.fadeout(@acts[1]) if !check
spr.fadein(@acts[1]) if check
end
end
end
#------------------------------------------------------
# * Fix for auto-generated sequence from in game editor
#------------------------------------------------------
def setup_screen
return TSBS.error(@acts[0], 1, @used_sequence) if @acts.size < 2
screen = $game_troop.screen
case @acts[1]
when Screen_Tone
return TSBS.error(@acts[0], 3, @used_sequence) if @acts.size < 4
tone = @acts[2].is_a?(Array) ? Tone.new(*@acts[2]) : @acts[2]
duration = @acts[3]
screen.start_tone_change(tone, duration)
when Screen_Shake
return TSBS.error(@acts[0], 4, @used_sequence) if @acts.size < 5
power = @acts[2]
speed = @acts[3]
duration = @acts[4]
screen.start_shake(power, speed, duration)
when Screen_Flash
return TSBS.error(@acts[0], 3, @used_sequence) if @acts.size < 4
color = @acts[2].is_a?(Array) ? Color.new(*@acts[2]) : @acts[2]
duration = @acts[3]
screen.start_flash(color, duration)
when Screen_Normalize
return TSBS.error(@acts[0], 2, @used_sequence) if @acts.size < 3
tone = Tone.new
duration = @acts[2]
screen.start_tone_change(tone, duration)
end
end
end
#===============================================================================
# ** Game_Enemy
#===============================================================================
class Game_Enemy
#-------------------
# Enemy revival fix
#-------------------
def hp=(hp)
super
@collapsed = false if hp > 0
end
#-------------------
# Default flip fix
#-------------------
def default_flip
result = TSBS::Enemy_Default_Flip
toggler = (!data_battler.note[DefaultFlip].nil? rescue false)
result = !result if toggler
return result
end
end
#===============================================================================
# ** Sprite_Battler
#===============================================================================
class Sprite_Battler
#----------------------------
# Battler visibility fix
#----------------------------
def init_visibility
return if actor? && !@battler.data_battler.dead_key.empty?
not_hidden = !@battler.hidden?
not_collapsed = (@battler.enemy? && @battler.battle_phase != :collapse ?
!@battler.collapsed : true)
@battler_visible = not_hidden && not_collapsed
self.opacity = 0 unless @battler_visible
end
#----------------------------
# Opacity refresh fix
#----------------------------
def update_opacity
self.opacity = [opacity,@battler.max_opac].min
@battler.refresh_opacity = false
end
end
#===============================================================================
# ** Sprite_AnimGuard
#===============================================================================
class Sprite_AnimGuard
#----------------------------
# Get battler (Multiple animation fix)
#----------------------------
def battler
@spr_battler.battler
end
end
#===============================================================================
# ** Sprite_BattlerIcon
#===============================================================================
class Sprite_BattlerIcon
#--------------------------------------
# Iconfix
#--------------------------------------
def icon_index=(index)
@icon_index = index
if index < 0
battler = @spr_battler.battler
name = battler.icon_file(index + 1)
if name.empty?
index = index.abs - 3
self.icon_index = (battler.weapons[index].icon_index rescue (
battler.weapons[index + 1].icon_index) rescue 0)
return
else
bmp = Cache.system(name)
self.bitmap = bmp
return
end
end
icon_bitmap = Cache.system("Iconset")
rect = Rect.new(index % 16 * 24, index / 16 * 24, 24, 24)
bmp = Bitmap.new(24,24)
bmp.blt(0, 0, icon_bitmap, rect, 255)
self.bitmap = bmp
end
#----------------------------------
# Change update key for icon
#----------------------------------
def update_key
actor = battler # Just make alias
@used_key = battler.icon_key
array = Icons[@used_key]
return icon_error unless array
self.anchor = array[0]
@dummy.x = (battler.flip ? -array[1] : array[1])
@dummy.y = array[2]
@above_char = array[3]
update_placement
self.angle = array[4]
target = array[5]
duration = array[6]
icon_index = (eval(array[7]) rescue 0) if array[7].is_a?(String)
if array[7] >= 0
icon_index = array[7]
elsif !array[7].nil?
if array[7] == -1 # First weapon ~
icon_index = (battler.weapons[0].icon_index rescue 0)
elsif array[7] == -2 # Second weapon ~
icon_index = (battler.weapons[1].icon_index rescue
(battler.weapons[0].icon_index rescue 0))
elsif array[7] <= -3 # Custom icon graphic
icon_index = array[7] + 2
end
end
self.mirror = (array[8].nil? ? false : array[8])
if array[9] && array[10] && array[11]
@dummy.slide(array[9], array[10], array[11])
end
icon_index = icon_index || 0
self.icon_index = icon_index
change_angle(target, duration)
battler.icon_key = ""
end
end
#===============================================================================
# ** Projectile Reflect Fix
#===============================================================================
class Sprite_Projectile
def repel
temp = subject
if random_reflect? # Random target reflect if skill/item allow to do so
temp = temp.friends_unit.alive_members.shuffle[0]
$game_temp.battler_targets << temp # <-- Add to refresh
end
self.subject = target
self.target = temp
# Invert setup as well ~
start = @setup[PROJ_START]
start_p = @setup[PROJ_STARTPOS]
@setup[PROJ_START] = @setup[PROJ_END]
@setup[PROJ_STARTPOS] = @setup[PROJ_ENDPOS]
@setup[PROJ_END] = start
@setup[PROJ_ENDPOS] = start_p
self.mirror = !self.mirror
# Re-start projectile
start_projectile
start_animation(@animation, !@mirror)
self.subject = temp if boomerang # Boomerang fix
end
# Boomerang + Area tag fix
def start_projectile
subj = (@setup[PROJ_REVERSE] ? @target : @subject)
subj = @subject if @target.is_a?(Array)
ypos = 0
xpos = 0
if subj.is_a?(Array)
size = subj.size
xpos = subj.inject(0) {|r,battler| r + battler.screen_x}/size
ypos = subj.inject(0) {|r,battler| r + battler.screen_y}/size
xpos += @setup[PROJ_STARTPOS][0]
else
spr_subj = subj.sprite
case @setup[PROJ_START]
when PROJ_POSITION_HEAD; ypos = subj.y - spr_subj.height
when PROJ_POSITION_MID; ypos = subj.y - spr_subj.height/2
when PROJ_POSITION_FEET; ypos = subj.y
when PROJ_POSITION_NONE; ypos = xpos = 0
else; ypos = subj.y;
end
xpos = subj.x + @setup[PROJ_STARTPOS][0]
end
ypos += @setup[PROJ_STARTPOS][1]
@angle = (self.mirror ? 360 - @setup[PROJ_ANGLE] : @setup[PROJ_ANGLE])
set_point(xpos, ypos)
@point.continue = @setup[PROJ_PIERCE]
@afterimage_opac = @setup[PROJ_AFTOPAC]
@afterimage_rate = @setup[PROJ_AFTRATE]
@anim_top = @setup[PROJ_ANIMPOS]
if @setup[PROJ_ANIMSTART]
if @setup[PROJ_ANIMSTART] == PROJ_ANIMDEFAULT
anim = $data_animations[item.animation_id]
else
anim = $data_animations[@setup[PROJ_ANIMSTART]]
end
@anim_start.start_animation(anim,subj.flip)
end
@anim_start.target_sprite = [subj.sprite] if @setup[PROJ_FLASH_REF][0]
apply_item(target, target.is_a?(Array)) if @setup[PROJ_DAMAGE_EXE] == -1
make_aim(@dur, @jump)
end
end
#===============================================================================
# ** Spriteset_Battle
#===============================================================================
class Spriteset_Battle
#----------------------------
# Looping background fix
#----------------------------
def battleback2_bitmap
if battleback2_name
Cache.battleback2(battleback2_name)
elsif TSBS::Looping_Background
Bitmap.new(Graphics.width, Graphics.height)
else
Bitmap.new(1, 1)
end
end
end
#===============================================================================
# ** Window_BattleLog
#===============================================================================
class Window_BattleLog
#-----------------------------------------
# Double resume fix in substitute
#-----------------------------------------
def display_substitute(sub, targ)
return unless $imported["YEA-BattleEngine"] &&
YEA::BATTLE::MSG_SUBSTITUTE_HIT
add_text(sprintf(Vocab::Substitute, substitute.name, target.name))
end
end
#===============================================================================
# ** Accessing spriteset fix
#===============================================================================
class Scene_Battle
#----------------------------------------------------------------------------
# Store spriteset as global variable in case if SceneManager.scene returns
# a nilclass, but spriteset still exist / not disposed yet. The question
# come up, how could we access the spriteset then?
#----------------------------------------------------------------------------
alias lazy_fix_start start
def start
lazy_fix_start
$sprset = @spriteset
end
#----------------------------------------------------------------------------
# Auto retarget fix
#----------------------------------------------------------------------------
def tsbs_action_main(targets, item, subj)
# Determine if item is not AoE ~
if !item.area?
subj.area_flag = false
# Repeat item sequence for target number times
targets.each do |target|
# Change target if the target is currently dead
if target.dead? && !item.for_dead_friend?
target = subj.opponents_unit.random_target
break if target.nil?
$game_temp.battler_targets << target # <-- Adding this line
# Break if there is no target avalaible or force break action
end
target = @cover_battlers[target] if @cover_battlers[target]
# Do sequence
subj.target = target
subj.battle_phase = :skill
wait_for_skill_sequence
break if [:forced, :idle].include?(subj.battle_phase) ||
subj.break_action
end
# If item is area of effect damage. Do sequence skill only once
else
subj.area_flag = true
subj.battle_phase = :skill
wait_for_skill_sequence
subj.area_flag = false
end
end
end
class Game_Actor
#----------------------------------------------------------------------------
# * Change how to access sprite
#----------------------------------------------------------------------------
def sprite
$sprset.get_sprite(self)
end
end
#===============================================================================
# ** Hide target fix in animation
#===============================================================================
class Sprite
#----------------------------------------------------------------------------
# * Change how my basic module works
#----------------------------------------------------------------------------
def flash(color, duration)
theo_clonesprites_flash(color, duration)
@dur_flash = duration
@color_flash = color.clone if color
@alpha_val = @color_flash.alpha.to_f
@alpha_ease = @alpha_val / duration
end
end
class Sprite_Battler
#----------------------------------------------------------------------------
# * Change alias to super. The next ruby version should consider alias as
# super -_-
#----------------------------------------------------------------------------
def flash(color, duration)
self.color.set(EmptyColor)
super(color, duration)
@spr_icon.flash(color, duration)
@shadow.flash(color, duration) unless color
end
end
#===============================================================================
# ** Scene_Battle
#===============================================================================
class Scene_Battle
#-----------------------------------------
# YEA - Active Chain Skill
#-----------------------------------------
def show_action_sequences(targets, item, subj)
tsbs_action_init(targets, item, subj)
tsbs_action_pre(targets, item, subj)
tsbs_action_main(targets, item, subj)
unless $imported["YEA-ActiveChainSkills"] && @active_chain_skill &&
@active_chain_skill > 0
tsbs_action_post(targets, item, subj)
tsbs_action_end(targets, item, subj)
$game_temp.backdrop.reset_transition_flags
wait(tsbs_wait_dur)
end
end
#-----------------------------------------
# YEA - Skill Steal patch
#-----------------------------------------
if $imported["YEA-SkillSteal"]
alias tsbs_skill_steal_apply_item tsbs_apply_item
def tsbs_apply_item(target, item, subj = @subject)
tsbs_skill_steal_apply_item(target, item, subj)
tsbs_skill_steal(target, item, subj)
end
def tsbs_skill_steal(target, item, subj)
return unless item.skill_steal
return if target.actor?
return unless subj.actor?
for skill in target.stealable_skills
next if subj.skill_learn?(skill)
@subject.learn_skill(skill.id)
string = YEA::SKILL_STEAL::MSG_SKILL_STEAL
skill_text = sprintf("\\i[%d]%s", skill.icon_index, skill.name)
text = sprintf(string, @subject.name, skill_text, target.name)
@stolen_skills << text
end
end
alias tsbs_skill_steal_action_init tsbs_action_init
def tsbs_action_init(targets, item, subj)
tsbs_skill_steal_action_init(targets, item, subj)
@stolen_skills = []
end
alias tsbs_skill_steal_action_end tsbs_action_end
def tsbs_action_end(targets, item, subj)
tsbs_skill_steal_action_end(targets, item, subj)
@stolen_skills.each do |text_skill|
@log_window.add_text(text_skill)
YEA::SKILL_STEAL::MSG_DURATION.times { tsbs_wait_update }
@log_window.back_one
end
end
end # YEA SKILL STEAL
#-----------------------------------------
# YEA - Steal Item patch
#-----------------------------------------
if $imported["YEA-StealItems"]
alias tsbs_steal_item_apply_item tsbs_apply_item
def tsbs_apply_item(target, item, subj = @subject)
tsbs_steal_item_apply_item(target, item, subj)
tsbs_apply_steal_results(target, item, subj)
end
def tsbs_apply_steal_results(target, item, subj)
return if target.actor?
return if item.steal_type.nil?
if target.stealable_items.empty?
fmt = YEA::STEAL::STEAL_EMPTY_TEXT
text = sprintf(fmt, target.name)
elsif target.result.stolen_item.nil?
fmt = YEA::STEAL::STEAL_FAIL_TEXT
text = sprintf(fmt, subj.name)
else
fmt = YEA::STEAL::STEAL_SUCCESS_TEXT
actor = subj.name
item = stolen_item_text(target)
enemy = target.name
text = sprintf(fmt, actor, item, enemy)
end
@stolen_items << text
end
alias tsbs_steal_item_action_init tsbs_action_init
def tsbs_action_init(targets, item, subj)
tsbs_steal_item_action_init(targets, item, subj)
@stolen_items = []
end
alias tsbs_steal_item_action_end tsbs_action_end
def tsbs_action_end(targets, item, subj)
tsbs_steal_item_action_end(targets, item, subj)
@stolen_items.each do |text_item|
@log_window.add_text(text_item)
60.times { tsbs_wait_update }
@log_window.back_one
end
end
end # YEA STEAL ITEM
end
if $imported["YEA-CommandParty"]
class Game_Party
alias tsbs_set_party_cooldown set_party_cooldown
def set_party_cooldown
tsbs_set_party_cooldown
battle_members.each do |m|
m.init_oripost
m.setup_instant_reset
m.sprite.start_effect(:appear)
end
end
end
end # YEA COMMAND PARTY