查看: 9722|回复: 3

[已经解决] YEP的ATB/CTB上的一个设计疏忽

[复制链接]
梦石
0
星屑
61
在线时间
696 小时
注册时间
2011-1-4
回帖
176
发表于 2016-2-26 21:53:03 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 cjlzbb 于 2016-2-27 13:45 编辑

我不知道这个是故意这么设计的,还是真的所有ATB/CTB作者都忘了的一点

持续状态的回合计数  是在  拥有这个状态的战斗者 行动时结算的

可能这么说不太明白,举个ATB的实例

我方角色A速度200,敌人B速度100

下毒技能冷却4回合,中毒状态持续4回合。按理是毒4次后刚好冷却完毕

1-0,A满ATB值,B半ATB值。A使用下毒,B中毒
2-0,A满ATB值,B满ATB值。A攻击
2-1,A空ATB值,B满ATB值。B攻击,B掉血,中毒剩余3回合
3-1,A满ATB值,B半ATB值。A攻击
4-1,A满ATB值,B满ATB值。A攻击
4-2,A空ATB值,B满ATB值。B攻击,B掉血,中毒剩余2回合
5-2,A满ATB值,B半ATB值。A下毒技能冷却完毕
前面的x-x是双方实际行动次数

情况就是这样,技能冷却时间是按角色行动来的这个没问题,4次行动冷却4回合。但是状态是得到状态的那方行动时才结算的。
如果说掉血技能只是伤害发挥失常,那么控制类状态则彻底失衡,不同战斗中发挥的作用完全不可控。

这个问题不只是MV里的ATB CTB脚本才存在的,之前用的VA脚本也会。
那时候被我瞎改了一通后搞定了,


当时的思路是状态本身并不造成伤害,
在状态备注里写上具体伤害公式,
每个角色行动前会用个对全场角色敌人都生效的特殊技能,
该次行动不结算 自动恢复 冷却 等等正常回合里会结算的项目,
该技能的伤害公式等于所有由该角色附加的状态的技能伤害公式之和。
然后场上所有存在的 由该角色附加的状态计时 -1

我是用变量记录下来 角色X身上的状态X是哪个角色附加的。。作为个脚本盲我已经尽力了。。。
这样子还误打误撞做出了按人物攻击力和目标防御力来计算的持续伤害,比默认的百分比掉血好用多了
另外MV有可以写伤害公式的持续状态的插件,也就是说其实是可以直接确定状态附加者是哪个角色的吧,那么应该很好改的


有没有大神可以帮忙改下MV里的ATB和CTB。
VA的脚本好歹瞎改改好了。MV的插件看都看不懂


终于能碰RM了,速度发个测试图
把毒属性设为每回合掉25%生命上限的血量
毒技能冷却4回合,
角色速度100,
敌人速度50,
这个是毒技能冷却好后的截图,可以看到剩下50%血量
PS:测试用的脚本是重新从http://yanfly.moe下的新版,不是楼下那个
QQ截图20160227134130.png
梦石
0
星屑
61
在线时间
696 小时
注册时间
2011-1-4
回帖
176
 楼主| 发表于 2016-2-26 22:04:53 | 显示全部楼层
本帖最后由 cjlzbb 于 2016-2-26 22:07 编辑

[fold=这个是找到的在状态备注栏里写公式的插件,应该有参考价值吧]//=============================================================================
// CustomStateDamage.js
//=============================================================================

/*:
* @plugindesc Allows the use of notetags to determine damage/regen done by states
* @author Icaro Augusto / Wesnoth / Frozen Phoenix
*
* @help
* Hp damage: <hpd n>formula</hpd>
* Hp regen: <hpr n>formula</hpr>
* Mp damage: <mpd n>formula</mpd>
* Mp regen: <mpr n>formula</mpr>
* Tp damage: <tpd n>formula</tpd>
* Tp regen: <tpr n>formula</tpr>
*
* n = element id. Put n = 0 for neutral damage/regen.
* formula = anything you can use in the skill's damage formula
*
* Example:
*
* <hpd 2>
* a.atk*4 - b.def*2
* </hpd>
*
*
*
*  
*  
*/

/*:ja
* @plugindesc
* @author
*
* @help
*/

(function() {
       
        //Return the value between the tags in the state's notes
        Game_Battler.prototype.matcher = function(mode, stateID) {
                switch (mode) {
                        case 1:
                                var re = /(?:<hpr\s(\d+)>)\n*(.*)\n*(?:<\/hpr>)/i;
                                break;
                        case 2:
                                var re = /(?:<mpr\s(\d+)>)\n*(.*)\n*(?:<\/mpr>)/i;
                                break;
                        case 3:
                                var re = /(?:<tpr\s(\d+)>)\n*(.*)\n*(?:<\/tpr>)/i;
                                break;
                        case 4:
                                var re = /(?:<hpd\s(\d+)>)\n*(.*)\n*(?:<\/hpd>)/i;
                                break;
                        case 5:
                                var re = /(?:<mpd\s(\d+)>)\n*(.*)\n*(?:<\/mpd>)/i;
                                break;
                        case 6:
                                var re = /(?:<tpd\s(\d+)>)\n*(.*)\n*(?:<\/tpd>)/i;
                                break;       
                        default:
                                var re = /(?:<hpr\s(\d+)>)\n*(.*)\n*(?:<\/hpr>)/i;
                                break;
                }
                notes = $dataStates[stateID].note;
                var a = this._stateUser[stateID] ? this._stateUser[stateID] : this;
                var b = this;
                var result = 0;
                if (re.test(notes))
                {
                        var m = eval(re.exec(notes)[1]);
                        var er = (m == 0) ? 1 : this.elementRate(m);
                        var result = eval(re.exec(notes)[2])*er;                       
                }               
                return result;
        };
       
        //State user
        _Game_BattlerBase_clearStates = Game_BattlerBase.prototype.clearStates;
        Game_BattlerBase.prototype.clearStates = function() {
                _Game_BattlerBase_clearStates.call(this);
                this._stateUser = {};
    };
       
        //State user
        _Game_BattlerBase_eraseState = Game_BattlerBase.prototype.eraseState;
        Game_BattlerBase.prototype.eraseState = function(stateId) {
                _Game_BattlerBase_eraseState.call(this, stateId);
                delete this._stateUser[stateId];
        };
       
        //Clear state user
        _Game_Battler_removeBattleStates = Game_Battler.prototype.removeBattleStates;
        Game_Battler.prototype.removeBattleStates = function() {
                _Game_Battler_removeBattleStates.call(this);
                this._stateUser = {};
        };
       
        //State user
        Game_Battler.prototype.addState = function(stateId) {
                if (this.isStateAddable(stateId)) {
                        if (!this.isStateAffected(stateId)) {
                                this.addNewState(stateId);
                                this.refresh();
                        }
                        this.resetStateCounts(stateId);
                        this._result.pushAddedState(stateId);
                        this._stateUser[stateId] = BattleManager._subject;
                }
        };
       
        //Evaluation
        Game_Battler.prototype.regenerateHp = function() {
                var value = Math.floor(this.mhp * this.hrg);
                for (i = 0 ; i < this.states().length ; i++)
                {
                        value += Math.max(this.matcher(1, this.states().id), 0);
                        value -= Math.max(this.matcher(4, this.states().id), 0);
                }
                value = Math.max(value, -this.maxSlipDamage());
                if (value !== 0) {
                        this.gainHp(value);
        }
        };
       
        //Evaluation
        Game_Battler.prototype.regenerateMp = function() {
                var value = Math.floor(this.mmp * this.mrg);
                for (i = 0 ; i < this.states().length ; i++)
                {
                        value += Math.max(this.matcher(2, this.states().id), 0);
                        value -= Math.max(this.matcher(5, this.states().id), 0);
                }
                if (value !== 0) {
                        this.gainMp(value);
                }
        };
       
        //Evaluation
        Game_Battler.prototype.regenerateTp = function() {
                var value = Math.floor(100 * this.trg);
                for (i = 0 ; i < this.states().length ; i++)
                {
                        value += Math.max(this.matcher(3, this.states().id), 0);
                        value -= Math.max(this.matcher(6, this.states().id), 0);
                }
                this.gainSilentTp(value);
        };


})();


       
       
       
[/fold]


[fold=YEP_X_BattleSysATB汉化版]//=============================================================================
// Yanfly Engine Plugins - Battle System - Active Turn Battle
// YEP_X_BattleSysATB.js
//=============================================================================

var Imported = Imported || {};
Imported.YEP_X_BattleSysATB = true;

var Yanfly = Yanfly || {};
Yanfly.ATB = Yanfly.ATB || {};

//=============================================================================
/*:
* @plugindesc v1.17 (前置插件 YEP_BattleEngineCore.js)
*  增加 ATB (动态回合战斗系统) 到你的RPG游戏中!
* ---翻译 by 抖M俱乐部的 SmithJiong/bennett01/SOAP
* 转载请感谢我! 没错上面三个都是我!
* @author  Yanfly Engine Plugins
*
* @param ---动态回合战斗系统设置---
* @default
*
* @param Per Tick
* @desc 行动槽填充速度的基本单位默认为单位敏捷,也支公式。
* @default user.agi
*
*
* @param Initial Speed
* @desc  最初行动值,这个数值决定了战斗开始时行动槽位置。
* 如果设置为2000,最大值为10000,则行动槽将会从20%处开始。
* @default 0
*
* @param Full Gauge
* @desc  行动槽值,这个值满了以后角色将会开始行动。
* 默认值取5000或者最高敏战斗单位的敏捷值*100中的最大值。
* @default Math.max(5000, BattleManager.highestBaseAgi() * 100)
*
* @param Charge Gauge
* @desc 咏唱值,即选择技能-释放技能之间等待条,俗称咏唱条。
* 默认值为2000或者最高敏战斗单位的敏捷值*20中的最大者。
* @default Math.max(2000, BattleManager.highestBaseAgi() * 20)
*
* @param Pre-Emptive Bonuses
* @desc How much of the ATB bar do you want filled up for an
* ATB pre-emptive bonus from 0 to 1.
* @default 0.8
*
* @param Surprise Bonuses
* @desc How much of the ATB bar do you want filled up for an
* ATB surprise bonus from 0 to 1.
* @default 0.8
*
*
* @param ---逃跑---
* @default
*
* @param Escape Ratio
* @desc 该项用于设置逃跑几率,默认逃跑成功率为:
* 我方敏捷/敌方敏捷 * 50%,可以自己修改。
* @default 0.5 * $gameParty.agility() / $gameTroop.agility()
*
* @param Fail Escape Boost
* @desc 玩家每次逃跑失败后增加成功率,
* 默认每次增加2.5%,如增加50%就改成0.5。
* @default 0.025
*
* @param ---行动---
* @default
*
* @param Full Turn
* @desc 这个选项定义了充满行动槽需要的时间单位,
* 通过调整这个值可以改变动态战斗节奏,值越低速度就越慢。
* @default Math.min(200, BattleManager.lowestBaseAgi() * 8)
*
* @param Flash Enemy
* @desc 敌人使用技能时是否闪烁,开启设true 关闭设false 默认开启
* @default true
*
* @param ---弹性设置---
* @default
*
* @param Enable Rubberband
* @desc This is an auto-balance mechanic for AGI.
* Disable - false     Enable - true
* 启用这个选项来让系统自动平衡ATB系统的有关AGI的配置
* 避免出现设置不当造成的人物或怪物变成植物人等现象。
* @default true

*
* @param Minimum Speed
* @desc If rubberbanding is enabled, what is the minimum
* speed increase? This is a formula.
* 弹性系统被启用时,定义最小战斗速度的公式。
* @default 0.5 * BattleManager.highestBaseAgi()
*
* @param Maximum Speed
* @desc If rubberbanding is enabled, what is the maximum
* speed increase? This is a formula.
* 弹性系统被启用时,定义最小战斗速度的公式。
* @default 1.5 * BattleManager.highestBaseAgi()
*
* @param ---Sound--- 音效
* @default
*
* @param Ready Sound
* @desc This is the sound played when the battler is ready.
* 战斗单位准备行动时的音效
* @default Decision1
*
* @param Ready Volume
* @desc This is the volume of the ready sound.
* 准备行动音效的音量
* @default 90
*
* @param Ready Pitch
* @desc This is the pitch of the ready sound.
* 准备行动音效的音高
* @default 120
*
* @param Ready Pan
* @desc This is the pan of the ready sound.
* 准备行动音效的位相
* @default 0
*
* @param ---Options--- 其他设置
* @default
*
* @param ATB Speed Text
* @desc Text used for ATB speed in options window.
* 设置窗口中设置ATB系统速度选项的文本文字
* @default ATB Speed
*
* @param Default ATB Speed
* @desc Default speed at which the gauges fill up.
* ATB战斗速度选项1-10 1最慢 10最快 默认10
* 1 - slowest     10 - fastest
* @default 10
*
* @param ---窗口---
* @default
*
* @param Lock Status Window
* @desc ATB系统激活时,是否锁定状态窗口。true锁定,false不锁定。
* OFF - false     ON - true
* @default true
*
* @param Gauge Style
* @desc 行动槽类型0-不显示 1-人物名字前方 2-人物名字右方
* 0 - None     1 - Under Name     2 - Right Side
* @default 1
*
* @param Gauge Text
* @desc 使用类型2所显示的行动槽名称。
* @default Turn
*
* @param Gauge Text Align
* @desc 使用类型2字体的格式 left-居左 center-居中 right-靠右
* left     center     right
* @default center
*
* @param ATB Gauge Color 1
* @desc 第一动槽的颜色
* @default 13
*
* @param ATB Gauge Color 2
* @desc 第二行动槽的颜色
* @default 5
*
* @param Slow Gauge Color 1
* @desc 第一行动槽被减速效果影响时的颜色
* @default 12
*
* @param Slow Gauge Color 2
* @desc 第二行动槽被减速效果影响后的颜色
* @default 4
*
* @param Fast Gauge Color 1
* @desc 第一行动槽被加速后的颜色
* @default 26
*
* @param Fast Gauge Color 2
* @desc 第二行动槽被加速后的颜色
* @default 27
*
* @param Stop Gauge Color 1
* @desc 第一行动槽被停止后的颜色
* @default 7
*
* @param Stop Gauge Color 2
* @desc 第二行动槽被停止后的颜色
* @default 8
*
* @param Full Gauge Color 1
* @desc 第一行动槽充满后的颜色
* @default 14
*
* @param Full Gauge Color 2
* @desc 第二动槽充满后的颜色
* @default 6
*
* @param Charge Gauge Color 1
* @desc 第一咏唱条的颜色
* @default 2
*
* @param Charge Gauge Color 2
* @desc 第二咏唱条的颜色
* @default 10
*
* @help
* ============================================================================
* Introduction-关于本插件的介绍
* ---翻译 by 抖M俱乐部的 SmithJiong/bennett01/SOAP
* 转载请感谢我! 没错上面三个都是我!
* ============================================================================
*
* The Battle System - Active Turn Battle是一个基于Yanfly大神Battle Engine Core插件的拓展插件,
* 所以它无法脱离核心战斗插件独立工作,安装时务必将该插件放置于战斗核心插件-Battle Engine Core下方,
* 要启用ATB战斗系统,请在战斗核心插件的配置中,将Default System 选项由dtb修改为atb即可。
*
* ATB战斗系统是一个出色的动态战斗系统,它给角色定义了一个行动槽,当行动槽填充时,角色不能进行任何操作,
* 只有行动槽充满时,才可以进行相关操作如攻击、技能等等,行动后清空行动槽,当行动槽再次充满后,角色才可进行下一次行动。
* 角色选择技能以后,会进入第二阶段行动槽填充,通常被成为咏唱时间条的填充,第二阶段行动槽填满后,角色才会释放技能。
* 这种经典的战斗系统被很频繁用到了如最终幻想系列等很多游戏当中,这也使得传统RPG原本枯燥的回合战斗变得更加紧张、刺激和有趣味,
* 使用本系统,将使回合战斗中的更多战术和策略技能的设计研发成为可能。
*
* ATB战斗系统使各角色的敏捷属性不再是花瓶,敏捷将直接决定角色的出手顺序和出手速度,
* 通常来说敏捷高的角色比敏捷低的角色更具备优势,前提是你不要弄个负敏神兽出来...
*
* ============================================================================
* 插件命令
* ============================================================================
*
* 你可以使用下面的命令在游戏内事件里调用插件命令,来更改当前游戏的战斗系统:
*
* 插件命令:
*   setBattleSys ATB      将战斗模式改为 ATB 动态回合战斗系统.
*   setBattleSys DTB      将战斗模式改为 DTB 默认回合战斗系统.
*
* 使用这个命令可以实现游戏对战斗模式的实时切换。
* ============================================================================
* 注释命令
* ============================================================================
*
* 以下为影响的ATB系统的相关注释命令
*
* 技能与道具注释
*
*   <ATB Help>
*   text
*   text
*   </ATB Help>
*   这个命令可以给技能或道具添加专有的ATB说明信息,即如果启用了ATB战斗系统,
*   则在技能/道具说明中显示<ATB Help>中的text文字说明,如果使用DTB系统,则显示默认说明。
*
*   <ATB Speed: x>
*   <ATB Charge: x>
*   <ATB Gauge: x>
*   仅在ATB模式启用时可用。可以将目标单位的ATB行动值-speed、
*   咏唱值-Charge、综合值-Gauge的设置为一个固定数值。简单解释:
*   speed参数-决定了行动阶段行动槽的值
*   Charge参数-咏唱阶段的行动槽的值
*   Gauge参数-这个参数会同时影响以上两个阶段的行动槽值
*   例子:道具注释中写上<ATB Speed: 1000> 即表示使用该道具后,目标的行动槽值将被设置为1000
*   你要注意的是,如果你的行动槽值已经积攒到了10000,使用该道具后,将被置于1000,相当于减速,如果为0则反之。
*
*   <ATB Speed: x%>
*   <ATB Charge: x%>
*   <ATB Gauge: x%>
*   参照上面的命令,你可以将具体的X数值更换为百分比,这样ATB系统将根据行动槽最大值
*   来计算你要实现的具体数值大小
*   例子:道具注释中写明<ATB Charge: 50%> 表示该道具使用后咏唱槽数值将被设置为50%,如果目标未咏唱,则不生效。
*   如果目标咏唱超过50%,则将被强制重置为50%,相当于减速,如果为0反之。
*
*   <ATB Speed: +x>   or   <ATB Speed: -x>
*   <ATB Charge: +x>  or   <ATB Charge: -x>
*   <ATB Gauge: +x>   or   <ATB Gauge: -x>
*   同上,你可以将x参数上加入+号或者-号来表示在当前行动槽基础上增加或者减少,这个命令通常被用于加速/减速道具或技能的设计。
*   例子:<ATB Gauge: +50%>  
*
*   <ATB Speed: +x%>   or   <ATB Speed: -x%>
*   <ATB Charge: +x%>  or   <ATB Charge: -x%>
*   <ATB Gauge: +x%>   or   <ATB Gauge: -x%>
*   同上,你同样可以把增加减少数值修改为百分比。
*
*   <After ATB: x>
*   <After ATB: x%>
*   顾名思义,你可以在道具和技能注释中加入这个命令,标识使用该道具或技能后,对使用者行动槽的影响。
*   因为使用技能或道具后,行动槽必定会被清空,所以+/-就没有意义了,你要把X替换为数值或百分比。
*   例子:我在电光火石这个技能的注释中加入了<After ATB: 50%>这个命令,表示我使用电光火石技能后,
*   使用者的回合结束后,行动槽将从50%处开始增加,相当于下回合行动更快速了,是不是很吊?
*
*   <ATB Interrupt>
*   <ATB Interrupt: x%>
*   这个命令比较强悍,就是打断!没错,Iterrupt命令会在对进入咏唱条的角色使用后生效,打断对方目标咏唱,
*   清空目标行动槽。如果你使用了百分比参数,则表示有多少百分比的几率成功。
*   例子:我在小石头这个道具的注释命令中添加了<ATB Interrupt: 50%>这个命令,表示当我使用这个道具后,
*   目标如果正在咏唱,则有50%概率被打断,技能释放失败。如果目标没有在咏唱,则道具无效。
*
*   <Cannot ATB Interrupt>
*   当然你可以在技能中加入<Cannot ATB Interrupt>这个注释,表示该技能无法被打断,
*   如果有这个命令,任何带有打断命令的技能和道具都不会对这个技能生效了,请叫我BOSS
*
*   下面这些命令可以用在角色、职业、敌人、武器、护甲和状态注释命令中,不要用错地方哦:
*
*   <ATB Start: +x>
*   <ATB Start: +x%>
*   上面的命令可以让你在回合开始时,获得行动槽的加成,x为数值或者百分比。第一回合结束后,行动槽将从0开始计算。
*   例子:哈罗德的角色注释中我加入了<ATB Start: +20%>命令,表示哈罗德每次战斗开始时行动槽都会从20%开始计算,而不是0
*   在第一回合之后,哈罗德的行动槽恢复正常,与其他角色一样从0开始。
*
*   <ATB Turn: +x>
*   <ATB Turn: +x%>
*   这个命令表示每个回合的行动槽获得行动力加成,x为数值或者百分比。包括第一回合在内的每一个回合,行动槽都会从X或x%开始计算。
*   例子:我在时魔法师的职业注释中加入了<ATB Turn: +50%>这个命令,然后我把玛莎转职成了时魔法师,但是悲剧的小明还是黑魔法师
*   所以小明的行动槽每回合是从头开始计算的,而玛莎美女每回合的行动力都是从50%处开始计算,所以,玛莎比小明更快,此题得证。
*
* ============================================================================
* Lunatic Mode - Conditional ATB Speed and Conditional ATB Charge
* 狂人模式已开启?Lunatic这个单词我并不熟..然而我也不是二次元党,
* 据说二次元可以把这个词儿翻译成萝莉..
* ============================================================================
*
* 等等,上面那些基本命令已经满足不了你的编程小心脏了吗?我们为您提供了可以在注释区域混合JavaScript脚本拓展
* 命令的专用模式已经开启,Lunatic Mode 可以让你在注释命令区间内按你们的想法设置条件和触发器,前提是,你要懂
* 这方面的技术。喂喂,懂脚本什么的(说我吗?)应该都懂点点E文吧,不懂的我翻了这段有啥意义吗?好纠结...掀桌
*
*   技能和道具命令
*   <Target ATB Eval>
*   speed = x;
*   charge = x;
*   </Target ATB Eval>
*   不同于直接的<ATB Speed/Charge/Gauge>命令,这段命令的格式如上,你可以在注释区的Lunatic Mode中
*   使用更复杂的语句和公式定义speed charge参数,也支持if else while for等javascript脚本命令。
*
*   给一个例子:
*
*   <Target ATB Eval>
*   speed = target.hp / target.mhp * max;
*   charge = target.hp / target.mhp * max;
*   </Target ATB Eval>
*   上面这段代码实现了speed和charge按照目标单位的hp和最大hp的百分比进行修改,即目标血越少行动条填充的越多。
*   延伸一点,你也可以使用触发器,使用if target.hp < target.mhp * 30% 这种条件来决定这个技能什么时候可以被触发。
*
*   --- --- --- --- ---
*
*   <After ATB Eval>
*   speed = x;
*   </After ATB Eval>
*   这个命令类似于<Afer ATB> 可以让你设计动作完毕后,该动作对角色行动槽的影响,当然你也可以设计的很复杂。
*
*   例子君出现了:
*
*   <After ATB Eval>
*   speed = user.mp / user.mmp  ;
*   </After ATB Eval>
*   上面的代码实现了按照人物MP最大百分比来加成施法后行动条的回复量的功能。
*
*   --- --- --- --- ---
*
*   <ATB Interrupt Eval>
*   interrupt = true;
*   </ATB Interrupt Eval>
*   打断,没什么好说的,加入各种触发器和公式命令都是可以的。
*
*   例子君出现了:
*
*   <ATB Interrupt Eval>
*   if (user.hp > target.hp) {
*      interrupt = true;
*   }
*   </ATB Interrupt Eval>
*   上面的命令实现了当使用者的当前hp大于目标的hp时,打断才能成功。
*   给一个延伸的例子,通常我们想要给打断技能一个固定几率,然后增加一个附加值
*   比如,默认50%的概率
*
* ============================================================================
* Yanfly Engine Plugins - Battle Engine Extension - Action Sequence Commands
* 下面部分的命令将会与Battle Engine带来的基础Action行为密切相关,在学习命令时
* 建议先去Battle Engine插件中掌握如何使用Action Sequence的相关命令和内容
* ============================================================================
*
* You can make use of these extra ATB related action sequences.
* 本插件提供了更多的关于atb系统的action sequences命令,快把他们加入到你的
* 技能和战斗中来吧。
*
*=============================================================================
* ATB CHARGE: target, X
* ATB CHARGE: target, X%
* ATB CHARGE: targets, +X
* ATB CHARGE: targets, +X%
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 上面的命令参照charge咏唱条的设定,不过你可以把targets更换为其他值了,
* 具体请参照action sequence的帮助文件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usage Example: atb charge: targets, +5000
*                atb charge: target, -50%
*=============================================================================
*
*=============================================================================
* ATB GAUGE: target, X
* ATB GAUGE: target, X%
* ATB GAUGE: targets, +X
* ATB GAUGE: targets, +X%
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 参照Gauge设置,针对speed和charge两个参数同时生效。
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usage Example: atb gauge: targets, +5000
*                atb gauge: target, -50%
*=============================================================================
*
*=============================================================================
* ATB INTERRUPT: target
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 打断命令,没什么好说的,用sequence系统可以做成群体打断,全体打断,打断自己人,好开心
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usage Example: atb interrupt: targets
*=============================================================================
*
*=============================================================================
* ATB SPEED: target, X
* ATB SPEED: target, X%
* ATB SPEED: targets, +X
* ATB SPEED: targets, +X%
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 参照speed参数设置,你可以实现更多目标
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usage Example: atb speed: targets, +5000
*                atb speed: target, -50%
*=============================================================================
*
* ============================================================================
* Changelog-更新日志,我就不翻译了-。-!!最后转载请在感谢名单中纪念我!
* ============================================================================
*
* Version 1.17:
* - Made a mechanic change so that turn 0 ends immediately upon battle start
* rather than requiring a full turn to end.
*
* Version 1.16:
* - Added a fail safe setting up ATB Charges when the Cannot Move restriction
* is imposed upon an actor.
*
* Verison 1.15:
* - Implemented a Forced Action queue list. This means if a Forced Action
* takes place in the middle of an action, the action will resume after the
* forced action finishes rather than cancels it out like MV does.
*
* Version 1.14:
* - Added a speed position check for Instant Casts to maintain order position.
*
* Version 1.13:
* - Fixed a bug that doesn't update state turns properly.
* - Removed 'Turn Structure parameter' as it goes against the nature of a
* Tick-Based battle system.
*
* Version 1.12:
* - Added speed rebalance formulas for tick-based systems (innate).
*
* Version 1.11:
* - Fixed a bug that would still allow battlers to perform actions even if the
* actions got sealed midway through charging the action.
*
* Version 1.10:
* - Fixed a bug that would cause AutoBattlers to stall if they got added into
* the party mid-battle.
*
* Version 1.09:
* - Mechanic change for states that update on Action End to end at the end of
* a battler's turn instead of at the start.
*
* Version 1.08a:
* - Fixed a bug that crashed the game when enemies were confused.
* - Preparation for Enemy ATB Gauges.
*
* Version 1.07:
* - Added 'Flash Enemy' to plugin parameters to flash the enemy once when it
* starts charging a skill.
*
* Version 1.06:
* - Added pre-emptive and surprise attack mechanic plugin parameters!
*
* Version 1.05:
* - Fixed a bug with Forced Actions locking out the battle.
*
* Version 1.04:
* - Added the 'Per Tick' parameter for you to adjust the formula that governs
* the speed rate at which the ATB gauge fills up.
*
* Version 1.03:
* - Fixed a bug that caused the ATB Gauge appear slow with maxed AGI.
*
* Version 1.02c:
* - Fixed a bug with the ATB GAUGE and ATB CHARGE action sequences.
* - Fixed a bug with battlers still getting a turn after the battle is over.
* - Fixed a bug that prevented escaping.
* - Added math fail safes for calculating ATB charging.
*
* Version 1.01:
* - Fixed a bug with escaping causing battlers to go into infinite lock.
* - Fixed a bug with multiple victory messages.
* - Added fail safe to prevent infinite charging.
* - Added <Cannot ATB Interrupt Notetag>.
*
* Version 1.00:
* - It's doooooooone!
*/
//=============================================================================

if (Imported.YEP_BattleEngineCore) {

//=============================================================================
// Parameter Variables
//=============================================================================

Yanfly.Parameters = PluginManager.parameters('YEP_X_BattleSysATB');
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.ATBPerTick = String(Yanfly.Parameters['Per Tick']);
Yanfly.Param.ATBInitSpeed = String(Yanfly.Parameters['Initial Speed']);
Yanfly.Param.ATBFullGauge = String(Yanfly.Parameters['Full Gauge']);
Yanfly.Param.ATBChargeGauge = String(Yanfly.Parameters['Charge Gauge']);
Yanfly.Param.ATBPreEmptive = Number(Yanfly.Parameters['Pre-Emptive Bonuses']);
Yanfly.Param.ATBSurprise = Number(Yanfly.Parameters['Surprise Bonuses']);
Yanfly.Param.ATBEscapeRatio = String(Yanfly.Parameters['Escape Ratio']);
Yanfly.Param.ATBEscapeBoost = String(Yanfly.Parameters['Fail Escape Boost']);
Yanfly.Param.ATBFullTurn = String(Yanfly.Parameters['Full Turn']);
Yanfly.Param.ATBTurnStructure = false;
Yanfly.Param.ATBFlashEnemy = eval(String(Yanfly.Parameters['Flash Enemy']));
Yanfly.Param.ATBRubberband = String(Yanfly.Parameters['Enable Rubberband']);
Yanfly.Param.ATBMinSpeed = String(Yanfly.Parameters['Minimum Speed']);
Yanfly.Param.ATBMaxSpeed = String(Yanfly.Parameters['Maximum Speed']);
Yanfly.Param.ATBReadyName = String(Yanfly.Parameters['Ready Sound']);
Yanfly.Param.ATBReadyVol = Number(Yanfly.Parameters['Ready Volume']);
Yanfly.Param.ATBReadyPitch = Number(Yanfly.Parameters['Ready Pitch']);
Yanfly.Param.ATBReadyPan = Number(Yanfly.Parameters['Ready Pan']);
Yanfly.Param.ATBOptionSpeedTx = String(Yanfly.Parameters['ATB Speed Text']);
Yanfly.Param.ATBDefaultSpeed = Number(Yanfly.Parameters['Default ATB Speed']);
Yanfly.Param.ATBLockStatusWin = String(Yanfly.Parameters['Lock Status Window']);
Yanfly.Param.ATBGaugeStyle = Number(Yanfly.Parameters['Gauge Style']);
Yanfly.Param.ATBGaugeText = String(Yanfly.Parameters['Gauge Text']);
Yanfly.Param.ATBGaugeAlign = String(Yanfly.Parameters['Gauge Text Align']);
Yanfly.Param.ATBColorAtb1 = Number(Yanfly.Parameters['ATB Gauge Color 1']);
Yanfly.Param.ATBColorAtb2 = Number(Yanfly.Parameters['ATB Gauge Color 2']);
Yanfly.Param.ATBColorSlow1 = Number(Yanfly.Parameters['Slow Gauge Color 1']);
Yanfly.Param.ATBColorSlow2 = Number(Yanfly.Parameters['Slow Gauge Color 2']);
Yanfly.Param.ATBColorFast1 = Number(Yanfly.Parameters['Fast Gauge Color 1']);
Yanfly.Param.ATBColorFast2 = Number(Yanfly.Parameters['Fast Gauge Color 2']);
Yanfly.Param.ATBColorStop1 = Number(Yanfly.Parameters['Stop Gauge Color 1']);
Yanfly.Param.ATBColorStop2 = Number(Yanfly.Parameters['Stop Gauge Color 2']);
Yanfly.Param.ATBColorFull1 = Number(Yanfly.Parameters['Full Gauge Color 1']);
Yanfly.Param.ATBColorFull2 = Number(Yanfly.Parameters['Full Gauge Color 2']);
Yanfly.Param.ATBColorChar1 = Number(Yanfly.Parameters['Charge Gauge Color 1']);
Yanfly.Param.ATBColorChar2 = Number(Yanfly.Parameters['Charge Gauge Color 2']);

//=============================================================================
// DataManager
//=============================================================================

Yanfly.ATB.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function() {
    if (!Yanfly.ATB.DataManager_isDatabaseLoaded.call(this)) return false;
    DataManager.processATBNotetags1($dataSkills);
    DataManager.processATBNotetags1($dataItems);
    DataManager.processATBNotetags2($dataActors);
    DataManager.processATBNotetags2($dataClasses);
    DataManager.processATBNotetags2($dataEnemies);
    DataManager.processATBNotetags2($dataWeapons);
    DataManager.processATBNotetags2($dataArmors);
    DataManager.processATBNotetags2($dataStates);
    return true;
};

DataManager.processATBNotetags1 = function(group) {
  var noteA1 = /<(?:ATB GAUGE):[ ](\d+)>/i;
  var noteA2 = /<(?:ATB GAUGE):[ ]([\+\-]\d+)>/i;
  var noteA3 = /<(?:ATB GAUGE):[ ](\d+)([%%])>/i;
  var noteA4 = /<(?:ATB GAUGE):[ ]([\+\-]\d+)([%%])>/i;
  var noteB1 = /<(?:ATB SPEED):[ ](\d+)>/i;
  var noteB2 = /<(?:ATB SPEED):[ ]([\+\-]\d+)>/i;
  var noteB3 = /<(?:ATB SPEED):[ ](\d+)([%%])>/i;
  var noteB4 = /<(?:ATB SPEED):[ ]([\+\-]\d+)([%%])>/i;
  var noteC1 = /<(?:ATB CHARGE):[ ](\d+)>/i;
  var noteC2 = /<(?:ATB CHARGE):[ ]([\+\-]\d+)>/i;
  var noteC3 = /<(?:ATB CHARGE):[ ](\d+)([%%])>/i;
  var noteC4 = /<(?:ATB CHARGE):[ ]([\+\-]\d+)([%%])>/i;
  var noteS1 = /<(?:AFTER ATB):[ ](\d+)>/i;
  var noteS2 = /<(?:AFTER ATB):[ ](\d+)([%%])>/i;
  var noteI1 = /<(?:ATB INTERRUPT)>/i;
  var noteI2 = /<(?:ATB INTERRUPT):[ ](\d+)([%%])>/i;
  var noteI3 = /<(?:CANNOT ATB INTERRUPT)>/i;
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.setATBGaugeFlat = undefined;
    obj.addATBGaugeFlat = 0;
    obj.setATBGaugeRate = undefined;
    obj.addATBGaugeRate = 0.0;
    obj.setATBSpeedFlat = undefined;
    obj.addATBSpeedFlat = 0;
    obj.setATBSpeedRate = undefined;
    obj.addATBSpeedRate = 0.0;
    obj.setATBChargeFlat = undefined;
    obj.addATBChargeFlat = 0;
    obj.setATBChargeRate = undefined;
    obj.addATBChargeRate = 0.0;
    obj.afterATBFlat = undefined;
    obj.afterATBRate = undefined;
    obj.atbInterruptRate = 0;
    obj.cannotAtbInterrupt = false;
    var evalMode = 'none';
    obj.atbEval = '';
    obj.atbAfterEval = '';
    obj.atbInterruptEval = '';
    obj.atbHelp = undefined;

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata;
      if (line.match(noteA1)) {
        obj.setATBGaugeFlat = parseInt(RegExp.$1);
      } else if (line.match(noteA2)) {
        obj.addATBGaugeFlat = parseInt(RegExp.$1);
      } else if (line.match(noteA3)) {
        obj.setATBGaugeRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteA4)) {
        obj.addATBGaugeRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteB1)) {
        obj.setATBSpeedFlat = parseInt(RegExp.$1);
      } else if (line.match(noteB2)) {
        obj.addATBSpeedFlat = parseInt(RegExp.$1);
      } else if (line.match(noteB3)) {
        obj.setATBSpeedRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteB4)) {
        obj.addATBSpeedRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteC1)) {
        obj.setATBChargeFlat = parseInt(RegExp.$1);
      } else if (line.match(noteC2)) {
        obj.addATBChargeFlat = parseInt(RegExp.$1);
      } else if (line.match(noteC3)) {
        obj.setATBChargeRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteC4)) {
        obj.addATBChargeRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteS1)) {
        obj.afterATBFlat = parseInt(RegExp.$1);
      } else if (line.match(noteS2)) {
        obj.afterATBRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteI1)) {
        obj.atbInterruptRate = 1;
      } else if (line.match(noteI2)) {
        obj.atbInterruptRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteI3)) {
        obj.cannotAtbInterrupt = true;
      } else if (line.match(/<(?:TARGET ATB EVAL)>/i)) {
        evalMode = 'atb eval';
      } else if (line.match(/<\/(?:TARGET ATB EVAL)>/i)) {
        evalMode = 'none';
      } else if (line.match(/<(?:AFTER ATB EVAL)>/i)) {
        evalMode = 'after atb eval';
      } else if (line.match(/<\/(?:AFTER ATB EVAL)>/i)) {
        evalMode = 'none';
      } else if (line.match(/<(?:ATB INTERRUPT EVAL)>/i)) {
        evalMode = 'atb interrupt eval';
      } else if (line.match(/<\/(?:ATB INTERRUPT EVAL)>/i)) {
        evalMode = 'none';
      } else if (line.match(/<(?:ATB HELP)>/i)) {
        evalMode = 'atb help';
        obj.atbHelp = '';
      } else if (line.match(/<\/(?:ATB HELP)>/i)) {
        evalMode = 'none';
      } else if (evalMode === 'atb help') {
        obj.atbHelp = obj.atbHelp + line + '\n';
      } else if (evalMode === 'atb eval') {
        obj.atbEval = obj.atbEval + line + '\n';
      } else if (evalMode === 'after atb eval') {
        obj.atbAfterEval = obj.atbAfterEval + line + '\n';
      } else if (evalMode === 'atb interrupt eval') {
        obj.atbInterruptEval = obj.atbInterruptEval + line + '\n';
      }
    }
  }
};

DataManager.processATBNotetags2 = function(group) {
  var noteA1 = /<(?:ATB START):[ ]([\+\-]\d+)>/i;
  var noteA2 = /<(?:ATB START):[ ]([\+\-]\d+)([%%])>/i;
  var noteB1 = /<(?:ATB TURN):[ ]([\+\-]\d+)>/i;
  var noteB2 = /<(?:ATB TURN):[ ]([\+\-]\d+)([%%])>/i;
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.atbStartFlat = 0;
    obj.atbStartRate = 0;
    obj.atbTurnFlat = 0;
    obj.atbTurnRate = 0;
    var evalMode = 'none';
    obj.atbHelp = undefined;

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata;
      if (line.match(noteA1)) {
        obj.atbStartFlat = parseInt(RegExp.$1);
      } else if (line.match(noteA2)) {
        obj.atbStartRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteB1)) {
        obj.atbTurnFlat = parseInt(RegExp.$1);
      } else if (line.match(noteB2)) {
        obj.atbTurnRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(/<(?:ATB HELP)>/i)) {
        evalMode = 'atb help';
        obj.atbHelp = '';
      } else if (line.match(/<\/(?:ATB HELP)>/i)) {
        evalMode = 'none';
      } else if (evalMode === 'atb help') {
        obj.atbHelp = obj.atbHelp + line + '\n';
      }
    }
  }
};

//=============================================================================
// ConfigManager
//=============================================================================

ConfigManager.atbSpeed = Yanfly.Param.ATBDefaultSpeed;

Yanfly.ATB.ConfigManager_makeData = ConfigManager.makeData;
ConfigManager.makeData = function() {
    var config = Yanfly.ATB.ConfigManager_makeData.call(this);
    config.atbSpeed = this.atbSpeed;
    return config;
};

Yanfly.ATB.ConfigManager_applyData = ConfigManager.applyData;
ConfigManager.applyData = function(config) {
    Yanfly.ATB.ConfigManager_applyData.call(this, config);
    this.atbSpeed = this.readConfigATBSpeed(config, 'atbSpeed');
};

ConfigManager.readConfigATBSpeed = function(config, name) {
    var value = config[name];
    if (value !== undefined) {
        return Number(value).clamp(1, 10);
    } else {
        return Yanfly.Param.ATBDefaultSpeed.clamp(1, 10);
    }
};

//=============================================================================
// BattleManager
//=============================================================================

BattleManager.isATB = function() {
    return this.isBattleSystem('atb');
};

Yanfly.ATB.BattleManager_isTurnBased = BattleManager.isTurnBased;
BattleManager.isTurnBased = function() {
    if (this.isATB()) return false;
    return Yanfly.ATB.BattleManager_isTurnBased.call(this);
};

Yanfly.ATB.BattleManager_tickRate = BattleManager.tickRate;
BattleManager.tickRate = function() {
    var rate = Yanfly.ATB.BattleManager_tickRate.call(this);
    if (this.isATB()) rate *= this.atbTickRate();
    return rate;
};

BattleManager.atbTickRate = function() {
    var rate = 0.1 * ConfigManager.atbSpeed;
    return rate;
};

Yanfly.ATB.BattleManager_makeEscapeRatio = BattleManager.makeEscapeRatio;
BattleManager.makeEscapeRatio = function() {
    if (this.isATB()) {
      this._escapeRatio = eval(Yanfly.Param.ATBEscapeRatio);
      this._escapeFailBoost = eval(Yanfly.Param.ATBEscapeBoost);
    } else {
      this._escapeFailBoost = 0.1;
      Yanfly.ATB.BattleManager_makeEscapeRatio.call(this);
    }
};

Yanfly.ATB.BattleManager_startBattle = BattleManager.startBattle;
BattleManager.startBattle = function() {
    Yanfly.ATB.BattleManager_startBattle.call(this);
    if (this.isATB()) {
      this._phase = null;
      this.startATB();
    }
};

Yanfly.ATB.BattleManager_endBattle = BattleManager.endBattle;
BattleManager.endBattle = function(result) {
    Yanfly.ATB.BattleManager_endBattle.call(this, result);
    this.clearATBData();
};

BattleManager.startATB = function() {
    if (this._phase === 'battleEnd') return;
    this.clearATBData();
    this._atbTarget = Math.max(1, eval(Yanfly.Param.ATBFullGauge));
    this._atbCharge = Math.max(1, eval(Yanfly.Param.ATBChargeGauge));
    this._atbFullTurn = Math.max(1, eval(Yanfly.Param.ATBFullTurn));
    this._atbRubberband = eval(Yanfly.Param.ATBRubberband);
    if (this.atbRubberband()) {
      this._atbMinimumSpeed = Math.max(1, eval(Yanfly.Param.ATBMinSpeed));
      this._atbMaximumSpeed = Math.max(1, eval(Yanfly.Param.ATBMaxSpeed));
    }
    this._atbTicks = this._atbFullTurn;
    this._atbReadySound = {
      name: Yanfly.Param.ATBReadyName,
      volume: Yanfly.Param.ATBReadyVol,
      pitch: Yanfly.Param.ATBReadyPitch,
      pan: Yanfly.Param.ATBReadyPan
    }
    $gameParty.onATBStart();
    $gameTroop.onATBStart();
    this._phase = 'start';
};

BattleManager.clearATBData = function() {
    this._highestBaseAgi = undefined;
    this._averageBaseAgi = undefined;
    this._lowestBaseAgi = undefined;
    this._atbTarget = undefined;
    this._atbCharge = undefined;
    this._atbTarget = undefined;
    this._atbCharge = undefined;
    this._atbFullTurn = undefined;
    this._atbRubberband = undefined;
    this._atbMinimumSpeed = undefined;
    this._atbMaximumSpeed = undefined;
    this._atbTicks = 0;
};

BattleManager.atbTarget = function() {
    if (!this._atbTarget) this.startATB();
    return this._atbTarget;
};

BattleManager.atbCharge = function() {
    if (!this._atbCharge) this.startATB();
    return this._atbCharge;
};

BattleManager.atbRubberband = function() {
    return this._atbRubberband;
};

BattleManager.atbMinimumSpeed = function() {
    return this._atbMinimumSpeed;
};

BattleManager.atbMaximumSpeed = function() {
    return this._atbMaximumSpeed;
};

BattleManager.highestBaseAgi = function() {
    if (this._highestBaseAgi) return this._highestBaseAgi;
    var agi = 0;
    for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
      var battler = $gameParty.battleMembers();
      if (battler) agi = Math.max(agi, battler.agi);
    }
    for (var i = 0; i < $gameTroop.members().length; ++i) {
      var battler = $gameTroop.members();
      if (battler) agi = Math.max(agi, battler.agi);
    }
    this._highestBaseAgi = agi;
    return this._highestBaseAgi;
};

BattleManager.averageBaseAgi = function() {
    if (this._averageBaseAgi) return this._averageBaseAgi;
    var agi = 0;
    for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
      var battler = $gameParty.battleMembers();
      if (battler) agi += battler.agi;
    }
    for (var i = 0; i < $gameTroop.members().length; ++i) {
      var battler = $gameTroop.members();
      if (battler) agi += battler.agi;
    }
    var sum = $gameParty.battleMembers().length;
    sum += $gameTroop.members().length;
    this._averageBaseAgi = agi / sum;
    return this._averageBaseAgi;
};

BattleManager.lowestBaseAgi = function() {
    if (this._lowestBaseAgi) return this._lowestBaseAgi;
    var agi = this.highestBaseAgi();
    for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
      var battler = $gameParty.battleMembers();
      if (battler) agi = Math.min(agi, battler.agi);
    }
    for (var i = 0; i < $gameTroop.members().length; ++i) {
      var battler = $gameTroop.members();
      if (battler) agi = Math.min(agi, battler.agi);
    }
    this._lowestBaseAgi = agi;
    return this._lowestBaseAgi;
};

Yanfly.ATB.BattleManager_update = BattleManager.update;
BattleManager.update = function() {
    if (this.isATB()) {
      if (this.isBusy()) return;
      if (this.updateEvent()) return;
      if (this._phase === 'battleEnd') {
        return Yanfly.ATB.BattleManager_update.call(this);
      }
      if (this.checkBattleEnd()) return;
      if (this._phase === 'atb') {
        this.updateATBPhase();
      } else {
        Yanfly.ATB.BattleManager_update.call(this);
      }
    } else {
      Yanfly.ATB.BattleManager_update.call(this);
    }
};

Yanfly.ATB.BattleManager_updateEventMain = BattleManager.updateEventMain;
BattleManager.updateEventMain = function() {
    if (this.isATB()) {
      $gameTroop.updateInterpreter();
      $gameParty.requestMotionRefresh();
      if ($gameTroop.isEventRunning()) {
          return true;
      }
      $gameTroop.setupBattleEvent();
      if ($gameTroop.isEventRunning() || SceneManager.isSceneChanging()) {
          return true;
      }
      return false;
    } else {
      return Yanfly.ATB.BattleManager_updateEventMain.call(this);
    }
};

BattleManager.updateATBPhase = function() {
    var chargedBattler = this.getChargedATBBattler();
    if (chargedBattler) return this.startATBAction(chargedBattler);
    var readyBattler = this.getReadyATBBattler();
    if (readyBattler) {
      return this.startATBInput(readyBattler);
    } else {
      this.updateATBTicks();
      this.updateBattlerATB();
    }
};

BattleManager.updateATBTicks = function() {
    this._atbTicks += 1 * this.tickRate();
    if (this._atbTicks < this._atbFullTurn) return;
    $gameTroop.increaseTurn();
    this._atbTicks = 0;
    if (this.isTurnBased()) {
      this.endTurn();
    } else {
      this.endTurn();
    }
};

BattleManager.getChargedATBBattler = function() {
    if ($gameParty.aliveMembers() <= 0 || $gameTroop.aliveMembers() <= 0) {
      return false;
    }
    var fastest = false;
    for (var i = 0; i < this.allBattleMembers().length; ++i) {
      var battler = this.allBattleMembers();
      if (!battler) continue;
      if (!this.isBattlerATBCharged(battler)) continue;
      if (!fastest) {
        fastest = battler;
      } else if (battler.atbCharge() > fastest.atbCharge()) {
        fastest = battler;
      }
    }
    return fastest;
};

BattleManager.isBattlerATBCharged = function(battler) {
    if (!battler.isATBCharging()) return false;
    if (battler.atbChargeRate() < 1) return false;
    if (battler.isConfused()) {
      battler.makeActions();
      if (battler.isActor()) battler.makeConfusionActions();
    }
    return battler.currentAction() && battler.currentAction().item();
};

BattleManager.getReadyATBBattler = function() {
    var fastest = false;
    for (var i = 0; i < this.allBattleMembers().length; ++i) {
      var battler = this.allBattleMembers();
      if (!battler) continue;
      if (!this.isBattlerATBReady(battler)) continue;
      if (!fastest) {
        fastest = battler;
      } else if (battler.atbSpeed() > fastest.atbSpeed()) {
        fastest = battler;
      }
    }
    return fastest;
};

BattleManager.isBattlerATBReady = function(battler) {
    if (battler.atbRate() < 1) return false;
    if (battler.isATBCharging()) return false;
    if (battler.currentAction() && battler.currentAction().item()) {
      battler.setupATBCharge();
      return false;
    }
    return true;
};

BattleManager.updateBattlerATB = function() {
    $gameParty.updateTick();
    $gameTroop.updateTick();
    if (this._statusWindow) this.statusUpdateATB();
};

BattleManager.setATBPhase = function() {
    this._phase = 'atb';
};

Yanfly.ATB.BattleManager_startInput = BattleManager.startInput;
BattleManager.startInput = function() {
    if (this.isATB()) {
      this.setATBPhase();
    } else {
      Yanfly.ATB.BattleManager_startInput.call(this);
    }
};

Yanfly.ATB.BattleManager_selectNextCommand = BattleManager.selectNextCommand;
BattleManager.selectNextCommand = function() {
    if (this.isATB()) {
      if (!this.actor()) return this.setATBPhase();
      this.resetNonPartyActorATB();
      this.actor().setupATBCharge();
      this.actor().spriteStepBack();
      this.actor().requestMotionRefresh();
      this._actorIndex = undefined;
      var chargedBattler = this.getChargedATBBattler();
      if (chargedBattler) {
        this.startATBAction(chargedBattler);
      } else {
        this.setATBPhase();
      }
    } else {
      Yanfly.ATB.BattleManager_selectNextCommand.call(this);
    }
};

BattleManager.resetNonPartyActorATB = function() {
    for (var i = 0; i < $gameParty.allMembers().length; ++i) {
      var actor = $gameParty.allMembers();
      if (!actor) continue;
      if ($gameParty.battleMembers().contains(actor)) continue;
      actor.resetAllATB();
    }
};

Yanfly.ATB.BattleManager_selectPreviousCommand =
    BattleManager.selectPreviousCommand;
BattleManager.selectPreviousCommand = function() {
    if (this.isATB()) {
      var actorIndex = this._actorIndex;
      var scene = SceneManager._scene;
      scene.startPartyCommandSelection();
      this._actorIndex = actorIndex;
      BattleManager.actor().setActionState('undecided');
      BattleManager.actor().requestMotionRefresh();
    } else {
      Yanfly.ATB.BattleManager_selectPreviousCommand.call(this);
    }
};

Yanfly.ATB.BattleManager_startTurn = BattleManager.startTurn;
BattleManager.startTurn = function() {
    if (this.isATB() && !this.isTurnBased()) return;
    Yanfly.ATB.BattleManager_startTurn.call(this);
};

Yanfly.ATB.BattleManager_updateTurnEnd = BattleManager.updateTurnEnd;
BattleManager.updateTurnEnd = function() {
    if (this.isATB()) {
      this.setATBPhase();
    } else {
      Yanfly.ATB.BattleManager_updateTurnEnd.call(this);
    }
};

BattleManager.startATBInput = function(battler) {
    if (battler.isDead()) return;
    battler.makeActions();
    if (battler.isEnemy()) {
      battler.setupATBCharge();
      if (Yanfly.Param.ATBFlashEnemy) battler.requestEffect('whiten');
      var chargedBattler = this.getChargedATBBattler();
      if (chargedBattler) this.startATBAction(chargedBattler);
    } else if (battler.canInput()) {
      this._actorIndex = battler.index();
      this.playATBReadySound();
      battler.setActionState('inputting');
      battler.spriteStepForward();
      this._phase = 'input';
    } else if (battler.isConfused()) {
      battler.makeConfusionActions();
      battler.setupATBCharge();
    } else {
      battler.makeAutoBattleActions();
      battler.setupATBCharge();
    }
};

BattleManager.playATBReadySound = function() {
    AudioManager.playSe(this._atbReadySound);
};

BattleManager.startATBAction = function(battler) {
    this._subject = battler;
    var action = this._subject.currentAction();
    if (action && action.isValid()) {
      this.startAction();
    } else {
      this.endAction();
    }
};

Yanfly.ATB.BattleManager_endAction = BattleManager.endAction;
BattleManager.endAction = function() {
    if (this.isATB()) {
      this.endATBAction();
    } else {
      Yanfly.ATB.BattleManager_endAction.call(this);
    }
};

BattleManager.endATBAction = function() {
    if (Imported.YEP_BattleEngineCore) {
      if (this._processingForcedAction) this._phase = this._preForcePhase;
      this._processingForcedAction = false;
    }
    if (this._subject) this._subject.onAllActionsEnd();
    if (this.updateEventMain()) return;
    this._subject.endTurnAllATB();
    if (this.loadPreForceActionSettings()) return;
    var chargedBattler = this.getChargedATBBattler();
    if (chargedBattler) {
      this.startATBAction(chargedBattler);
    } else {
      this.setATBPhase();
    }
};

BattleManager.statusUpdateATB = function() {
    this._statusWindow.redrawATB();
};

Yanfly.ATB.BattleManager_processEscape = BattleManager.processEscape;
BattleManager.processEscape = function() {
    if (this.isATB()) {
      return this.processEscapeATB();
    } else {
      return Yanfly.ATB.BattleManager_processEscape.call(this);
    }
};

BattleManager.processEscapeATB = function() {
  $gameParty.performEscape();
  SoundManager.playEscape();
  var success = this._preemptive ? true : (Math.random() < this._escapeRatio);
  if (success) {
      $gameParty.removeBattleStates();
      $gameParty.performEscapeSuccess();
      this.displayEscapeSuccessMessage();
      this._escaped = true;
      this.processAbort();
  } else {
      this.actor().spriteStepBack();
      this.actor().clearActions();
      this.displayEscapeFailureMessage();
      this._escapeRatio += this._escapeFailBoost;
      this.startTurn();
      this.processFailEscapeATB();
  }
  return success;
};

BattleManager.processFailEscapeATB = function() {
    var actor = $gameParty.members()[this._actorIndex];
    if (!actor) return;
    actor.resetAllATB();
};

Yanfly.ATB.BattleManager_processActionSequence =
  BattleManager.processActionSequence;
BattleManager.processActionSequence = function(actionName, actionArgs) {
  if (this.isATB()) {
    // ATB CHARGE
    if (actionName === 'ATB CHARGE') {
      return this.actionATBCharge(actionArgs);
    }
    // ATB GAUGE
    if (actionName === 'ATB GAUGE') {
      return this.actionATBCharge(actionArgs) && this.actionATBSpeed(actionArgs);
    }
    // ATB INTERRUPT
    if (actionName === 'ATB INTERRUPT') {
      return this.actionATBInterrupt(actionArgs);
    }
    // ATB SPEED
    if (actionName === 'ATB SPEED') {
      return this.actionATBSpeed(actionArgs);
    }
  }
  return Yanfly.ATB.BattleManager_processActionSequence.call(this,
    actionName, actionArgs);
};

BattleManager.actionATBCharge = function(actionArgs) {
    var targets = this.makeActionTargets(actionArgs[0]);
    if (targets.length < 1) return true;
    var cmd = actionArgs[1];
    if (cmd.match(/([\+\-]\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isATBCharging()) continue;
        var max = target.atbChargeDenom();
        var value = rate * max + target.atbCharge();
        target.setATBCharge(value);
        target.refresh();
      }
    } else if (cmd.match(/([\+\-]\d+)/i)) {
      var plus = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isATBCharging()) continue;
        var value = plus + target.atbCharge();
        target.setATBCharge(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isATBCharging()) continue;
        var max = target.atbChargeDenom();
        var value = rate * max;
        target.setATBCharge(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)/i)) {
      var value = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isATBCharging()) continue;
        target.setATBCharge(value);
        target.refresh();
      }
    }
    return true;
};

BattleManager.actionATBInterrupt = function(actionArgs) {
    var targets = this.makeActionTargets(actionArgs[0]);
    if (targets.length < 1) return true;
    for (var i = 0; i < targets.length; ++i) {
      var target = targets;
      if (!target) continue;
      if (target === this._subject) continue;
      if (!target.isATBCharging()) continue;
      target.processATBInterrupt();
    }
    return true;
};

BattleManager.actionATBSpeed = function(actionArgs) {
    var targets = this.makeActionTargets(actionArgs[0]);
    if (targets.length < 1) return true;
    var cmd = actionArgs[1];
    if (cmd.match(/([\+\-]\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      var max = this.atbTarget();
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isATBCharging()) continue;
        var value = rate * max + target.atbSpeed();
        target.setATBSpeed(value);
        target.refresh();
      }
    } else if (cmd.match(/([\+\-]\d+)/i)) {
      var plus = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isATBCharging()) continue;
        var value = plus + target.atbSpeed();
        target.setATBSpeed(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      var max = this.atbTarget();
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isATBCharging()) continue;
        var value = rate * max;
        target.setATBSpeed(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)/i)) {
      var value = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isATBCharging()) continue;
        target.setATBSpeed(value);
        target.refresh();
      }
    }
    return true;
};

//=============================================================================
// Game_Action
//=============================================================================

Yanfly.ATB.Game_Action_applyItemUserEffect =
    Game_Action.prototype.applyItemUserEffect;
Game_Action.prototype.applyItemUserEffect = function(target) {
    Yanfly.ATB.Game_Action_applyItemUserEffect.call(this, target);
    if (BattleManager.isATB() && $gameParty.inBattle()) {
      this.applyItemATBEffect(target);
    }
};

Game_Action.prototype.applyItemATBEffect = function(target) {
  if (!target) return;
  this.applyItemATBSetEffects(target);
  this.applyItemATBAddEffects(target);
  this.applyItemATBEvalEffect(target);
  this.applyItemATBInterrupt(target);
  this.applyItemATBInterruptEval(target);
};

Game_Action.prototype.applyItemATBSetEffects = function(target) {
  var item = this.item();
  if (!item) return;
  var value = undefined;
  if (target.isATBCharging()) {
    var max = target.atbChargeDenom();
    if (item.setATBChargeFlat !== undefined) {
      value = item.setATBChargeFlat;
    } else if (item.setATBGaugeFlat !== undefined) {
      value = item.setATBGaugeFlat;
    } else if (item.setATBChargeRate !== undefined) {
      value = item.setATBChargeRate * max;
    } else if (item.setATBGaugeRate !== undefined) {
      value = item.setATBGaugeRate * max;
    }
    if (value !== undefined) target.setATBCharge(value);
  } else {
    var max = BattleManager.atbTarget();
    if (item.setATBSpeedFlat !== undefined) {
      value = item.setATBSpeedFlat;
    } else if (item.setATBGaugeFlat !== undefined) {
      value = item.setATBGaugeFlat;
    } else if (item.setATBSpeedRate !== undefined) {
      value = item.setATBSpeedRate * max;
    } else if (item.setATBGaugeRate !== undefined) {
      value = item.setATBGaugeRate * max;
    }
    if (value !== undefined) target.setATBSpeed(value);
  }
  if (value !== undefined && target.isActor()) BattleManager.statusUpdateATB();
};

Game_Action.prototype.applyItemATBAddEffects = function(target) {
    var item = this.item();
    if (!item) return;
    if (target.isATBCharging()) {
      var value = target.atbCharge();
      var max = target.atbChargeDenom();
      value += item.addATBChargeRate * max;
      value += item.addATBGaugeRate * max;
      value += item.addATBChargeFlat;
      value += item.addATBGaugeFlat;
      target.setATBCharge(value);
    } else {
      var value = target.atbSpeed();
      var max = BattleManager.atbTarget()
      value += item.addATBSpeedRate * max;
      value += item.addATBGaugeRate * max;
      value += item.addATBSpeedFlat;
      value += item.addATBGaugeFlat;
      target.setATBSpeed(value);
    }
    if (value !== 0 && target.isActor()) BattleManager.statusUpdateATB();
};

Game_Action.prototype.applyItemATBEvalEffect = function(target) {
    var a = this.subject();
    var user = this.subject();
    var b = target;
    var item = this.item();
    var skill = this.item();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var speed = target.atbSpeed();
    var charge = target.atbCharge();
    if (target.isATBCharging()) {
      var max = target.atbChargeDenom();
    } else {
      var max = BattleManager.atbTarget();
    }
    eval(item.atbEval);
    target.setATBSpeed(speed);
    target.setATBCharge(charge);
};

Game_Action.prototype.applyItemATBInterrupt = function(target) {
    var item = this.item();
    if (!item) return;
    if (target === this.subject()) return;
    if (!target.isATBCharging()) return;
    if (item.atbInterruptRate <= 0) return;
    var success = (Math.random() < item.atbInterruptRate);
    if (success) target.processATBInterrupt();
};

Game_Action.prototype.applyItemATBInterruptEval = function(target) {
    var item = this.item();
    if (!item) return;
    if (target === this.subject()) return;
    if (!target.isATBCharging()) return;
    if (item.atbInterruptEval === '') return;
    var interrupt = false;
    var a = this.subject();
    var user = this.subject();
    var b = target;
    var item = this.item();
    var skill = this.item();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var speed = target.atbSpeed();
    var charge = target.atbCharge();
    eval(item.atbInterruptEval);
    if (interrupt) target.processATBInterrupt();
};

Game_Action.prototype.rebalanceATBSpeed = function(target) {
    var speed = this.subject().atbSpeed();
    var offset = 00000000001;
    speed = Math.max(speed + offset, target.atbSpeed() + target.atbCharge());
    this.subject().setATBSpeed(speed);
};

//=============================================================================
// Game_Battlerbase
//=============================================================================

Yanfly.ATB.Game_BattlerBase_refresh = Game_BattlerBase.prototype.refresh;
Game_BattlerBase.prototype.refresh = function() {
    Yanfly.ATB.Game_BattlerBase_refresh.call(this);
    if (BattleManager.isATB() && $gameParty.inBattle()) {
      this._atbTickValue = undefined;
    }
};

Yanfly.ATB.Game_BattlerBase_die = Game_BattlerBase.prototype.die;
Game_BattlerBase.prototype.die = function() {
    Yanfly.ATB.Game_BattlerBase_die.call(this);
    if (BattleManager.isATB() && $gameParty.inBattle()) this.resetAllATB();
};

//=============================================================================
// Game_Battler
//=============================================================================

Game_Battler.prototype.onATBStart = function() {
    this._atbSpeed = eval(Yanfly.Param.ATBInitSpeed);
    this._atbSpeed += BattleManager.atbTarget() * this.atbStartRate();
    this._atbSpeed += this.atbStartFlat();
    this._atbCharge = 0;
    this._atbCharging = false;
    this._atbChargeMod = 0;
    this.applyPreemptiveBonusATB();
    this.applySurpriseBonusATB();
    this.refresh();
};

Game_Battler.prototype.applyPreemptiveBonusATB = function() {
    if (!BattleManager._preemptive) return;
    if (!this.isActor()) return;
    var rate = Yanfly.Param.ATBPreEmptive;
    this._atbSpeed += rate * BattleManager.atbTarget();
};

Game_Battler.prototype.applySurpriseBonusATB = function() {
    if (!BattleManager._surprise) return;
    if (!this.isEnemy()) return;
    var rate = Yanfly.Param.ATBSurprise;
    this._atbSpeed += rate * BattleManager.atbTarget();
};

Yanfly.ATB.Game_Battler_onBattleEnd = Game_Battler.prototype.onBattleEnd;
Game_Battler.prototype.onBattleEnd = function() {
    Yanfly.ATB.Game_Battler_onBattleEnd.call(this);
    this._atbSpeed = 0;
    this._atbCharge = 0;
    this._atbCharging = false;
    this._atbChargeMod = 0;
};

Game_Battler.prototype.atbSpeed = function() {
    if (this._atbSpeed === undefined) this.onATBStart();
    return this._atbSpeed;
};

Game_Battler.prototype.atbRate = function() {
    if (this._atbSpeed === undefined) this.onATBStart();
    var rate = this._atbSpeed / BattleManager.atbTarget();
    return rate.clamp(0, 1);
};

Game_Battler.prototype.isATBCharging = function() {
    return this._atbCharging;
};

Game_Battler.prototype.setATBCharging = function(value) {
    this._atbCharging = value;
};

Game_Battler.prototype.atbCharge = function() {
  if (this._atbCharge === undefined) this.onATBStart();
  return this._atbCharge;
};

Game_Battler.prototype.atbChargeDenom = function() {
    var denom = Math.max(1, BattleManager.atbCharge() - this._atbChargeMod);
    return denom;
};

Game_Battler.prototype.atbChargeRate = function() {
    if (this._atbCharge === undefined) this.onATBStart();
    if (!this.isATBCharging()) return 0;
    var rate = this._atbCharge / this.atbChargeDenom();
    return rate.clamp(0, 1);
};

Game_Battler.prototype.setATBSpeed = function(value) {
    this._atbSpeed = Math.max(0, value);
};

Game_Battler.prototype.setATBCharge = function(value) {
    if (this.isATBCharging()) this._atbCharge = Math.max(0, value);
};

Game_Battler.prototype.setupATBCharge = function() {
    this.setATBCharging(true);
    if (!this.currentAction()) this.makeActions();
    if (this.currentAction()) {
      var item = this.currentAction().item();
      if (item) {
        this._atbChargeMod = item.speed;
      } else {
        this._atbChargeMod = 0;
      }
    } else {
      this._atbChargeMod = 0;
    }   
    this.setATBCharge(0);
    this.setActionState('waiting');
    if (BattleManager.isTickBased()) this.onTurnStart();
};

Yanfly.ATB.Game_Battler_updateTick = Game_Battler.prototype.updateTick;
Game_Battler.prototype.updateTick = function() {
    Yanfly.ATB.Game_Battler_updateTick.call(this);
    if (BattleManager.isATB()) this.updateATB();
};

Game_Battler.prototype.updateATB = function() {
    if (this.isDead()) return this.resetAllATB();
    if (!this.canMove()) {
      this.updateATBStates();
      return;
    }
    if (this.isATBCharging()) {
      if (!this.currentAction()) this.resetAllATB();
      if (this.currentAction() && this.currentAction().item() === null) {
        this.resetAllATB();
      }
    }
    if (this.isATBCharging()) {
      var value = this.atbCharge() + this.atbSpeedTick();
      this.setATBCharge(value);
    } else if (this.atbRate() < 1) {
      var value = this.atbSpeed() + this.atbSpeedTick();
      this.setATBSpeed(value);
    }
};

Game_Battler.prototype.updateATBStates = function() {
    if (BattleManager.timeBasedBuffs()) return;
    for (var i = 0; i < this._states.length; ++i) {
      var stateId = this._states;
      var state = $dataStates[stateId];
      if (!state) continue;
      if (!this._stateTurns[stateId]) continue;
      if (state.restriction >= 4 && state.autoRemovalTiming !== 0) {
        var value = BattleManager.tickRate() / Yanfly.Param.BECTurnTime;
        this._stateTurns[stateId] -= value;
        if (this._stateTurns[stateId] <= 0) this.removeState(stateId);
      }
    }
};

Game_Battler.prototype.resetAllATB = function() {
    this._atbCharge = 0;
    this._atbChargeMod = 0;
    this._atbCharging = false;
    this._atbSpeed = 0;
    this.clearActions();
};

Game_Battler.prototype.endTurnAllATB = function() {
    this._atbCharge = 0;
    this._atbChargeMod = 0;
    this._atbCharging = false;
    if (this.checkATBEndInstantCast()) return;
    this.setEndActionATBSpeed();
    this.clearActions();
    this.setActionState('undecided');
    if (this.battler()) this.battler().refreshMotion();
    if (BattleManager.isTickBased()) this.onTurnEnd();
};

Game_Battler.prototype.checkATBEndInstantCast = function() {
    if (!Imported.YEP_InstantCast) return false;
    var action = this.currentAction();
    if (!action) return false;
    var item = action.item();
    if (!item) return false;
    if (!this.isInstantCast(item)) return false;
    var length = BattleManager.allBattleMembers().length;
    for (var i = 0; i < length; ++i) {
      var member = BattleManager.allBattleMembers();
      if (!member) continue;
      var max = member.atbSpeed() + member.atbCharge();
      this._atbSpeed = Math.max(this._atbSpeed, max);
    }
    this._atbSpeed = Math.max(this._atbSpeed, BattleManager.atbTarget());
    this._atbSpeed += 0.00000000001;
    return true;
};

Game_Battler.prototype.atbSpeedRate = function() {
    if (!this.canMove()) return 0;
    var base = this.paramBase(6) + this.paramPlus(6);
    if (base >= this.paramMax(6) && this.agi >= this.paramMax(6)) return 1;
    var rate = this.agi / base;
    return rate;
};

Game_Battler.prototype.atbSpeedTick = function() {
    var value = this.atbTickValue();
    if (BattleManager.atbRubberband()) {
      var min = BattleManager.atbMinimumSpeed();
      var max = BattleManager.atbMaximumSpeed();
      value = value.clamp(min, max);
    }
    return value * BattleManager.tickRate();
};

Game_Battler.prototype.atbTickValue = function() {
    if (this._atbTickValue !== undefined) return this._atbTickValue;
    var a = this;
    var user = this;
    var subject = this;
    this._atbTickValue = eval(Yanfly.Param.ATBPerTick);
    return this._atbTickValue;
};

Game_Battler.prototype.setEndActionATBSpeed = function() {
    this._atbSpeed = 0;
    var action = this.currentAction();
    if (!action) return;
    var item = action.item();;
    if (item) {
      if (item.afterATBFlat !== undefined) this.setATBSpeed(item.afterATBFlat);
      if (item.afterATBRate !== undefined) {
        this.setATBSpeed(item.afterATBRate * BattleManager.atbTarget());
      }
    }
    this._atbSpeed += BattleManager.atbTarget() * this.atbTurnRate();
    this._atbSpeed += this.atbTurnFlat();
    if (item) this.afterATBEval(item);
};

Game_Battler.prototype.afterATBEval = function(item) {
    if (!item) return;
    var a = this;
    var user = this;
    var skill = item;
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var speed = this._atbSpeed;
    var max = BattleManager.atbTarget();
    eval(item.atbAfterEval);
    this.setATBSpeed(speed);
};

Game_Battler.prototype.processATBInterrupt = function() {
    if (this.currentAction()) {
      var item = this.currentAction().item();
      if (item && item.cannotAtbInterrupt) return;
    }
    this.resetAllATB();
    this.refresh();
};

Game_Battler.prototype.atbStartFlat = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.atbStartFlat;
    }
    return value;
};

Game_Battler.prototype.atbStartRate = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.atbStartRate;
    }
    return value;
};

Game_Battler.prototype.atbTurnFlat = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.atbTurnFlat;
    }
    return value;
};

Game_Battler.prototype.atbTurnRate = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.atbTurnRate;
    }
    return value;
};

Yanfly.ATB.Game_Battler_removeState = Game_Battler.prototype.removeState;
Game_Battler.prototype.removeState = function(stateId) {
    if (BattleManager.isATB()) {
      var confuseCondition = this.isConfused();
    }
    Yanfly.ATB.Game_Battler_removeState.call(this, stateId);
    if (BattleManager.isATB()) {
      if (confuseCondition !== this.isConfused()) this.resetAllATB();
    }
};

//=============================================================================
// Game_Actor
//=============================================================================

Game_Actor.prototype.atbStartFlat = function() {
    var value = Game_Battler.prototype.atbStartFlat.call(this);
    value += this.actor().atbStartFlat;
    value += this.currentClass().atbStartFlat;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.atbStartFlat) value += equip.atbStartFlat;
    }
    return value;
};

Game_Actor.prototype.atbStartRate = function() {
    var value = Game_Battler.prototype.atbStartRate.call(this);
    value += this.actor().atbStartRate;
    value += this.currentClass().atbStartRate;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.atbStartRate) value += equip.atbStartRate;
    }
    return value;
};

Game_Actor.prototype.atbTurnFlat = function() {
    var value = Game_Battler.prototype.atbTurnFlat.call(this);
    value += this.actor().atbTurnFlat;
    value += this.currentClass().atbTurnFlat;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.atbTurnFlat) value += equip.atbTurnFlat;
    }
    return value;
};

Game_Actor.prototype.atbTurnRate = function() {
    var value = Game_Battler.prototype.atbTurnRate.call(this);
    value += this.actor().atbTurnRate;
    value += this.currentClass().atbTurnRate;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.atbTurnRate) value += equip.atbTurnRate;
    }
    return value;
};

//=============================================================================
// Game_Enemy
//=============================================================================

Game_Enemy.prototype.atbStartFlat = function() {
    var value = Game_Battler.prototype.atbStartFlat.call(this);
    value += this.enemy().atbStartFlat;
    return value;
};

Game_Enemy.prototype.atbStartRate = function() {
    var value = Game_Battler.prototype.atbStartRate.call(this);
    value += this.enemy().atbStartRate;
    return value;
};

Game_Enemy.prototype.atbTurnFlat = function() {
    var value = Game_Battler.prototype.atbTurnFlat.call(this);
    value += this.enemy().atbTurnFlat;
    return value;
};

Game_Enemy.prototype.atbTurnRate = function() {
    var value = Game_Battler.prototype.atbTurnRate.call(this);
    value += this.enemy().atbTurnRate;
    return value;
};

//=============================================================================
// Game_Unit
//=============================================================================

Game_Unit.prototype.onATBStart = function() {
    if (!BattleManager.isATB()) return;
    for (var i = 0; i < this.members().length; ++i) {
      var member = this.members();
      if (member) member.onATBStart();
    }
};

Game_Unit.prototype.increaseTurnTimeBasedATB = function() {
    for (var i = 0; i < this.members().length; ++i) {
      var member = this.members();
      if (!member) continue;
      if (member.isDead()) continue;
      if (member.isHidden()) continue;
      if (member.canMove()) continue;
      member.onTurnEnd();
    }
};

//=============================================================================
// Game_Party
//=============================================================================

Yanfly.ATB.Game_Party_performEscape = Game_Party.prototype.performEscape;
Game_Party.prototype.performEscape = function() {
    if (BattleManager.isATB()) return;
    Yanfly.ATB.Game_Party_performEscape.call(this);
};

//=============================================================================
// Game_Troop
//=============================================================================

Yanfly.ATB.Game_Troop_increaseTurn = Game_Troop.prototype.increaseTurn;
Game_Troop.prototype.increaseTurn = function() {
    Yanfly.ATB.Game_Troop_increaseTurn.call(this);
    if (BattleManager.isATB() && BattleManager.timeBasedStates()) {
      $gameParty.increaseTurnTimeBasedATB();
      this.increaseTurnTimeBasedATB();
    }
};

//=============================================================================
// Window_Base
//=============================================================================

Window_Base.prototype.atbGaugeStyle = function() {
    return Yanfly.Param.ATBGaugeStyle
};

Window_Base.prototype.atbGaugeColor1 = function(actor) {
    if (actor.atbRate() < 1) {
      if (actor.atbSpeedRate() === 0) {
        return this.textColor(Yanfly.Param.ATBColorStop1);
      } else if (actor.atbSpeedRate() > 1) {
        return this.textColor(Yanfly.Param.ATBColorFast1);
      } else if (actor.atbSpeedRate() < 1) {
        return this.textColor(Yanfly.Param.ATBColorSlow1);
      } else {
        return this.textColor(Yanfly.Param.ATBColorAtb1);
      }
    } else if (actor.atbRate() >= 1 && actor.atbChargeRate() >= 0) {
      return this.textColor(Yanfly.Param.ATBColorFull1);
    } else {
      return this.gaugeBackColor();
    }
};

Window_Base.prototype.atbGaugeColor2 = function(actor) {
    if (actor.atbRate() < 1) {
      if (actor.atbSpeedRate() === 0) {
        return this.textColor(Yanfly.Param.ATBColorStop2);
      } else if (actor.atbSpeedRate() > 1) {
        return this.textColor(Yanfly.Param.ATBColorFast2);
      } else if (actor.atbSpeedRate() < 1) {
        return this.textColor(Yanfly.Param.ATBColorSlow2);
      } else {
        return this.textColor(Yanfly.Param.ATBColorAtb2);
      }
    } else if (actor.atbRate() >= 1 && actor.atbChargeRate() >= 0) {
      return this.textColor(Yanfly.Param.ATBColorFull2);
    } else {
      return this.gaugeBackColor();
    }
};

Window_Base.prototype.drawActorAtbGauge = function(actor, wx, wy, ww) {
    ww = ww || 96;
    if (!actor) return;
    var color1 = this.atbGaugeColor1(actor);
    var color2 = this.atbGaugeColor2(actor);
    if (actor.atbRate() < 1) {
      var rate = actor.atbRate();
    } else if (actor.atbRate() >= 1 && actor.atbChargeRate() >= 0) {
      var rate = 1;
    } else {
      var rate = 0;
    }
    this.drawGauge(wx, wy, ww, rate, color1, color2);
    if (actor.atbChargeRate() > 0) this.drawAtbChargeGauge(actor, wx, wy, ww);
    if (this.atbGaugeStyle() === 2) {
      var text = Yanfly.Param.ATBGaugeText;
      var align =Yanfly.Param.ATBGaugeAlign;
      if (actor.atbRate() >= 1) {
        this.changeTextColor(this.normalColor());
      } else {
        this.changeTextColor(this.systemColor());
      }
      this.drawText(text, wx, wy, ww, align);
      this.resetTextColor();
    }
};

Window_Base.prototype.drawAtbChargeGauge = function(actor, wx, wy, ww) {
    var color1 = this.textColor(Yanfly.Param.ATBColorChar1);
    var color2 = this.textColor(Yanfly.Param.ATBColorChar2);
    var rate = actor.atbChargeRate();
    this.drawGauge(wx, wy, ww * rate, 1, color1, color2);
};

//=============================================================================
// Window_Help
//=============================================================================

Yanfly.ATB.Window_Help_setItem = Window_Help.prototype.setItem;
Window_Help.prototype.setItem = function(item) {
    if (this.meetATBConditions(item)) return this.setText(item.atbHelp);
    Yanfly.ATB.Window_Help_setItem.call(this, item);
};

Window_Help.prototype.meetATBConditions = function(item) {
    if (!item) return false;
    if (!BattleManager.isATB()) return false;
    return item.atbHelp !== undefined;
};

//=============================================================================
// Window_BattleStatus
//=============================================================================

Window_BattleStatus.prototype.redrawATB = function() {
  if (this.isATBGaugeStyle(0)) return;
  var rect;
  for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
    var actor = $gameParty.battleMembers();
    if (this.isATBGaugeStyle(1)) {
      rect = this.basicAreaRect(i);
      this.contents.clearRect(rect.x - 1, rect.y, rect.width + 2, rect.height);
      this.drawBasicArea(rect, actor);
    } else if (this.isATBGaugeStyle(2)) {
      this.redrawATBGaugeRect(i, actor);
    }
  }
};

Window_BattleStatus.prototype.redrawATBGaugeRect = function(index, actor) {
  var rect = this.gaugeAreaRect(index);
  var clrect = this.gaugeAreaRect(index);
  var totalArea = this.gaugeAreaWidth();
  if ($dataSystem.optDisplayTp) {
    var gw = totalArea / 4 - 15;
    clrect.x = rect.x + gw * 3 + 44;
    clrect.y = rect.y;
    clrect.width = gw + 2;
    this.contents.clearRect(clrect.x, clrect.y, clrect.width, clrect.height);
    this.drawActorAtbGauge(actor, rect.x + gw * 3 + 45, rect.y, gw);
  } else {
    totalArea -= 30;
    var hpW = parseInt(totalArea * 108 / 300);
    var otW = parseInt(totalArea * 96 / 300);
    clrect.x = rect.x + hpW + otW + 29;
    clrect.y = rect.y;
    clrect.width = otW + 2;
    this.contents.clearRect(clrect.x, clrect.y, clrect.width, clrect.height);
    this.drawActorAtbGauge(actor, rect.x + hpW + otW + 30, rect.y, otW);
  }
};

Window_BattleStatus.prototype.isATBGaugeStyle = function(type) {
    if (this.atbGaugeStyle() !== type) return false;
    if (!BattleManager.isATB()) return false;
    return (SceneManager._scene instanceof Scene_Battle);
};

Yanfly.ATB.Window_BattleStatus_drawBasicArea =
    Window_BattleStatus.prototype.drawBasicArea;
Window_BattleStatus.prototype.drawBasicArea = function(rect, actor) {
    if (this.isATBGaugeStyle(1)) {
      this.drawActorAtbGauge(actor, rect.x, rect.y, rect.width);
    }
    Yanfly.ATB.Window_BattleStatus_drawBasicArea.call(this, rect, actor);
};

Yanfly.ATB.Window_BattleStatus_drawGaugeAreaWithTp =
    Window_BattleStatus.prototype.drawGaugeAreaWithTp;
Window_BattleStatus.prototype.drawGaugeAreaWithTp = function(rect, actor) {
  if (this.isATBGaugeStyle(2)) {
    var totalArea = this.gaugeAreaWidth();
    var gw = totalArea / 4 - 15;
    this.drawActorHp(actor, rect.x + 0, rect.y, gw);
    this.drawActorMp(actor, rect.x + gw * 1 + 15, rect.y, gw);
    this.drawActorTp(actor, rect.x + gw * 2 + 30, rect.y, gw);
    this.drawActorAtbGauge(actor, rect.x + gw * 3 + 45, rect.y, gw);
  } else {
    Yanfly.ATB.Window_BattleStatus_drawGaugeAreaWithTp.call(this, rect, actor);
  }
};

Yanfly.ATB.Window_BattleStatus_drawGaugeAreaWOTp =
    Window_BattleStatus.prototype.drawGaugeAreaWithoutTp;
Window_BattleStatus.prototype.drawGaugeAreaWithoutTp = function(rect, actor) {
  if (this.isATBGaugeStyle(2)) {
    var totalArea = this.gaugeAreaWidth() - 30;
    var hpW = parseInt(totalArea * 108 / 300);
    var otW = parseInt(totalArea * 96 / 300);
    this.drawActorHp(actor, rect.x + 0, rect.y, hpW);
    this.drawActorMp(actor, rect.x + hpW + 15, rect.y, otW);
    this.drawActorAtbGauge(actor, rect.x + hpW + otW + 30, rect.y, otW);
  } else {
    Yanfly.ATB.Window_BattleStatus_drawGaugeAreaWOTp.call(this, rect, actor);
  }
};

//=============================================================================
// Window_Options
//=============================================================================

Yanfly.ATB.Window_Options_addGeneralOptions =
    Window_Options.prototype.addGeneralOptions;
Window_Options.prototype.addGeneralOptions = function() {
    Yanfly.ATB.Window_Options_addGeneralOptions.call(this);
    if ($gameSystem.getBattleSystem() === 'atb') this.addATBOptions();
};

Window_Options.prototype.addATBOptions = function() {
    var text = Yanfly.Param.ATBOptionSpeedTx;
    this.addCommand(text, 'atbSpeed');
};

Yanfly.ATB.Window_Options_statusText = Window_Options.prototype.statusText;
Window_Options.prototype.statusText = function(index) {
    var symbol = this.commandSymbol(index);
    if (symbol === 'atbSpeed') {
      return this.getConfigValue('atbSpeed');
    } else {
      return Yanfly.ATB.Window_Options_statusText.call(this, index);
    }
};

Yanfly.ATB.Window_Options_processOk = Window_Options.prototype.processOk;
Window_Options.prototype.processOk = function() {
    var index = this.index();
    var symbol = this.commandSymbol(index);
    if (symbol === 'atbSpeed') {
      var value = this.getConfigValue(symbol);
      value += 1;
      if (value > 10) value = 1;
      this.changeValue(symbol, value);
    } else {
      Yanfly.ATB.Window_Options_processOk.call(this);
    }
};

Yanfly.ATB.Window_Options_cursorRight = Window_Options.prototype.cursorRight;
Window_Options.prototype.cursorRight = function(wrap) {
    var index = this.index();
    var symbol = this.commandSymbol(index);
    if (symbol === 'atbSpeed') {
      var value = this.getConfigValue(symbol);
      value += 1;
      if (value > 10) value = 1;
      this.changeValue(symbol, value);
    } else {
      Yanfly.ATB.Window_Options_cursorRight.call(this, wrap);
    }
};

Yanfly.ATB.Window_Options_cursorLeft = Window_Options.prototype.cursorLeft;
Window_Options.prototype.cursorLeft = function(wrap) {
    var index = this.index();
    var symbol = this.commandSymbol(index);
    if (symbol === 'atbSpeed') {
      var value = this.getConfigValue(symbol);
      value -= 1;
      if (value < 1) value = 10;
      this.changeValue(symbol, value);
    } else {
      Yanfly.ATB.Window_Options_cursorLeft.call(this, wrap);
    }
};

//=============================================================================
// Scene_Battle
//=============================================================================

Yanfly.ATB.Scene_Battle_updateWindowPositions =
    Scene_Battle.prototype.updateWindowPositions;
Scene_Battle.prototype.updateWindowPositions = function() {
    if (BattleManager.isATB() && !this._atbLockStatusWin) {
      this._atbLockStatusWin = eval(Yanfly.Param.ATBLockStatusWin);
    }
    if (BattleManager.isATB() && this._atbLockStatusWin) {
      this.updateWindowPositionsATB();
    } else {
      Yanfly.ATB.Scene_Battle_updateWindowPositions.call(this);
    }
};

Yanfly.ATB.Scene_Battle_isStartActorCommand =
    Scene_Battle.prototype.isStartActorCommand;
Scene_Battle.prototype.isStartActorCommand = function() {
    if (BattleManager.isATB()) return true;
    return Yanfly.ATB.Scene_Battle_isStartActorCommand.call(this);
};

Scene_Battle.prototype.updateWindowPositionsATB = function() {
    var activeWin = null;
    if (this._partyCommandWindow.active) activeWin = this._partyCommandWindow;
    if (this._actorCommandWindow.active) activeWin = this._actorCommandWindow;
    if (activeWin === null) return;
    if (activeWin.x <= Graphics.boxWidth / 2) {
      this._statusWindow.x = Graphics.boxWidth - this._statusWindow.width;
    } else {
      this._statusWindow.x = 0;
    }
};

Yanfly.ATB.Scene_Battle_commandFight = Scene_Battle.prototype.commandFight;
Scene_Battle.prototype.commandFight = function() {
    if (BattleManager.isATB()) {
      this.startActorCommandSelection();
      BattleManager._phase = 'input';
    } else {
      Yanfly.ATB.Scene_Battle_commandFight.call(this);
    }
};

Yanfly.ATB.Scene_Battle_startActorCommandSelection =
    Scene_Battle.prototype.startActorCommandSelection;
Scene_Battle.prototype.startActorCommandSelection = function() {
    Yanfly.ATB.Scene_Battle_startActorCommandSelection.call(this);
    if (BattleManager.isATB()) {
      BattleManager.actor().spriteStepForward();
      BattleManager.actor().setActionState('undecided');
      BattleManager.actor().requestMotionRefresh();
      BattleManager.actor().makeActions();
    }
};

//=============================================================================
// End of File
//=============================================================================
};
[/fold]


[fold=YEP_X_BattleSysCTB汉化版]//=============================================================================
// Yanfly Engine Plugins - Battle System - Charge Turn Battle
// YEP_X_BattleSysCTB.js
//=============================================================================

var Imported = Imported || {};
Imported.YEP_X_BattleSysCTB = true;

var Yanfly = Yanfly || {};
Yanfly.CTB = Yanfly.CTB || {};

//=============================================================================
/*:
* @plugindesc v1.07 (Requires YEP_BattleEngineCore.js) Add CTB (Charge
* Turn Battle) into your game using this plugin!
* 排位战斗系统--我暂且这么定义吧,因为实在没有找到合适的官方中文术语
* --翻译 by 抖M俱乐部的 SmithJiong/bennett01/SOAP
* 转载请注明出处
* @author Yanfly Engine Plugins
*
* @param ---CTB Settings--- 排位战斗系统设置
* @default
*
* @param Per Tick
* @desc This is how much speed is gained per tick.
* 类似ATB,这个是决定角色排位顺序的基础值,默认为敏捷.
* @default user.agi
*
* @param Initial Speed
* @desc The speed position of the battler at the start of battle.
* 排位系统的初始速度值,这个值可以参照ATB系统的Speed值.
* This is a formula processed as an eval.
* 可以使用公式来定义.
* @default 0
*
* @param Full Gauge
* @desc The target speed for an CTB gauge to be full.
* 排位槽的最大速度值,表示了开始行动需要积攒多少速度值.
* This is a formula processed as an eval.
* 可以使用公式来定义
* @default Math.max(7000, BattleManager.highestBaseAgi() * 120)
*
* @param Pre-Emptive Bonuses
* @desc How much of the CTB bar do you want filled up for an
* CTB pre-emptive bonus from 0 to 1.
* @default 0.8
*
* @param Surprise Bonuses
* @desc How much of the CTB bar do you want filled up for an
* CTB surprise bonus from 0 to 1.
* @default 0.8
*
* @param ---Escape---逃跑
* @default
*
* @param Escape Ratio
* @desc How CTB calculates escape ratios.
* Default: 0.5 * $gameParty.agility() / $gameTroop.agility()
* CTB系统的逃跑几率,与ATB逃跑几率设置相同。
* @default 0.125 * $gameParty.agility() / $gameTroop.agility()
*
* @param Fail Escape Boost
* @desc Each time the player fails escape, increase the success
* rate by this much. Default: 0.1
* 每次逃跑失败后增加的成功率,与ATB系统的设置相同.
* @default 0.025
*
* @param ---Turn---回合
* @default
*
* @param Full Turn
* @desc This is how many ticks to equal a full battle turn.
* This is a formula processed as an eval.
* 这个选项定义了每次可以填充角色的排位槽的速度值,
* 简单的说该通过调整这个值可以改变动态战斗节奏,
* 通常来说这个值越低速度就越慢
* @default Math.min(200, BattleManager.lowestBaseAgi() * 8)
*
* @param ---Rubberband---弹性设置
* @default
*
* @param Enable Rubberband
* @desc This is an auto-balance mechanic for AGI.
* Disable - false     Enable - true
* 是否启用弹性设置来平衡排位槽,与ATB系统的设置相同.
* @default true
*
* @param Minimum Speed
* @desc If rubberbanding is enabled, what is the minimum
* speed increase? This is a formula.
* 弹性系统限制下单位每次最少增加的速度值.
* @default 0.5 * BattleManager.highestBaseAgi()
*
* @param Maximum Speed
* @desc If rubberbanding is enabled, what is the maximum
* speed increase? This is a formula.
* 弹性系统限制下单位每次最多增加的速度值
* @default 1.5 * BattleManager.highestBaseAgi()
*
* @param ---Sound--- 声音
* @default
*
* @param Ready Sound
* @desc This is the sound played when the battler is ready.
* 战斗单位准备行动时的音效
* @default Decision1
*
* @param Ready Volume
* @desc This is the volume of the ready sound.
* 准备行动音效的音量
* @default 90
*
* @param Ready Pitch
* @desc This is the pitch of the ready sound.
* 准备行动音效的音高
* @default 120
*
* @param Ready Pan
* @desc This is the pan of the ready sound.
* 准备行动音效的位相
* @default 0
*
* @param ---Turn Order---
* @default
*
* @param Show Turn Order
* @desc Show the battler turn order?
* NO - false     YES - true
* 是否显示战斗行动顺序条 显示-true 不显示-false
* @default true
*
* @param Icon Size
* @desc This is the size of the icons displayed for the turn order.
* 战斗行动顺序条图标的大小,值越大 条越大
* Default: 32
* @default 32
*
* @param Position Y
* @desc Where do you want to align the Y turn order?
* 战斗行动顺序条图标的纵轴位置,数值决定行动条的上下位置
* @default 54
*
* @param Position X
* @desc Which side of the screen should the turn order appear?
* left     center     right
* 战斗行动顺序条图标的横轴位置,有三个选项
* left-左对齐 center-居中 right-右对齐
* @default right
*
* @param Turn Direction
* @desc Which way do you want the turn icons going?
* left     right
* 你想要行动条的玩家头像图标向哪个方向移动
* left-向左移动 right-向右移动
* @default left
*
* @param Ally Border Color
* @desc Text Color used for the borders of allies.
* 盟友头像图标边框的颜色
* @default 4
*
* @param Ally Back Color
* @desc Text Color used for the ally background color.
* 盟友头像图标背景的颜色
* @default 22
*
* @param Ally Icon
* @desc Default icon used for allies. If this value is 0,
* the icon will be the ally's face graphic instead.
* 盟友图标的头像,如果设置为0则代表使用系统默认头像.
* @default 0
*
* @param Enemy Border Color
* @desc Text Color used for the borders of enemies.
* 敌人头像图标边框的颜色
* @default 2
*
* @param Enemy Back Color
* @desc Text Color used for the ally background color.
* 盟友头像图标背景的颜色
* @default 19
*
* @param Enemy Icon
* @desc Default icon used for enemies. If this value is 0,
* the icon will be the enemy's drawn battler instead.
* 敌人图标的头像,如果设置为0则代表使用系统默认头像.
* @default 0
*
* @param Enemy SV Battlers
* @desc If using Animated SV Enemies, draw their battlers if no icon
* is being used? This can become laggy. NO - false  YES - true
* 是否使用动态SV的敌人,如果使用了这类敌人而没有设计专门的静态头像,排位条可能会卡住.
* @default false
*
* @help
* ============================================================================
* Introduction - 插件介绍
* ============================================================================
*
* The Battle System - Charge Turn Battle plugin is an extension plugin for
* Yanfly Engine Plugins' Battle Engine Core. This extension plugin will not
* work without the main plugin.
*
* To use the CTB system, go to the Battle Engine Core plugin and change the
* 'Default System' setting in the parameters to 'ctb'.
*
* The Charge Turn Battle system functions by calculating every battlers' speed
* and balancing them relative to one another. When it's a battler's turn, the
* battler will either choose an action to perform immediately or charge it for
* later depending if the skill requires charging.
*
* This is a battle system where agility plays an important factor in the
* progress of battle where higher agility values give battlers more advantage
* and lower agility values give battlers less advantage.
*
* OK,其实我很乐意给这类战斗插件做翻译,CTB系统也是一个很经典的回合战斗系统
* 你一定玩过空轨、碧轨、零轨对吧,那你一定对这种战斗系统不陌生,类似于ATB系统
* CTB系统也有一个行动槽,但是与ATB不同,他是所有角色统一的一个排位槽,角色根据
* 自身敏捷进行排位槽积攒排位值,最先攒满的角色进行行动,行动中角色可以使用立即施放,
* 或需咏唱一段时间的技能,在选择咏唱技能后,其他角色的行动槽将继续增长,到达顶点后开始行动.
*
* 类似与ATB插件,本插件也将依靠Battle Engine Core核心插件,安装时务必位于核心插件下方
* 同时要启用CTB战斗系统,你也需要在核心插件的Default System选项中 将键值修改为CTB即可
*
* ============================================================================
* Plugin Commands 插件命令
* ============================================================================
*
* To change your battle system to Charge Turn Battle if it isn't the default
* battle system, you can use the following Plugin Command:
* 与ATB系统的设置相同,CTB模式也允许你是用插件命令在游戏内切换游戏模式
*
* Plugin Command:
* 插件命令:
*   setBattleSys CTB      设置为CTB系统
*   setBattleSys DTB      设置为DTB系统.
*
* Using the above Plugin Commands, you can toggle between the Default Battle
* System and Charge Turn Battle!
* 使用事件内的插件命令,可以实现在游戏内部对战斗系统的转换功能.
*
* ============================================================================
* Notetags-注释命令
* ============================================================================
*
* The following are notetags that pertain to and affect the CTB system.
* 下面的注释命令只会在你启用了CTB战斗系统时生效.
*
* Actor and Enemy Notetags:
* 玩家角色和敌人注释命令:
*   <CTB Icon: x>
*   设置角色或敌人的CTB排位槽的头像图标.
*
*   <CTB Border Color: x>
*   设置角色或敌人的CTB排位槽的边框线条颜色.
*
*   <CTB Background Color: x>
*   设置角色或敌人的CTB排位槽的边框背景颜色.
*
* Actor only Notetags:
* 仅可用于玩家角色的注释命令
*   <Class x CTB Icon: y>
*   This sets it so that if the actor is a specific class, the actor will get
*   a specific icon used for the CTB Turn Order. If the actor is class x, it
*   will receive icon y.
*   给不同职业定义不同的头像图标,x为职业ID,y为头像ID
*
*
*   <Hero CTB Icon: x>
*   <Warrior CTB Icon: x>
*   <Mage CTB Icon: x>
*   <Priest CTB Icon: x>
*   If you prefer to use names instead of class ID's, you can use the above
*   notetag format. If the actor is the named class, it will receive icon x.
*   If you have multiple classes with the same name, priority will be given to
*   the class with the highest ID.
*   如果你要使用职业名称来定义头像也是可以的,但写法略有不同,把上面class x直接替换为职业名称即可.
*
* Skill and Item Notetags:
* 技能和道具注释命令:
*   <CTB Help>
*   text
*   text
*   </CTB Help>
*   For those planning on using multiple battle systems, sometimes you may
*   have your skills perform differently while using CTB. If so, using this
*   notetag will allow skills and items to display different help text while
*   CTB is enabled.
*   给技能和道具添加一个专属的CTB说明信息,这个信息只有在CTB系统启用时会显示.
*
*   <CTB Speed: x>
*   Usable only during CTB. This sets the target's current speed to x.
*   把目标的当前排位值设置为x,这个类似于ATB的speed值
*
*   <CTB Speed: x%>
*   Usable only during CTB. This sets the target's current speed to x% of
*   the CTB turn completion target.
*   把目标的当前排位值设置x%,100%就是直接行动
*
*   <CTB Speed: +x>
*   <CTB Speed: -x>
*   Usable only during CTB. This increases or decreases the target's current
*   speed by x.
*   把目标的当前排位值增加或减少x +/- 起到快速行动或延迟行动的目的
*
*   <CTB Speed: +x%>
*   <CTB Speed: -x%>
*   Usable only during CTB. This increases or decreases the target's current
*   speed or charge by x% of the CTB turn completion target.
*   你也可以使用+/-百分比的形式进行定义
*
*   <CTB Order: +x>
*   <CTB Order: -x>
*   Moves target's position in the turn order by +x or -x. +x will make the
*   target having to wait more before getting their turn while -x will make
*   the target having to wait less. The effect is minimal and will only last
*   for the current turn cycle.
*   使用这个命令按照x参数改变当前目标的综合排序,+x会使目标需要等待更长的时间.
*   这个命令的效果微小,并且只会持续到当前回合的循环结束
*   * Note: If you use this for multiple targets, each target will shift turns
*   individually at a time.
*   要注意:如果你的命令针对了多个目标,每个目标的回合变化将会分别计算
*   翻译者解释:其实就是按照x排序啦,比如你写+1就是把目标的行动推后1位,由于只在当前
*   回合的循环轮生效,所以+100和+1000的效果都是推到最后,但是+1000肯定能够要比+100更靠后
*   如果x相同,那么将会根据原来的角色顺序排序
*   这个命令我认为作者其实主要想用来微调某个角色的行动顺序的功能,因为靠speed参数来调整
*   需要的计算量比较大,而且很不稳定.而这个+1 +2 -1 -2的排序功能设定起来就相对容易多了.
*
*   <After CTB: x>
*   <After CTB: x%>
*   This will set the skill/item user's CTB speed value to x or x%. If 'x' is
*   used, this will be the exact CTB value. If x% is used, this will be the
*   percentage of the CTB turn completion target that it will be at.
*   在行动结束后,将排位槽的值设置为x或x%
*
* Actor, Class, Enemy, Weapon, Armor, and State Notetags:
* 角色,职业,敌人,武器,护甲和状态命令:
*   <CTB Start: +x>
*   <CTB Start: +x%>
*   Usable only during CTB. This will give the actor, class, enemy, weapon,
*   armor, or state the property of starting battle with X CTB Speed or X% of
*   the CTB turn completion target.
*   在CTB模式中,定义角色开始时的排序槽值,第一次行动后从0开始排位.
*
*   <CTB Turn: +x>
*   <CTB Turn: +x%>
*   Usable only during CTB. This will give the actor, class, enemy, weapon,
*   armor, or state the property of starting a turn with X CTB Speed or X% of
*   the CTB turn completion target.
*   每回合开始时目标的排序槽值,行动后依然从x或x%处开始排位.
*
* ============================================================================
* Lunatic Mode - Conditional CTB Speed and Conditional CTB Charge
* 以下不翻了..看不懂E文的基本不会用...会JS脚本的基本都能看懂..我就不做无用功了
* ============================================================================
*
* For those who have a bit of JavaScript experience and would like to have
* more unique ways of performing CTB speed and charge changes, you can use the
* following notetags:
*
* Skill and Item Notetags:
*   <Target CTB Speed Eval>
*   speed = x;
*   charge = x;
*   </Target CTB Speed Eval>
*   You can omit speed and/or charge. Whatever you set 'speed' to will change
*   the CTB speed of the target. If the target is charging, 'charge' will
*   cause the target's charge to change to that value. To make things more
*   simple, 'max' will be the full gauge value.
*
*   Here is an example:
*
*   <Target CTB Speed Eval>
*   speed = target.hp / target.mhp * max;
*   charge = target.hp / target.mhp * max;
*   </Target CTB Speed Eval>
*   The above code will set the user's current CTB gauge to position equal to
*   the target's HP ratio. If the target has 25% HP, the CTB gauge will go to
*   25% full for the target.
*
*   --- --- --- --- ---
*
*   <Target CTB Order Eval>
*   order = x;
*   </Target CTB Order Eval>
*   Set the 'order' variable to how much you want to alter the target's
*   current turn order by. If 'order' is positive, the order will need to wait
*   that many more turns before its turn comes up. If 'order' is negative, it
*   will will that amount of turns less before the order comes up.
*
*   Here is an example:
*
*   <Target CTB Order Eval>
*   if (target.hp > 1000) {
*     order = 3;
*   } else {
*     order = -1;
*   }
*   </Target CTB Order Eval>
*   If the target when attacked has over 1000 HP left, the target will have to
*   wait 3 more turns before its turn arrives. If the target has 1000 or less,
*   the target actually waits 1 less turn.
*
*   --- --- --- --- ---
*
*   <After CTB Eval>
*   speed = x;
*   </After CTB Eval>
*   This is the CTB set after the user has used the skill/item and the custom
*   CTB amount you want the user to be at after. 'max' be the value of the
*   full gauge value. Whatever you set 'speed', the user's CTB speed value
*   will change to that much:
*
*   Here is an example:
*
*   <After CTB Eval>
*   speed = user.mp / user.mmp * max;
*   </After CTB Eval>
*   The above code will set the user's CTB gauge after using the skill/item to
*   equal the user's MP ratio. If the user has 25% MP, the CTB gauge will go
*   to 25% full for the user.
*
* ============================================================================
* Yanfly Engine Plugins - Battle Engine Extension - Action Sequence Commands
* ============================================================================
*
* You can make use of these extra CTB related action sequences.
*
*=============================================================================
* CTB ORDER: target, +X
* CTB ORDER: target, -X
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usable only for CTB. Moves target's position in the turn order by +x or -x.
* +x will make the target having to wait more before getting their turn while
* -x will make the target having to wait less. The effect is minimal and will
* only last for the current turn cycle.
* * Note: If you use this for multiple targets, each target will shift turns
* individually at a time.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usage Example: ctb order: target, -2
*                ctb order: target, +3
*=============================================================================
*
*=============================================================================
* CTB SPEED: target, X
* CTB SPEED: target, X%
* CTB SPEED: targets, +X
* CTB SPEED: targets, +X%
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usable only for CTB. Sets the target's CTB speed to X or X%. This only
* applies when the target is filling up its CTB gauge. This will not affect
* the user to prevent mechanical issues.
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Usage Example: ctb speed: targets, +5000
*                ctb speed: target, -50%
*=============================================================================
*
* ============================================================================
* Changelog
* ============================================================================
*
* Version 1.07:
* - Made a mechanic change so that turn 0 ends immediately upon battle start
* rather than requiring a full turn to end.
*
* Version 1.06:
* - Fixed a bug that would cause a crash when a party member leaves the party.
*
* Version 1.05c:
* - Implemented a Forced Action queue list. This means if a Forced Action
* takes place in the middle of an action, the action will resume after the
* forced action finishes rather than cancels it out like MV does.
* - Fixed a graphical issue where enemies appearing midway don't have letters
* attached to their icons.
* - Added a fail safe for loaded saves that did not have CTB installed before.
*
* Version 1.04:
* - Added a speed position check for Instant Casts to maintain order position.
*
* Version 1.03:
* - Fixed a bug that doesn't update state turns properly.
* - Removed 'Turn Structure parameter' as it goes against the nature of a
* Tick-Based battle system.
*
* Version 1.02:
* - Added failsafe for battlers without actions.
* - Added speed rebalance formulas for tick-based systems (innate).
* - Added <Class x CTB Icon: y> and <classname CTB Icon: x> notetags.
*
* Version 1.01:
* - Provided loop breaks to prevent lock-ups with non-Yanfly plugins.
* - Added 'Icon Size' parameter to allow customization of icon sizes.
*
* Version 1.00:
* - It's doooooooooone!
*/
//=============================================================================

if (Imported.YEP_BattleEngineCore) {

//=============================================================================
// Parameter Variables
//=============================================================================

Yanfly.Parameters = PluginManager.parameters('YEP_X_BattleSysCTB');
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.CTBPerTick = String(Yanfly.Parameters['Per Tick']);
Yanfly.Param.CTBInitSpeed = String(Yanfly.Parameters['Initial Speed']);
Yanfly.Param.CTBFullGauge = String(Yanfly.Parameters['Full Gauge']);
Yanfly.Param.CTBPreEmptive = Number(Yanfly.Parameters['Pre-Emptive Bonuses']);
Yanfly.Param.CTBSurprise = Number(Yanfly.Parameters['Surprise Bonuses']);

Yanfly.Param.CTBEscapeRatio = String(Yanfly.Parameters['Escape Ratio']);
Yanfly.Param.CTBEscapeBoost = String(Yanfly.Parameters['Fail Escape Boost']);

Yanfly.Param.CTBFullTurn = String(Yanfly.Parameters['Full Turn']);
Yanfly.Param.CTBTurnStructure = false;

Yanfly.Param.CTBRubberband = String(Yanfly.Parameters['Enable Rubberband']);
Yanfly.Param.CTBMinSpeed = String(Yanfly.Parameters['Minimum Speed']);
Yanfly.Param.CTBMaxSpeed = String(Yanfly.Parameters['Maximum Speed']);

Yanfly.Param.CTBReadyName = String(Yanfly.Parameters['Ready Sound']);
Yanfly.Param.CTBReadyVol = Number(Yanfly.Parameters['Ready Volume']);
Yanfly.Param.CTBReadyPitch = Number(Yanfly.Parameters['Ready Pitch']);
Yanfly.Param.CTBReadyPan = Number(Yanfly.Parameters['Ready Pan']);

Yanfly.Param.CTBOptionSpeedTx = String(Yanfly.Parameters['CTB Speed Text']);
Yanfly.Param.CTBDefaultSpeed = Number(Yanfly.Parameters['Default CTB Speed']);

Yanfly.Param.CTBTurnOrder = eval(String(Yanfly.Parameters['Show Turn Order']));
Yanfly.Param.CTBTurnPosY = Number(Yanfly.Parameters['Position Y']);
Yanfly.Param.CTBTurnPosX = String(Yanfly.Parameters['Position X']);
Yanfly.Param.CTBIconSize = Number(Yanfly.Parameters['Icon Size']);
Yanfly.Param.CTBTurnDirection = String(Yanfly.Parameters['Turn Direction']);
Yanfly.Param.CTBColorAllyBr = Number(Yanfly.Parameters['Ally Border Color']);
Yanfly.Param.CTBColorAllyBg = Number(Yanfly.Parameters['Ally Back Color']);
Yanfly.Param.CTBAllyIcon = Number(Yanfly.Parameters['Ally Icon']);
Yanfly.Param.CTBColorEnemyBr = Number(Yanfly.Parameters['Enemy Border Color']);
Yanfly.Param.CTBColorEnemyBg = Number(Yanfly.Parameters['Enemy Back Color']);
Yanfly.Param.CTBColorBackground = Number(Yanfly.Parameters['Background Color']);
Yanfly.Param.CTBEnemyIcon = Number(Yanfly.Parameters['Enemy Icon']);
Yanfly.Param.CTBEnemySVBattler = String(Yanfly.Parameters['Enemy SV Battlers']);
Yanfly.Param.CTBEnemySVBattler = eval(Yanfly.Param.CTBEnemySVBattler);

//=============================================================================
// DataManager
//=============================================================================

Yanfly.CTB.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function() {
    if (!Yanfly.CTB.DataManager_isDatabaseLoaded.call(this)) return false;
    this.processCTBNotetagsC($dataClasses);
    this.processCTBNotetags1($dataSkills);
    this.processCTBNotetags1($dataItems);
    this.processCTBNotetags2($dataActors);
    this.processCTBNotetags2($dataClasses);
    this.processCTBNotetags2($dataEnemies);
    this.processCTBNotetags2($dataWeapons);
    this.processCTBNotetags2($dataArmors);
    this.processCTBNotetags2($dataStates);
    this.processCTBNotetags3($dataActors, true);
    this.processCTBNotetags3($dataEnemies, false);
    return true;
};

DataManager.processCTBNotetagsC = function(group) {
  if (Yanfly.ClassIdRef) return;
  Yanfly.ClassIdRef = {};
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    if (obj.name.length <= 0) continue;
    Yanfly.ClassIdRef[obj.name.toUpperCase()] = n;
  }
};

DataManager.processCTBNotetags1 = function(group) {
  var noteA1 = /<(?:CTB SPEED):[ ](\d+)>/i;
  var noteA2 = /<(?:CTB SPEED):[ ]([\+\-]\d+)>/i;
  var noteA3 = /<(?:CTB SPEED):[ ](\d+)([%%])>/i;
  var noteA4 = /<(?:CTB SPEED):[ ]([\+\-]\d+)([%%])>/i;
  var noteB1 = /<(?:CTB ORDER):[ ]([\+\-]\d+)>/i;
  var noteS1 = /<(?:AFTER CTB):[ ](\d+)>/i;
  var noteS2 = /<(?:AFTER CTB):[ ](\d+)([%%])>/i;
    for (var n = 1; n < group.length; n++) {
      var obj = group[n];
      var notedata = obj.note.split(/[\r\n]+/);

      obj.setCTBGaugeFlat = undefined;
      obj.addCTBGaugeFlat = 0;
      obj.setCTBGaugeRate = undefined;
      obj.addCTBGaugeRate = 0.0;
      obj.ctbOrderModifier = 0;
      obj.afterCTBFlat = undefined;
      obj.afterCTBRate = undefined;
      var evalMode = 'none';
      obj.ctbEval = '';
      obj.ctbOrderEval = '';
      obj.ctbAfterEval = '';
      obj.ctbHelp = undefined;

      for (var i = 0; i < notedata.length; i++) {
        var line = notedata;
        if (line.match(noteA1)) {
          obj.setCTBGaugeFlat = parseInt(RegExp.$1);
        } else if (line.match(noteA2)) {
          obj.addCTBGaugeFlat = parseInt(RegExp.$1);
        } else if (line.match(noteA3)) {
          obj.setCTBGaugeRate = parseFloat(RegExp.$1 * 0.01);
        } else if (line.match(noteA4)) {
          obj.addCTBGaugeRate = parseFloat(RegExp.$1 * 0.01);
        } else if (line.match(noteB1)) {
          obj.ctbOrderModifier = parseInt(RegExp.$1);
        } else if (line.match(noteS1)) {
          obj.afterCTBFlat = parseInt(RegExp.$1);
        } else if (line.match(noteS2)) {
          obj.afterCTBRate = parseFloat(RegExp.$1 * 0.01);
        } else if (line.match(/<(?:TARGET CTB SPEED EVAL)>/i)) {
          evalMode = 'ctb speed eval';
        } else if (line.match(/<\/(?:TARGET CTB SPEED EVAL)>/i)) {
          evalMode = 'none';
        } else if (line.match(/<(?:TARGET CTB ORDER EVAL)>/i)) {
          evalMode = 'ctb order eval';
        } else if (line.match(/<\/(?:TARGET CTB ORDER EVAL)>/i)) {
          evalMode = 'none';
        } else if (line.match(/<(?:AFTER CTB EVAL)>/i)) {
          evalMode = 'after ctb eval';
        } else if (line.match(/<\/(?:AFTER CTB EVAL)>/i)) {
          evalMode = 'none';
        } else if (line.match(/<(?:CTB HELP)>/i)) {
          evalMode = 'ctb help';
          obj.ctbHelp = '';
        } else if (line.match(/<\/(?:CTB HELP)>/i)) {
          evalMode = 'none';
        } else if (evalMode === 'ctb help') {
          obj.ctbHelp = obj.ctbHelp + line + '\n';
        } else if (evalMode === 'ctb speed eval') {
          obj.ctbEval = obj.ctbEval + line + '\n';
        } else if (evalMode === 'ctb order eval') {
          obj.ctbOrderEval = obj.ctbOrderEval + line + '\n';
        } else if (evalMode === 'after ctb eval') {
          obj.ctbAfterEval = obj.ctbAfterEval + line + '\n';
        }
      }
    }
};

DataManager.processCTBNotetags2 = function(group) {
  var noteA1 = /<(?:CTB START):[ ]([\+\-]\d+)>/i;
  var noteA2 = /<(?:CTB START):[ ]([\+\-]\d+)([%%])>/i;
  var noteB1 = /<(?:CTB TURN):[ ]([\+\-]\d+)>/i;
  var noteB2 = /<(?:CTB TURN):[ ]([\+\-]\d+)([%%])>/i;
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.ctbStartFlat = 0;
    obj.ctbStartRate = 0;
    obj.ctbTurnFlat = 0;
    obj.ctbTurnRate = 0;
    var evalMode = 'none';
    obj.ctbHelp = undefined;

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata;
      if (line.match(noteA1)) {
        obj.ctbStartFlat = parseInt(RegExp.$1);
      } else if (line.match(noteA2)) {
        obj.ctbStartRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(noteB1)) {
        obj.ctbTurnFlat = parseInt(RegExp.$1);
      } else if (line.match(noteB2)) {
        obj.ctbTurnRate = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(/<(?:CTB HELP)>/i)) {
        evalMode = 'ctb help';
        obj.ctbHelp = '';
      } else if (line.match(/<\/(?:CTB HELP)>/i)) {
        evalMode = 'none';
      } else if (evalMode === 'ctb help') {
        obj.ctbHelp = obj.ctbHelp + line + '\n';
      }
    }
  }
};

DataManager.processCTBNotetags3 = function(group, isActor) {
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);
   
    if (isActor) obj.ctbIcon = Yanfly.Param.CTBAllyIcon;
    if (isActor) obj.ctbBorderColor = Yanfly.Param.CTBColorAllyBr;
    if (isActor) obj.ctbBackgroundColor = Yanfly.Param.CTBColorAllyBg;
    if (isActor) obj.ctbClassIcon = {};
    if (!isActor) obj.ctbIcon = Yanfly.Param.CTBEnemyIcon;
    if (!isActor) obj.ctbBorderColor = Yanfly.Param.CTBColorEnemyBr;
    if (!isActor) obj.ctbBackgroundColor = Yanfly.Param.CTBColorEnemyBg;

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata;
      if (line.match(/<(?:CTB ICON):[ ](\d+)>/i)) {
        obj.ctbIcon = parseInt(RegExp.$1);
      } else if (line.match(/<(?:CTB BORDER COLOR):[ ](\d+)>/i)) {
        obj.ctbBorderColor = parseInt(RegExp.$1);
      } else if (line.match(/<(?:CTB BACKGROUND COLOR):[ ](\d+)>/i)) {
        obj.ctbBackgroundColor = parseInt(RegExp.$1);
      } else if (line.match(/<(?:CLASS)[ ](\d+)[ ](?:CTB ICON):[ ](\d+)>/i)) {
        var classId = parseInt(RegExp.$1);
        var icon = parseInt(RegExp.$2);
        obj.ctbClassIcon[classId] = icon;
      } else if (line.match(/<(.*)[ ](?:CTB ICON):[ ](\d+)>/i)) {
        var name = String(RegExp.$1).toUpperCase();
        var icon = parseInt(RegExp.$2);
        var classId = Yanfly.ClassIdRef[name];
        if (classId) obj.ctbClassIcon[classId] = icon;
      }
    }
  }
};

//=============================================================================
// BattleManager
//=============================================================================

BattleManager.isCTB = function() {
    return this.isBattleSystem('ctb');
};

Yanfly.CTB.BattleManager_isTurnBased = BattleManager.isTurnBased;
BattleManager.isTurnBased = function() {
    if (this.isCTB()) return false;
    return Yanfly.CTB.BattleManager_isTurnBased.call(this);
};

BattleManager.ctbTickRate = function() {
    var rate = 0.1 * ConfigManager.ctbSpeed;
    return rate;
};

Yanfly.CTB.BattleManager_makeEscapeRatio = BattleManager.makeEscapeRatio;
BattleManager.makeEscapeRatio = function() {
    if (this.isCTB()) {
      this._escapeRatio = eval(Yanfly.Param.CTBEscapeRatio);
      this._escapeFailBoost = eval(Yanfly.Param.CTBEscapeBoost);
    } else {
      this._escapeFailBoost = 0.1;
      Yanfly.CTB.BattleManager_makeEscapeRatio.call(this);
    }
};

Yanfly.CTB.BattleManager_startBattle = BattleManager.startBattle;
BattleManager.startBattle = function() {
    Yanfly.CTB.BattleManager_startBattle.call(this);
    if (this.isCTB()) {
      this._phase = null;
      this.startCTB();
    }
};

Yanfly.CTB.BattleManager_endBattle = BattleManager.endBattle;
BattleManager.endBattle = function(result) {
    Yanfly.CTB.BattleManager_endBattle.call(this, result);
    this.clearCTBData();
};

BattleManager.startCTB = function() {
    if (this._phase === 'battleEnd') return;
    this.clearCTBData();
    this._ctbTarget = Math.max(1, eval(Yanfly.Param.CTBFullGauge));
    this._ctbFullTurn = Math.max(1, eval(Yanfly.Param.CTBFullTurn));
    this._ctbRubberband = eval(Yanfly.Param.CTBRubberband);
    if (this.ctbRubberband()) {
      this._ctbMinimumSpeed = Math.max(1, eval(Yanfly.Param.CTBMinSpeed));
      this._ctbMaximumSpeed = Math.max(1, eval(Yanfly.Param.CTBMaxSpeed));
    }
    this._ctbTicks = this._ctbFullTurn;
    this._ctbReadySound = {
      name: Yanfly.Param.CTBReadyName,
      volume: Yanfly.Param.CTBReadyVol,
      pitch: Yanfly.Param.CTBReadyPitch,
      pan: Yanfly.Param.CTBReadyPan
    }
    $gameParty.onCTBStart();
    $gameTroop.onCTBStart();
    this._phase = 'start';
};

BattleManager.clearCTBData = function() {
    this._highestBaseAgi = undefined;
    this._averageBaseAgi = undefined;
    this._lowestBaseAgi = undefined;
    this._ctbTarget = undefined;
    this._ctbCharge = undefined;
    this._ctbTarget = undefined;
    this._ctbCharge = undefined;
    this._ctbFullTurn = undefined;
    this._ctbRubberband = undefined;
    this._ctbMinimumSpeed = undefined;
    this._ctbMaximumSpeed = undefined;
    this._ctbTicks = 0;
};

BattleManager.ctbTarget = function() {
    if (!this._ctbTarget) this.startCTB();
    return this._ctbTarget;
};

BattleManager.ctbRubberband = function() {
    return this._ctbRubberband;
};

BattleManager.ctbMinimumSpeed = function() {
    return this._ctbMinimumSpeed;
};

BattleManager.ctbMaximumSpeed = function() {
    return this._ctbMaximumSpeed;
};

BattleManager.highestBaseAgi = function() {
    if (this._highestBaseAgi) return this._highestBaseAgi;
    var agi = 0;
    for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
      var battler = $gameParty.battleMembers();
      if (battler) agi = Math.max(agi, battler.agi);
    }
    for (var i = 0; i < $gameTroop.members().length; ++i) {
      var battler = $gameTroop.members();
      if (battler) agi = Math.max(agi, battler.agi);
    }
    this._highestBaseAgi = agi;
    return this._highestBaseAgi;
};

BattleManager.averageBaseAgi = function() {
    if (this._averageBaseAgi) return this._averageBaseAgi;
    var agi = 0;
    for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
      var battler = $gameParty.battleMembers();
      if (battler) agi += battler.agi;
    }
    for (var i = 0; i < $gameTroop.members().length; ++i) {
      var battler = $gameTroop.members();
      if (battler) agi += battler.agi;
    }
    var sum = $gameParty.battleMembers().length;
    sum += $gameTroop.members().length;
    this._averageBaseAgi = agi / sum;
    return this._averageBaseAgi;
};

BattleManager.lowestBaseAgi = function() {
    if (this._lowestBaseAgi) return this._lowestBaseAgi;
    var agi = this.highestBaseAgi();
    for (var i = 0; i < $gameParty.battleMembers().length; ++i) {
      var battler = $gameParty.battleMembers();
      if (battler) agi = Math.min(agi, battler.agi);
    }
    for (var i = 0; i < $gameTroop.members().length; ++i) {
      var battler = $gameTroop.members();
      if (battler) agi = Math.min(agi, battler.agi);
    }
    this._lowestBaseAgi = agi;
    return this._lowestBaseAgi;
};

BattleManager.ctbTurnOrder = function() {
    var battlers = $gameParty.aliveMembers().concat($gameTroop.aliveMembers());
    battlers.sort(function(a, b) {
      if (a.ctbTicksToReady() > b.ctbTicksToReady()) return 1;
      if (a.ctbTicksToReady() < b.ctbTicksToReady()) return -1;
      return 0;
    });
    return battlers;
};

Yanfly.CTB.BattleManager_update = BattleManager.update;
BattleManager.update = function() {
    if (this.isCTB()) {
      if (this.isBusy()) return;
      if (this.updateEvent()) return;
      if (this._phase === 'battleEnd') {
        return Yanfly.CTB.BattleManager_update.call(this);
      }
      if (this.checkBattleEnd()) return;
      if (this._phase === 'ctb') {
        this.updateCTBPhase();
      } else {
        Yanfly.CTB.BattleManager_update.call(this);
      }
    } else {
      Yanfly.CTB.BattleManager_update.call(this);
    }
};

Yanfly.CTB.BattleManager_updateEventMain = BattleManager.updateEventMain;
BattleManager.updateEventMain = function() {
    if (this.isCTB()) {
      $gameTroop.updateInterpreter();
      $gameParty.requestMotionRefresh();
      if ($gameTroop.isEventRunning()) {
          return true;
      }
      $gameTroop.setupBattleEvent();
      if ($gameTroop.isEventRunning() || SceneManager.isSceneChanging()) {
          return true;
      }
      return false;
    } else {
      return Yanfly.CTB.BattleManager_updateEventMain.call(this);
    }
};

BattleManager.updateCTBPhase = function() {
    this._ctbLoops = 0;
    for (;;) {
      if (this.breakCTBPhase()) break;
      var chargedBattler = this.getChargedCTBBattler();
      if (chargedBattler) return this.startCTBAction(chargedBattler);
      var readyBattler = this.getReadyCTBBattler();
      if (readyBattler) {
        return this.startCTBInput(readyBattler);
      } else {
        if (this.updateCTBTicks()) break;
        this.updateBattlerCTB();
      }
    }
};

BattleManager.breakCTBPhase = function() {
    if (this._victoryPhase) return true;
    if (this._processingForcedAction) return true;
    if ($gameTroop.isEventRunning()) return true;
    if (++this._ctbLoops >= 1000000) return true;
    return this._phase !== 'ctb';
};

BattleManager.updateCTBTicks = function() {
    this._ctbTicks += 1 * this.tickRate();
    if (this._ctbTicks < this._ctbFullTurn) return false;
    this._ctbTicks = 0;
    $gameTroop.increaseTurn();
    this.endTurn();
    return true;
};

BattleManager.getChargedCTBBattler = function() {
    if ($gameParty.aliveMembers() <= 0 || $gameTroop.aliveMembers() <= 0) {
      return false;
    }
    var fastest = false;
    for (var i = 0; i < this.allBattleMembers().length; ++i) {
      var battler = this.allBattleMembers();
      if (!battler) continue;
      if (!this.isBattlerCTBCharged(battler)) continue;
      if (!fastest) {
        fastest = battler;
      } else if (battler.ctbTicksToReady() < fastest.ctbTicksToReady()) {
        fastest = battler;
      }
    }
    return fastest;
};

BattleManager.isBattlerCTBCharged = function(battler) {
    if (!battler.isCTBCharging()) return false;
    if (battler.ctbChargeRate() < 1) return false;
    if (battler.isConfused()) {
      battler.makeActions();
      if (battler.isActor()) battler.makeConfusionActions();
    }
    return battler.currentAction() && battler.currentAction().item();
};

BattleManager.getReadyCTBBattler = function() {
    var fastest = false;
    for (var i = 0; i < this.allBattleMembers().length; ++i) {
      var battler = this.allBattleMembers();
      if (!battler) continue;
      if (!this.isBattlerCTBReady(battler)) continue;
      if (!fastest) {
        fastest = battler;
      } else if (battler.ctbTicksToReady() < fastest.ctbTicksToReady()) {
        fastest = battler;
      }
    }
    return fastest;
};

BattleManager.isBattlerCTBReady = function(battler) {
    if (battler.ctbRate() < 1) return false;
    if (battler.isCTBCharging()) return false;
    if (battler.currentAction() && battler.currentAction().item()) {
      battler.setupCTBCharge();
      return true;
    }
    return true;
};

BattleManager.updateBattlerCTB = function() {
    $gameParty.updateTick();
    $gameTroop.updateTick();
};

BattleManager.setCTBPhase = function() {
    this._phase = 'ctb';
};

Yanfly.CTB.BattleManager_startInput = BattleManager.startInput;
BattleManager.startInput = function() {
    if (this.isCTB()) {
      this.setCTBPhase();
    } else {
      Yanfly.CTB.BattleManager_startInput.call(this);
    }
};

Yanfly.CTB.BattleManager_selectNextCommand = BattleManager.selectNextCommand;
BattleManager.selectNextCommand = function() {
    if (this.isCTB()) {
      if (!this.actor()) return this.setCTBPhase();
      this.resetNonPartyActorCTB();
      this.actor().setupCTBCharge();
      if (this.actor().isCTBCharging()) {
        this.actor().spriteStepBack();
        this.actor().requestMotionRefresh();
        this._actorIndex = undefined;
        this.setCTBPhase();
      } else if (this.isValidCTBActorAction()) {
        this.startCTBAction(this.actor());
      } else {
        if (this.actor()) this.ctbSkipTurn();
        $gameParty.requestMotionRefresh();
        this.setCTBPhase();
      }
    } else {
      Yanfly.CTB.BattleManager_selectNextCommand.call(this);
    }
};

BattleManager.ctbSkipTurn = function() {
    this.actor().clearActions();
    this.actor().setActionState('undecided');
    this.actor().requestMotionRefresh();
    if (!this._bypassCtbEndTurn) this.actor().endTurnAllCTB();
    this.actor().spriteStepBack();
};

BattleManager.isValidCTBActorAction = function() {
    if (!this.actor()) return false;
    if (!this.actor().currentAction()) return false;
    return this.actor().currentAction().item();
};

BattleManager.resetNonPartyActorCTB = function() {
    for (var i = 0; i < $gameParty.allMembers().length; ++i) {
      var actor = $gameParty.allMembers();
      if (!actor) continue;
      if ($gameParty.battleMembers().contains(actor)) continue;
      actor.resetAllCTB();
    }
};

Yanfly.CTB.BattleManager_selectPreviousCommand =
    BattleManager.selectPreviousCommand;
BattleManager.selectPreviousCommand = function() {
    if (this.isCTB()) {
      if (this.actor()) this.actor().spriteStepBack();
      var actorIndex = this._actorIndex;
      var scene = SceneManager._scene;
      this._bypassCtbEndTurn = true;
      scene.startPartyCommandSelection();
      this._bypassCtbEndTurn = undefined;
      this._actorIndex = actorIndex;
    } else {
      Yanfly.CTB.BattleManager_selectPreviousCommand.call(this);
    }
};

Yanfly.CTB.BattleManager_startTurn = BattleManager.startTurn;
BattleManager.startTurn = function() {
    if (this.isCTB() && !this.isTurnBased()) return;
    Yanfly.CTB.BattleManager_startTurn.call(this);
};

Yanfly.CTB.BattleManager_updateTurnEnd = BattleManager.updateTurnEnd;
BattleManager.updateTurnEnd = function() {
    if (this.isCTB()) {
      this.setCTBPhase();
    } else {
      Yanfly.CTB.BattleManager_updateTurnEnd.call(this);
    }
};

BattleManager.startCTBInput = function(battler) {
    if (battler.isDead()) return;
    battler.makeActions();
    if (battler.isEnemy()) {
      battler.setupCTBCharge();
    } else if (battler.canInput()) {
      this._actorIndex = battler.index();
      this.playCTBReadySound();
      battler.setActionState('inputting');
      battler.spriteStepForward();
      this._phase = 'input';
      return;
    } else if (battler.isConfused()) {
      battler.makeConfusionActions();
      battler.setupCTBCharge();
    } else {
      battler.makeAutoBattleActions();
      battler.setupCTBCharge();
    }
    if (battler.isCTBCharging()) {
      this.setCTBPhase();
    } else {
      this.startCTBAction(battler);
    }
};

BattleManager.playCTBReadySound = function() {
    AudioManager.playSe(this._ctbReadySound);
};

BattleManager.startCTBAction = function(battler) {
    this._subject = battler;
    var action = this._subject.currentAction();
    if (action && action.isValid()) {
      this.startAction();
    } else {
      this.endAction();
    }
};

Yanfly.CTB.BattleManager_endAction = BattleManager.endAction;
BattleManager.endAction = function() {
    if (this.isCTB()) {
      this.endCTBAction();
    } else {
      Yanfly.CTB.BattleManager_endAction.call(this);
    }
};

BattleManager.endCTBAction = function() {
    if (Imported.YEP_BattleEngineCore) {
      if (this._processingForcedAction) this._phase = this._preForcePhase;
      this._processingForcedAction = false;
    }
    if (this._subject) this._subject.onAllActionsEnd();
    if (this.updateEventMain()) return;
    this._subject.endTurnAllCTB();
    if (this.loadPreForceActionSettings()) return;
    var chargedBattler = this.getChargedCTBBattler();
    if (chargedBattler) {
      this.startCTBAction(chargedBattler);
    } else {
      this.setCTBPhase();
    }
};

Yanfly.CTB.BattleManager_processEscape = BattleManager.processEscape;
BattleManager.processEscape = function() {
    if (this.isCTB()) {
      return this.processEscapeCTB();
    } else {
      return Yanfly.CTB.BattleManager_processEscape.call(this);
    }
};

BattleManager.processEscapeCTB = function() {
  $gameParty.performEscape();
  SoundManager.playEscape();
  var success = this._preemptive ? true : (Math.random() < this._escapeRatio);
  if (success) {
      $gameParty.removeBattleStates();
      $gameParty.performEscapeSuccess();
      this.displayEscapeSuccessMessage();
      this._escaped = true;
      this.processAbort();
  } else {
      this.actor().spriteStepBack();
      this.actor().clearActions();
      this.displayEscapeFailureMessage();
      this._escapeRatio += this._escapeFailBoost;
      this.startTurn();
      this.processFailEscapeCTB();
  }
  return success;
};

BattleManager.processFailEscapeCTB = function() {
    var actor = $gameParty.members()[this._actorIndex];
    if (!actor) return;
    actor.resetAllCTB();
};

BattleManager.redrawCTBIcons = function() {
    var max = $gameTroop.members().length;
    for (var i = 0; i < max; ++i) {
      var member = $gameTroop.members();
      if (!member) continue;
      if (!member.battler()._ctbIcon) continue;
      member.battler()._ctbIcon.forceRedraw();
    }
};

Yanfly.CTB.BattleManager_processActionSequence =
  BattleManager.processActionSequence;
BattleManager.processActionSequence = function(actionName, actionArgs) {
  if (this.isCTB()) {
    // CTB SPEED
    if (actionName === 'CTB SPEED') {
        this.actionCTBCharge(actionArgs);
      return this.actionCTBSpeed(actionArgs);
    }
    // CTB ORDER
    if (actionName === 'CTB ORDER') {
      return this.actionCTBOrder(actionArgs);
    }
  }
  return Yanfly.CTB.BattleManager_processActionSequence.call(this,
    actionName, actionArgs);
};

BattleManager.actionCTBCharge = function(actionArgs) {
    var targets = this.makeActionTargets(actionArgs[0]);
    if (targets.length < 1) return true;
    var cmd = actionArgs[1];
    if (cmd.match(/([\+\-]\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isCTBCharging()) continue;
        var max = target.ctbChargeDestination();
        var value = rate * max + target.ctbCharge();
        target.setCTBCharge(value);
        target.refresh();
      }
    } else if (cmd.match(/([\+\-]\d+)/i)) {
      var plus = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isCTBCharging()) continue;
        var value = plus + target.ctbCharge();
        target.setCTBCharge(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isCTBCharging()) continue;
        var max = target.ctbChargeDestination();
        var value = rate * max;
        target.setCTBCharge(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)/i)) {
      var value = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (!target.isCTBCharging()) continue;
        target.setCTBCharge(value);
        target.refresh();
      }
    }
    return true;
};

BattleManager.actionCTBSpeed = function(actionArgs) {
    var targets = this.makeActionTargets(actionArgs[0]);
    if (targets.length < 1) return true;
    var cmd = actionArgs[1];
    if (cmd.match(/([\+\-]\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      var max = this.ctbTarget();
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isCTBCharging()) continue;
        var value = rate * max + target.ctbSpeed();
        target.setCTBSpeed(value);
        target.refresh();
      }
    } else if (cmd.match(/([\+\-]\d+)/i)) {
      var plus = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isCTBCharging()) continue;
        var value = plus + target.ctbSpeed();
        target.setCTBSpeed(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)([%%])/i)) {
      var rate = parseFloat(RegExp.$1 * 0.01);
      var max = this.ctbTarget();
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isCTBCharging()) continue;
        var value = rate * max;
        target.setCTBSpeed(value);
        target.refresh();
      }
    } else if (cmd.match(/(\d+)/i)) {
      var value = parseInt(RegExp.$1);
      for (var i = 0; i < targets.length; ++i) {
        var target = targets;
        if (!target) continue;
        if (target === this._subject) continue;
        if (target.isCTBCharging()) continue;
        target.setCTBSpeed(value);
        target.refresh();
      }
    }
    return true;
};

BattleManager.actionCTBOrder = function(actionArgs) {
    var targets = this.makeActionTargets(actionArgs[0]);
    if (targets.length < 1) return true;
    var value = parseInt(actionArgs[1]);
    for (var i = 0; i < targets.length; ++i) {
      var target = targets;
      if (!target) continue;
      target.ctbAlterTurnOrder(value);
    }
    return true;
};

//=============================================================================
// Game_Action
//=============================================================================

Yanfly.CTB.Game_Action_applyItemUserEffect =
    Game_Action.prototype.applyItemUserEffect;
Game_Action.prototype.applyItemUserEffect = function(target) {
    Yanfly.CTB.Game_Action_applyItemUserEffect.call(this, target);
    if (BattleManager.isCTB() && $gameParty.inBattle()) {
      this.applyItemCTBEffect(target);
    }
};

Game_Action.prototype.applyItemCTBEffect = function(target) {
  if (!target) return;
  this.applyItemCTBOrderEffect(target);
  this.applyItemCTBOrderEvalEffect(target);
  this.applyItemCTBSetEffects(target);
  this.applyItemCTBAddEffects(target);
  this.applyItemCTBEvalEffect(target);
  this.rebalanceCTBSpeed(target);
};

Game_Action.prototype.applyItemCTBOrderEffect = function(target) {
    var item = this.item();
    if (!item) return;
    if (item.ctbOrderModifier === 0) return;
    target.ctbAlterTurnOrder(item.ctbOrderModifier);
};

Game_Action.prototype.applyItemCTBSetEffects = function(target) {
  var item = this.item();
  if (!item) return;
  var value = undefined;
  if (target.isCTBCharging()) {
    var max = target.ctbChargeDestination();
    if (item.setCTBGaugeFlat !== undefined) {
      value = item.setCTBGaugeFlat;
    } else if (item.setCTBGaugeRate !== undefined) {
      value = item.setCTBGaugeRate * max;
    }
    if (value !== undefined) target.setCTBCharge(value);
  } else {
    var max = BattleManager.ctbTarget();
    if (item.setCTBGaugeFlat !== undefined) {
      value = item.setCTBGaugeFlat;
    } else if (item.setCTBGaugeRate !== undefined) {
      value = item.setCTBGaugeRate * max;
    }
    if (value !== undefined) target.setCTBSpeed(value);
  }
};

Game_Action.prototype.applyItemCTBAddEffects = function(target) {
    var item = this.item();
    if (!item) return;
    if (target.isCTBCharging()) {
      var value = target.ctbCharge();
      var max = target.ctbChargeDestination();
      value += item.addCTBGaugeRate * max;
      value += item.addCTBGaugeFlat;
      target.setCTBCharge(value);
    } else {
      var value = target.ctbSpeed();
      var max = BattleManager.ctbTarget()
      value += item.addCTBGaugeRate * max;
      value += item.addCTBGaugeFlat;
      target.setCTBSpeed(value);
    }
};

Game_Action.prototype.applyItemCTBEvalEffect = function(target) {
    if (this.item().ctbEval === '') return;
    var a = this.subject();
    var user = this.subject();
    var b = target;
    var item = this.item();
    var skill = this.item();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var speed = target.ctbSpeed();
    var charge = target.ctbCharge();
    if (target.isCTBCharging()) {
      var max = target.ctbChargeDestination();
    } else {
      var max = BattleManager.ctbTarget();
    }
    eval(item.ctbEval);
    target.setCTBSpeed(speed);
    target.setCTBCharge(charge);
};

Game_Action.prototype.applyItemCTBOrderEvalEffect = function(target) {
    if (this.item().ctbOrderEval === '') return;
    var a = this.subject();
    var user = this.subject();
    var b = target;
    var item = this.item();
    var skill = this.item();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var order = 0;
    eval(item.ctbOrderEval);
    target.ctbAlterTurnOrder(order);
};

Game_Action.prototype.rebalanceCTBSpeed = function(target) {
    var speed = this.subject().ctbSpeed();
    var offset = 00000000001;
    speed = Math.max(speed + offset, target.ctbSpeed() + target.ctbCharge());
    this.subject().setCTBSpeed(speed);
};

//=============================================================================
// Game_Battlerbase
//=============================================================================

Yanfly.CTB.Game_BattlerBase_refresh = Game_BattlerBase.prototype.refresh;
Game_BattlerBase.prototype.refresh = function() {
    Yanfly.CTB.Game_BattlerBase_refresh.call(this);
    if (BattleManager.isCTB() && $gameParty.inBattle()) {
      this._ctbTickValue = undefined;
      this.clearCTBCommandWindowCache();
    }
};

Game_BattlerBase.prototype.clearCTBCommandWindowCache = function() {
    this._commandWindowIndex = undefined;
    this._commandWindowItem = undefined;
    this._skillWindowIndex = undefined;
    this._skillWindowItem = undefined;
    this._itemWindowIndex = undefined;
    this._itemWindowItem = undefined;
};

Yanfly.CTB.Game_BattlerBase_die = Game_BattlerBase.prototype.die;
Game_BattlerBase.prototype.die = function() {
    Yanfly.CTB.Game_BattlerBase_die.call(this);
    if (BattleManager.isCTB() && $gameParty.inBattle()) this.resetAllCTB();
};

Yanfly.CTB.Game_BattlerBase_appear = Game_BattlerBase.prototype.appear;
Game_BattlerBase.prototype.appear = function() {
    Yanfly.CTB.Game_BattlerBase_appear.call(this);
    if (BattleManager.isCTB() && this.isEnemy()) {
      BattleManager.redrawCTBIcons();
    }
};

//=============================================================================
// Game_Battler
//=============================================================================

Game_Battler.prototype.ctbIcon = function() {
    return 0;
};

Game_Battler.prototype.ctbBorderColor = function() {
    return 0;
};

Game_Battler.prototype.ctbBackgroundColor = function() {
    return 0;
};

Game_Battler.prototype.onCTBStart = function() {
    this._ctbSpeed = eval(Yanfly.Param.CTBInitSpeed);
    this._ctbSpeed += BattleManager.ctbTarget() * this.ctbStartRate();
    this._ctbSpeed += this.ctbStartFlat();
    this._ctbCharge = 0;
    this._ctbCharging = false;
    this._ctbChargeMod = 0;
    this.applyPreemptiveBonusCTB();
    this.applySurpriseBonusCTB();
    this.refresh();
};

Game_Battler.prototype.applyPreemptiveBonusCTB = function() {
    if (!BattleManager._preemptive) return;
    if (!this.isActor()) return;
    var rate = Yanfly.Param.CTBPreEmptive;
    this._ctbSpeed += rate * BattleManager.ctbTarget();
};

Game_Battler.prototype.applySurpriseBonusCTB = function() {
    if (!BattleManager._surprise) return;
    if (!this.isEnemy()) return;
    var rate = Yanfly.Param.CTBSurprise;
    this._ctbSpeed += rate * BattleManager.ctbTarget();
};

Yanfly.CTB.Game_Battler_onBattleEnd = Game_Battler.prototype.onBattleEnd;
Game_Battler.prototype.onBattleEnd = function() {
    Yanfly.CTB.Game_Battler_onBattleEnd.call(this);
    this._ctbSpeed = 0;
    this._ctbCharge = 0;
    this._ctbCharging = false;
    this._ctbChargeMod = 0;
    this.clearCTBCommandWindowCache();
};

Game_Battler.prototype.ctbTicksToReady = function() {
    var goal = BattleManager.ctbTarget();
    if (this.isCTBCharging()) goal += this.ctbChargeDestination();
    goal -= this.ctbSpeed();
    goal -= (this.isCTBCharging()) ? this.ctbCharge() : 0;
    var rate = this.ctbSpeedTick();
    if (this.ctbTicksToReadyActionCheck()) {
      var item = this.ctbTicksToReadyActionCheck();
      if (item.speed < 0) goal -= item.speed;
    }
    return goal / Math.max(1, rate);
};

Game_Battler.prototype.ctbTicksToReadyActionCheck = function() {
    if (!BattleManager.isInputting()) return false;
    if (BattleManager.actor() !== this) return false;
    var scene = SceneManager._scene;
    if (scene._skillWindow.active) {
      if (this._skillWindowIndex === scene._skillWindow.index()) {
        return this._skillWindowItem;
      }
      this._skillWindowIndex = scene._skillWindow.index();
      this._skillWindowItem = scene._skillWindow.item();
      return this._skillWindowItem;
    } else if (scene._itemWindow.active) {
      if (this._itemWindowIndex === scene._itemWindow.index()) {
        return this._itemWindowItem;
      }
      this._itemWindowIndex = scene._itemWindow.index();
      this._itemWindowItem = scene._itemWindow.item()
      return this._itemWindowItem;
    } else if (scene._actorCommandWindow.active) {
      if (this._commandWindowIndex === scene._actorCommandWindow.index()) {
        return this._commandWindowItem;
      }
      var win = scene._actorCommandWindow;
      var symbol = win.currentSymbol();
      this._commandWindowIndex = win.index();
      if (symbol === 'attack') {
        this._commandWindowItem = $dataSkills[this.attackSkillId()];
        return this._commandWindowItem;
      } else if (symbol === 'guard') {
        this._commandWindowItem = $dataSkills[this.guardSkillId()];
        return this._commandWindowItem;
      } else {
        this._commandWindowItem = undefined;
        return false;
      }
    }
    if (!this.currentAction()) return false;
    return this.currentAction().item();
};

Game_Battler.prototype.ctbSpeed = function() {
    if (this.isDead()) return -1 * BattleManager.ctbTarget();
    if (this.isHidden()) return -1 * BattleManager.ctbTarget();
    if (this._ctbSpeed === undefined) this.onCTBStart();
    return this._ctbSpeed;
};

Game_Battler.prototype.ctbRate = function() {
    if (this._ctbSpeed === undefined) this.onCTBStart();
    var rate = this._ctbSpeed / BattleManager.ctbTarget();
    return rate.clamp(0, 1);
};

Game_Battler.prototype.isCTBCharging = function() {
    return this._ctbCharging;
};

Game_Battler.prototype.setCTBCharging = function(value) {
    this._ctbCharging = value;
};

Game_Battler.prototype.ctbCharge = function() {
  if (this._ctbCharge === undefined) this.onCTBStart();
  return this._ctbCharge;
};

Game_Battler.prototype.ctbChargeDestination = function() {
    var denom = Math.max(1, -1 * this._ctbChargeMod);
    return denom;
};

Game_Battler.prototype.ctbChargeRate = function() {
    if (this._ctbCharge === undefined) this.onCTBStart();
    if (!this.isCTBCharging()) return 0;
    var rate = this._ctbCharge / this.ctbChargeDestination();
    return rate.clamp(0, 1);
};

Game_Battler.prototype.setCTBSpeed = function(value) {
    this._ctbSpeed = value;
};

Game_Battler.prototype.setCTBCharge = function(value) {
    if (this.isCTBCharging()) this._ctbCharge = value;
};

Game_Battler.prototype.setupCTBCharge = function() {
    if (!this.currentAction()) this.makeActions();
    if (this.currentAction()) {
      var item = this.currentAction().item();
      if (item && item.speed < 0) {
        this.setCTBCharging(true);
        this._ctbChargeMod = item.speed;
        this.setCTBCharge(0);
      } else if (!item) {
        this._ctbChargeMod = 0;
      } else {
        this._ctbChargeMod = 0;
      }
    } else {
      this._ctbChargeMod = 0;
    }
    this.setActionState('waiting');
    if (BattleManager.isTickBased()) this.onTurnStart();
};

Yanfly.CTB.Game_Battler_updateTick = Game_Battler.prototype.updateTick;
Game_Battler.prototype.updateTick = function() {
    Yanfly.CTB.Game_Battler_updateTick.call(this);
    if (BattleManager.isCTB()) this.updateCTB();
};

Game_Battler.prototype.updateCTB = function() {
    if (this.isDead()) return this.resetAllCTB();
    if (!this.canMove()) {
      this.updateCTBStates();
      return;
    }
    if (this.isCTBCharging()) {
      if (!this.currentAction()) this.resetAllCTB();
      if (this.currentAction() && this.currentAction().item() === null) {
        this.resetAllCTB();
      }
    }
    if (this.isCTBCharging()) {
      var value = this.ctbCharge() + this.ctbSpeedTick();
      this.setCTBCharge(value);
    } else if (this.ctbRate() < 1) {
      var value = this.ctbSpeed() + this.ctbSpeedTick();
      this.setCTBSpeed(value);
    }
};

Game_Battler.prototype.updateCTBStates = function() {
    if (BattleManager.timeBasedBuffs()) return;
    for (var i = 0; i < this._states.length; ++i) {
      var stateId = this._states;
      var state = $dataStates[stateId];
      if (!state) continue;
      if (!this._stateTurns[stateId]) continue;
      if (state.restriction >= 4 && state.autoRemovalTiming !== 0) {
        var value = BattleManager.tickRate() / Yanfly.Param.BECTurnTime;
        this._stateTurns[stateId] -= value;
        if (this._stateTurns[stateId] <= 0) this.removeState(stateId);
      }
    }
};

Game_Battler.prototype.resetAllCTB = function() {
    this._ctbCharge = 0;
    this._ctbChargeMod = 0;
    this._ctbCharging = false;
    this._ctbSpeed = 0;
    this.clearActions();
};

Game_Battler.prototype.endTurnAllCTB = function() {
    this._ctbCharge = 0;
    this._ctbChargeMod = 0;
    this._ctbCharging = false;
    if (this.checkCTBEndInstantCast()) return;
    this.setEndActionCTBSpeed();
    this.clearActions();
    this.setActionState('undecided');
    if (this.battler()) this.battler().refreshMotion();
    if (BattleManager.isTickBased()) this.onTurnEnd();
};

Game_Battler.prototype.checkCTBEndInstantCast = function() {
    if (!Imported.YEP_InstantCast) return false;
    var action = this.currentAction();
    if (!action) return false;
    var item = action.item();
    if (!item) return false;
    if (!this.isInstantCast(item)) return false;
    var length = BattleManager.allBattleMembers().length;
    for (var i = 0; i < length; ++i) {
      var member = BattleManager.allBattleMembers();
      if (!member) continue;
      var max = member.ctbSpeed() + member.ctbCharge();
      this._ctbSpeed = Math.max(this._ctbSpeed, max);
    }
    this._ctbSpeed = Math.max(this._ctbSpeed, BattleManager.ctbTarget());
    this._ctbSpeed += 0.00000000001;
    return true;
};

Game_Battler.prototype.ctbSpeedRate = function() {
    if (!this.canMove()) return 0;
    var base = this.paramBase(6) + this.paramPlus(6);
    if (base >= this.paramMax(6) && this.agi >= this.paramMax(6)) return 1;
    var rate = this.agi / base;
    return rate;
};

Game_Battler.prototype.ctbSpeedTick = function() {
    var value = this.ctbTickValue();
    if (BattleManager.ctbRubberband()) {
      var min = BattleManager.ctbMinimumSpeed();
      var max = BattleManager.ctbMaximumSpeed();
      value = value.clamp(min, max);
      value += this.minorCTBOffset();
    }
    return value * BattleManager.tickRate();
};

Game_Battler.prototype.ctbTickValue = function() {
    if (this._ctbTickValue !== undefined) return this._ctbTickValue;
    var a = this;
    var user = this;
    var subject = this;
    this._ctbTickValue = eval(Yanfly.Param.CTBPerTick);
    return this._ctbTickValue;
};

Game_Battler.prototype.setEndActionCTBSpeed = function() {
    this._ctbSpeed = 0;
    var action = this.currentAction();
    if (!action) return;
    var item = action.item();;
    if (item) {
      if (item.afterCTBFlat !== undefined) this.setCTBSpeed(item.afterCTBFlat);
      if (item.afterCTBRate !== undefined) {
        this.setCTBSpeed(item.afterCTBRate * BattleManager.ctbTarget());
      }
      if (item.speed > 0) this._ctbSpeed += item.speed;
    }
    this._ctbSpeed += BattleManager.ctbTarget() * this.ctbTurnRate();
    this._ctbSpeed += this.ctbTurnFlat();
    if (item) this.afterCTBEval(item);
};

Game_Battler.prototype.afterCTBEval = function(item) {
    if (!item) return;
    var a = this;
    var user = this;
    var skill = item;
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var speed = this._ctbSpeed;
    var max = BattleManager.ctbTarget();
    eval(item.ctbAfterEval);
    this.setCTBSpeed(speed);
};

Game_Battler.prototype.ctbStartFlat = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.ctbStartFlat;
    }
    return value;
};

Game_Battler.prototype.ctbStartRate = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.ctbStartRate;
    }
    return value;
};

Game_Battler.prototype.ctbTurnFlat = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.ctbTurnFlat;
    }
    return value;
};

Game_Battler.prototype.ctbTurnRate = function() {
    var value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states();
      if (state) value += state.ctbTurnRate;
    }
    return value;
};

Yanfly.CTB.Game_Battler_removeState = Game_Battler.prototype.removeState;
Game_Battler.prototype.removeState = function(stateId) {
    if (BattleManager.isCTB()) {
      var confuseCondition = this.isConfused();
    }
    Yanfly.CTB.Game_Battler_removeState.call(this, stateId);
    if (BattleManager.isCTB()) {
      if (confuseCondition !== this.isConfused()) this.resetAllCTB();
    }
};

Game_Battler.prototype.minorCTBOffset = function() {
    var value = 0.00000000001;
    if (this.isActor()) value *= $gameParty.members().length - this.index();
    if (this.isEnemy()) value *= -1 * this.index();
    return value;
};

Game_Battler.prototype.ctbTurnOrder = function() {
    var index = BattleManager.ctbTurnOrder().indexOf(this);
    return index;
};

Game_Battler.prototype.ctbAlterTurnOrder = function(value) {
    var sign = (value > 0) ? 1 : -1;
    var max = BattleManager.ctbTurnOrder().length - 1;
    var index = this.ctbTurnOrder();
    index += value;
    index = index.clamp(0, max);
    var battler = BattleManager.ctbTurnOrder()[index];
    if (!battler) battler = this;
    var ticksTarget = battler.ctbTicksToReady();
    var ticksCurrent = this.ctbTicksToReady();
    var ticksChange = ticksTarget - ticksCurrent;
    ticksChange += sign * Math.abs(this.minorCTBOffset());
    this._ctbSpeed -= this.ctbSpeedTick() * ticksChange;
};

//=============================================================================
// Game_Actor
//=============================================================================

Game_Actor.prototype.ctbIcon = function() {
    if (this.actor().ctbClassIcon) {
      if (this.actor().ctbClassIcon[this._classId]) {
        return this.actor().ctbClassIcon[this._classId];
      }
    }
    return this.actor().ctbIcon;
};

Game_Actor.prototype.ctbBorderColor = function() {
    return this.actor().ctbBorderColor;
};

Game_Actor.prototype.ctbBackgroundColor = function() {
    return this.actor().ctbBackgroundColor;
};

Game_Actor.prototype.ctbStartFlat = function() {
    var value = Game_Battler.prototype.ctbStartFlat.call(this);
    value += this.actor().ctbStartFlat;
    value += this.currentClass().ctbStartFlat;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.ctbStartFlat) value += equip.ctbStartFlat;
    }
    return value;
};

Game_Actor.prototype.ctbStartRate = function() {
    var value = Game_Battler.prototype.ctbStartRate.call(this);
    value += this.actor().ctbStartRate;
    value += this.currentClass().ctbStartRate;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.ctbStartRate) value += equip.ctbStartRate;
    }
    return value;
};

Game_Actor.prototype.ctbTurnFlat = function() {
    var value = Game_Battler.prototype.ctbTurnFlat.call(this);
    value += this.actor().ctbTurnFlat;
    value += this.currentClass().ctbTurnFlat;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.ctbTurnFlat) value += equip.ctbTurnFlat;
    }
    return value;
};

Game_Actor.prototype.ctbTurnRate = function() {
    var value = Game_Battler.prototype.ctbTurnRate.call(this);
    value += this.actor().ctbTurnRate;
    value += this.currentClass().ctbTurnRate;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips();
      if (equip && equip.ctbTurnRate) value += equip.ctbTurnRate;
    }
    return value;
};

Yanfly.CTB.Game_Actor_changeClass = Game_Actor.prototype.changeClass;
Game_Actor.prototype.changeClass = function(classId, keepExp) {
    Yanfly.CTB.Game_Actor_changeClass.call(this, classId, keepExp);
    this.ctbTransform();
};

Yanfly.CTB.Game_Actor_setCharacterImage =
    Game_Actor.prototype.setCharacterImage;
Game_Actor.prototype.setCharacterImage = function(name, index) {
    Yanfly.CTB.Game_Actor_setCharacterImage.call(this, name, index)
    this.ctbTransform();
};

Yanfly.CTB.Game_Actor_setFaceImage = Game_Actor.prototype.setFaceImage;
Game_Actor.prototype.setFaceImage = function(faceName, faceIndex) {
    Yanfly.CTB.Game_Actor_setFaceImage.call(this, faceName, faceIndex);
    this.ctbTransform();
};

Yanfly.CTB.Game_Actor_setBattlerImage = Game_Actor.prototype.setBattlerImage;
Game_Actor.prototype.setBattlerImage = function(battlerName) {
    Yanfly.CTB.Game_Actor_setBattlerImage.call(this, battlerName);
    this.ctbTransform();
};

Game_Actor.prototype.ctbTransform = function() {
    if (!$gameParty.inBattle()) return;
    if (!BattleManager.isCTB()) return;
    this._ctbTransformed = true;
};

//=============================================================================
// Game_Enemy
//=============================================================================

Game_Enemy.prototype.ctbIcon = function() {
    return this.enemy().ctbIcon;
};

Game_Enemy.prototype.ctbBorderColor = function() {
    return this.enemy().ctbBorderColor;
};

Game_Enemy.prototype.ctbBackgroundColor = function() {
    return this.enemy().ctbBackgroundColor;
};

Game_Enemy.prototype.ctbStartFlat = function() {
    var value = Game_Battler.prototype.ctbStartFlat.call(this);
    value += this.enemy().ctbStartFlat;
    return value;
};

Game_Enemy.prototype.ctbStartRate = function() {
    var value = Game_Battler.prototype.ctbStartRate.call(this);
    value += this.enemy().ctbStartRate;
    return value;
};

Game_Enemy.prototype.ctbTurnFlat = function() {
    var value = Game_Battler.prototype.ctbTurnFlat.call(this);
    value += this.enemy().ctbTurnFlat;
    return value;
};

Game_Enemy.prototype.ctbTurnRate = function() {
    var value = Game_Battler.prototype.ctbTurnRate.call(this);
    value += this.enemy().ctbTurnRate;
    return value;
};

Yanfly.CTB.Game_Enemy_transform = Game_Enemy.prototype.transform;
Game_Enemy.prototype.transform = function(enemyId) {
    Yanfly.CTB.Game_Enemy_transform.call(this, enemyId);
    this._ctbTransformed = true;
};

//=============================================================================
// Game_Unit
//=============================================================================

Game_Unit.prototype.onCTBStart = function() {
    if (!BattleManager.isCTB()) return;
    for (var i = 0; i < this.members().length; ++i) {
      var member = this.members();
      if (member) member.onCTBStart();
    }
};

Game_Unit.prototype.increaseTurnTimeBasedCTB = function() {
    for (var i = 0; i < this.members().length; ++i) {
      var member = this.members();
      if (!member) continue;
      if (member.isDead()) continue;
      if (member.isHidden()) continue;
      if (member.canMove()) continue;
      member.onTurnEnd();
    }
};

//=============================================================================
// Game_Party
//=============================================================================

Yanfly.CTB.Game_Party_performEscape = Game_Party.prototype.performEscape;
Game_Party.prototype.performEscape = function() {
    if (BattleManager.isCTB()) return;
    Yanfly.CTB.Game_Party_performEscape.call(this);
};

//=============================================================================
// Game_Troop
//=============================================================================

Yanfly.CTB.Game_Troop_increaseTurn = Game_Troop.prototype.increaseTurn;
Game_Troop.prototype.increaseTurn = function() {
    Yanfly.CTB.Game_Troop_increaseTurn.call(this);
    if (BattleManager.isCTB() && BattleManager.timeBasedStates()) {
      $gameParty.increaseTurnTimeBasedCTB();
      this.increaseTurnTimeBasedCTB();
    }
};

//=============================================================================
// Sprite_Battler
//=============================================================================

Yanfly.CTB.Sprite_Battler_postSpriteInitialize =
        Sprite_Battler.prototype.postSpriteInitialize;
Sprite_Battler.prototype.postSpriteInitialize = function() {
    Yanfly.CTB.Sprite_Battler_postSpriteInitialize.call(this);
    if (BattleManager.isCTB()) this.createCTBIcon();
};

Sprite_Battler.prototype.createCTBIcon = function() {
    if (!Yanfly.Param.CTBTurnOrder) return;
    this._ctbIcon = new Window_CTBIcon(this);
};

Yanfly.CTB.Sprite_Battler_update = Sprite_Battler.prototype.update;
Sprite_Battler.prototype.update = function() {
    Yanfly.CTB.Sprite_Battler_update.call(this);
    this.addCTBIcon();
};

Sprite_Battler.prototype.addCTBIcon = function() {
    if (!this._ctbIcon) return;
    if (this._addedCTBIcon) return;
    if (!SceneManager._scene) return;
    var scene = SceneManager._scene;
    if (!scene._windowLayer) return;
    this._addedCTBIcon = true;
    this._ctbIcon.setWindowLayer(scene._windowLayer);
    scene.addChild(this._ctbIcon);
};

//=============================================================================
// Window_Help
//=============================================================================

Yanfly.CTB.Window_Help_setItem = Window_Help.prototype.setItem;
Window_Help.prototype.setItem = function(item) {
    if (this.meetCTBConditions(item)) return this.setText(item.ctbHelp);
    Yanfly.CTB.Window_Help_setItem.call(this, item);
};

Window_Help.prototype.meetCTBConditions = function(item) {
    if (!item) return false;
    if (!BattleManager.isCTB()) return false;
    return item.ctbHelp !== undefined;
};

//=============================================================================
// Window_CTBIcon
//=============================================================================

function Window_CTBIcon() {
    this.initialize.apply(this, arguments);
}

Window_CTBIcon.prototype = Object.create(Window_Base.prototype);
Window_CTBIcon.prototype.constructor = Window_CTBIcon;

Window_CTBIcon.prototype.initialize = function(mainSprite) {
    this._mainSprite = mainSprite;
    var width = this.iconWidth() + 8 + this.standardPadding() * 2;
    var height = this.iconHeight() + 8 + this.standardPadding() * 2;
    this._redraw = false;
    this._position = Yanfly.Param.CTBTurnPosX.toLowerCase();
    this._direction = Yanfly.Param.CTBTurnDirection.toLowerCase();
    Window_Base.prototype.initialize.call(this, 0, 0, width, height);
    this.opacity = 0;
    this.contentsOpacity = 0;
};

Window_CTBIcon.prototype.iconWidth = function() {
    return Yanfly.Param.CTBIconSize;
};

Window_CTBIcon.prototype.iconHeight = function() {
    return Yanfly.Param.CTBIconSize;
};

Window_CTBIcon.prototype.setWindowLayer = function(windowLayer) {
        this._windowLayer = windowLayer;
};

Window_CTBIcon.prototype.update = function() {
    Window_Base.prototype.update.call(this);
    this.updateBattler();
    this.updateIconIndex();
    this.updateRedraw();
    this.updateDestinationX();
    this.updateOpacity();
    this.updatePositionX();
    this.updatePositionY();
};

Window_CTBIcon.prototype.updateBattler = function() {
    var changed = this._battler !== this._mainSprite._battler;
    if (this._battler && this._battler._ctbTransformed) changed = true;
    if (!changed) return;
    this._battler = this._mainSprite._battler;
    if (!this._battler) return this.removeCTBIcon();
    this._battler._ctbTransformed = undefined;
    this._iconIndex = this._battler.ctbIcon();
    if (this._iconIndex > 0) {
      this._image = ImageManager.loadSystem('IconSet');
    } else if (this._battler.isEnemy()) {
      if (this.isUsingSVBattler()) {
        var name = this._battler.svBattlerName();
        this._image = ImageManager.loadSvActor(name);
      } else {
        var battlerName = this._battler.battlerName();
        var battlerHue = this._battler.battlerHue();
        if ($gameSystem.isSideView()) {
          this._image = ImageManager.loadSvEnemy(battlerName, battlerHue);
        } else {
          this._image = ImageManager.loadEnemy(battlerName, battlerHue);
        }
      }
    } else if (this._battler.isActor()) {
      var faceName = this._battler.faceName();
      this._image = ImageManager.loadFace(faceName);
    }
    this._redraw = true;
};

Window_CTBIcon.prototype.removeCTBIcon = function() {
    this.contents.clear();
    this.opacity = 0;
    this.contentsOpacity =0;
};

Window_CTBIcon.prototype.isUsingSVBattler = function() {
    if (!Imported.YEP_X_AnimatedSVEnemies) return false;
    if (!this._battler.hasSVBattler()) return false;
    return Yanfly.Param.CTBEnemySVBattler;
};

Window_CTBIcon.prototype.updateIconIndex = function() {
    if (!this._battler) return;
    var changed = this._iconIndex !== this._battler.ctbIcon();
    if (changed) {
        this._iconIndex = this._battler.ctbIcon();
        this._redraw = true;
    }
};

Window_CTBIcon.prototype.forceRedraw = function() {
    this._redraw = true;
};

Window_CTBIcon.prototype.updateRedraw = function() {
    if (!this._redraw) return;
    if (!this._image) return;
    if (this._image.width <= 0) return;
    this._redraw = false;
    this.contents.clear();
    this.drawBorder();
    if (this._iconIndex > 0) {
        this.drawIcon(this._iconIndex, 4, 4);
    } else if (this._battler.isActor()) {
        this.redrawActorFace();
    } else if (this._battler.isEnemy()) {
        this.redrawEnemy();
    }
    this.redrawLetter();
};

Window_CTBIcon.prototype.drawIcon = function(iconIndex, x, y) {
    var bitmap = ImageManager.loadSystem('IconSet');
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = iconIndex % 16 * pw;
    var sy = Math.floor(iconIndex / 16) * ph;
    var ww = this.iconWidth();
    var wh = this.iconHeight();
    this.contents.blt(bitmap, sx, sy, pw, ph, x, y, ww, wh);
};

Window_CTBIcon.prototype.drawBorder = function() {
    var width = this.contents.width;
    var height = this.contents.height;
    this.contents.fillRect(0, 0, width, height, this.gaugeBackColor());
    width -= 2;
    height -= 2;
    this.contents.fillRect(1, 1, width, height, this.ctbBorderColor());
    width -= 4;
    height -= 4;
    this.contents.fillRect(3, 3, width, height, this.gaugeBackColor());
    width -= 2;
    height -= 2;
    this.contents.fillRect(4, 4, width, height, this.ctbBackgroundColor());
};

Window_CTBIcon.prototype.ctbBorderColor = function() {
    var colorId = this._battler.ctbBorderColor() || 0;
    return this.textColor(colorId);
};

Window_CTBIcon.prototype.ctbBackgroundColor = function() {
    var colorId = this._battler.ctbBackgroundColor() || 0;
    return this.textColor(colorId);
};

Window_CTBIcon.prototype.redrawActorFace = function() {
    var width = Window_Base._faceWidth;
    var height = Window_Base._faceHeight;
    var faceIndex = this._battler.faceIndex();
    var bitmap = this._image;
    var pw = Window_Base._faceWidth;
    var ph = Window_Base._faceHeight;
    var sw = Math.min(width, pw);
    var sh = Math.min(height, ph);
    var dx = Math.floor(Math.max(width - pw, 0) / 2);
    var dy = Math.floor(Math.max(height - ph, 0) / 2);
    var sx = faceIndex % 4 * pw + (pw - sw) / 2;
    var sy = Math.floor(faceIndex / 4) * ph + (ph - sh) / 2;
    var dw = this.contents.width - 8;
    var dh = this.contents.height - 8;
    this.contents.blt(bitmap, sx, sy, sw, sh, dx + 4, dy + 4, dw, dh);
};

Window_CTBIcon.prototype.redrawEnemy = function() {
    if (this.isUsingSVBattler()) {
      return this.redrawSVEnemy();
    };
    var bitmap = this._image;
    var sw = bitmap.width;
    var sh = bitmap.height;
    var dw = this.contents.width - 8;
    var dh = this.contents.height - 8;
    var dx = 0;
    var dy = 0;
    if (sw >= sh) {
      var rate = sh / sw;
      dh *= rate;
      dy += this.contents.height - 8 - dh;
    } else {
      var rate = sw / sh;
      dw *= rate;
      dx += Math.floor((this.contents.width - 8 - dw) / 2);
    }
    this.contents.blt(bitmap, 0, 0, sw, sh, dx + 4, dy + 4, dw, dh);
};

Window_CTBIcon.prototype.redrawSVEnemy = function() {
    var bitmap = this._image;
    var sw = bitmap.width / 9;
    var sh = bitmap.height / 6;
    var dw = this.contents.width - 8;
    var dh = this.contents.height - 8;
    var dx = 0;
    var dy = 0;
    if (sw >= sh) {
      var rate = sh / sw;
      dh *= rate;
      dy += this.contents.height - 8 - dh;
    } else {
      var rate = sw / sh;
      dw *= rate;
      dx += Math.floor((this.contents.width - 8 - dw) / 2);
    }
    this.contents.blt(bitmap, 0, 0, sw, sh, dx + 4, dy + 4, dw, dh);
};

Window_CTBIcon.prototype.redrawLetter = function() {
    if (!this._battler.isEnemy()) return;
    if (!this._battler._plural) return;
    var letter = this._battler._letter;
    var dy = this.contents.height - this.lineHeight();
    this.drawText(letter, 0, dy, this.contents.width - 4, 'right');
};

Window_CTBIcon.prototype.destinationXConstant = function() {
    return this.contents.width + 2;
};

Window_CTBIcon.prototype.updateDestinationX = function() {
    if (!this._battler) return;
    if (this._battler.isDead()) return;
    if (this._position === 'left') this.updateDestinationLeftAlign();
    if (this._position === 'center') this.updateDestinationCenterAlign();
    if (this._position === 'right') this.updateDestinationRightAlign();
    if (this._direction === 'left') this.updateDestinationGoingLeft();
    if (this._direction === 'right') this.updateDestinationGoingRight();
};

Window_CTBIcon.prototype.updateDestinationLeftAlign = function() {
    this._destinationX = 0;
};

Window_CTBIcon.prototype.updateDestinationCenterAlign = function() {
    this._destinationX = 0;
    var width = this.standardPadding() * 2;
    var size = BattleManager.ctbTurnOrder().length;
    var constant = this.destinationXConstant();
    width += constant * size;
    width += constant / 2 - 2;
    this._destinationX = Math.floor((Graphics.boxWidth - width) / 2);
};

Window_CTBIcon.prototype.updateDestinationRightAlign = function() {
    this._destinationX = Graphics.boxWidth;
    this._destinationX -= this.standardPadding() * 2;
    var size = BattleManager.ctbTurnOrder().length;
    var constant = this.destinationXConstant();
    this._destinationX -= constant * size;
    this._destinationX -= constant / 2;
    this._destinationX += 2;
};

Window_CTBIcon.prototype.updateDestinationGoingLeft = function(index) {
    var index = BattleManager.ctbTurnOrder().indexOf(this._battler);
    if (index < 0) index = BattleManager.ctbTurnOrder().length + 5;
    var constant = this.destinationXConstant();
    this._destinationX += index * constant;
    if (index !== 0) {
      this._destinationX += constant / 2;
    }
};

Window_CTBIcon.prototype.updateDestinationGoingRight = function(index) {
    var index = BattleManager.ctbTurnOrder().reverse().indexOf(this._battler);
    if (index < 0) index = -5;
    var constant = this.destinationXConstant();
    this._destinationX += index * constant;
    if (index === BattleManager.ctbTurnOrder().length - 1) {
      this._destinationX += constant / 2;
    }
};

Window_CTBIcon.prototype.updatePositionX = function() {
    if (this._destinationX === undefined) return;
    if (BattleManager._escaped) return;
    var desX = this._destinationX;
    var moveAmount = Math.max(1, Math.abs(desX - this.x) / 4);
    if (this.x > desX) this.x = Math.max(this.x - moveAmount, desX);
    if (this.x < desX) this.x = Math.min(this.x + moveAmount, desX);
};

Window_CTBIcon.prototype.destinationY = function() {
    var value = Yanfly.Param.CTBTurnPosY - this.standardPadding();
    var scene = SceneManager._scene;
    if (scene && scene._helpWindow.visible) {
        value = Math.max(value, scene._helpWindow.height);
    }
    if (!this._battler) return value;
    if (this._battler.isSelected()) {
        value -= this.contents.height / 4;
    }
    return value;
};

Window_CTBIcon.prototype.updatePositionY = function() {
    if (BattleManager._escaped) return;
    if (this._destinationX !== this.x) {
      var desX = this._destinationX;
      var cap1 = this.destinationY() - this.contents.height / 2;
      var cap2 = this.destinationY() + this.contents.height / 2;
      var moveAmount = Math.max(1, Math.abs(cap2 - this.y) / 4);
      if (this.x > desX) this.y = Math.max(this.y - moveAmount, cap1);
      if (this.x < desX) this.y = Math.min(this.y + moveAmount, cap2);
    } else if (this.destinationY() !== this.y) {
      var desY = this.destinationY();
      var moveAmount = Math.max(1, Math.abs(desY - this.y) / 4);
      if (this.y > desY) this.y = Math.max(this.y - moveAmount, desY);
      if (this.y < desY) this.y = Math.min(this.y + moveAmount, desY);
    }
};

Window_CTBIcon.prototype.opacityFadeRate = function() {
    return 8;
};

Window_CTBIcon.prototype.updateOpacity = function() {
    var rate = this.opacityFadeRate();
    if (this._foreverHidden) return this.reduceOpacity();
    if (this._windowLayer && this._windowLayer.x !== 0) {
      return this.reduceOpacity();
    }
    if (BattleManager._victoryPhase) {
      this._foreverHidden = true;
      return this.reduceOpacity();
    }
    if (BattleManager._escaped) {
      this._foreverHidden = true;
      return this.reduceOpacity();
    }
    if (this._battler) {
      var index = BattleManager.ctbTurnOrder().reverse().indexOf(this._battler);
      if (index < 0) return this.reduceOpacity();
    }
    this.contentsOpacity += rate;
};

Window_CTBIcon.prototype.reduceOpacity = function() {
    this.contentsOpacity -= this.opacityFadeRate();
};

//=============================================================================
// Scene_Battle
//=============================================================================

Yanfly.CTB.Scene_Battle_isStartActorCommand =
    Scene_Battle.prototype.isStartActorCommand;
Scene_Battle.prototype.isStartActorCommand = function() {
    if (BattleManager.isCTB()) return true;
    return Yanfly.CTB.Scene_Battle_isStartActorCommand.call(this);
};

Yanfly.CTB.Scene_Battle_commandFight = Scene_Battle.prototype.commandFight;
Scene_Battle.prototype.commandFight = function() {
    if (BattleManager.isCTB()) {
      this.startActorCommandSelection();
      BattleManager._phase = 'input';
    } else {
      Yanfly.CTB.Scene_Battle_commandFight.call(this);
    }
};

Yanfly.CTB.Scene_Battle_startActorCommandSelection =
    Scene_Battle.prototype.startActorCommandSelection;
Scene_Battle.prototype.startActorCommandSelection = function() {
    Yanfly.CTB.Scene_Battle_startActorCommandSelection.call(this);
    if (BattleManager.isCTB()) {
      BattleManager.actor().spriteStepForward();
      BattleManager.actor().setActionState('undecided');
      BattleManager.actor().requestMotionRefresh();
      BattleManager.actor().makeActions();
    }
};

Yanfly.CTB.Scene_Battle_updateWindowPositions =
    Scene_Battle.prototype.updateWindowPositions;
Scene_Battle.prototype.updateWindowPositions = function() {
    if (BattleManager.isCTB()) return this.updateWindowPositionsCTB();
    Yanfly.CTB.Scene_Battle_updateWindowPositions.call(this);
};

Scene_Battle.prototype.updateWindowPositionsCTB = function() {
    if (this._ctbWindowPosCount === undefined) this._ctbWindowPosCount = 0;
    if (this._partyCommandWindow.active) {
      this._ctbWindowPosCount = 16;
      var statusX = 0;
      statusX = this._partyCommandWindow.width;
      if (this._statusWindow.x < statusX) {
        this._statusWindow.x += 16;
        if (this._statusWindow.x > statusX) this._statusWindow.x = statusX;
      }
      if (this._statusWindow.x > statusX) {
        this._statusWindow.x -= 16;
        if (this._statusWindow.x < statusX) this._statusWindow.x = statusX;
      }
    } else if (this._actorCommandWindow.active) {
      this._ctbWindowPosCount = 16;
      Yanfly.CTB.Scene_Battle_updateWindowPositions.call(this);
    } else {
      if (--this._ctbWindowPosCount > 0) return;
      Yanfly.CTB.Scene_Battle_updateWindowPositions.call(this);
    }
};

//=============================================================================
// End of File
//=============================================================================
};
[/fold]
回复

使用道具 举报

梦石
0
星屑
80
在线时间
386 小时
注册时间
2007-7-27
回帖
4075

开拓者

发表于 2016-2-27 18:28:13 | 显示全部楼层
我记得YEP最开始有两种,一种是按时间计算的,一种是按回合计算的
后来他觉得太复杂了,就把按时间的砍了
吸吸
回复

使用道具 举报

梦石
0
星屑
61
在线时间
696 小时
注册时间
2011-1-4
回帖
176
 楼主| 发表于 2016-2-27 20:12:59 | 显示全部楼层
本帖最后由 cjlzbb 于 2016-2-27 20:15 编辑
trentswd 发表于 2016-2-27 18:28
我记得YEP最开始有两种,一种是按时间计算的,一种是按回合计算的
后来他觉得太复杂了,就把按时间的砍了 ...


今天到官网下了最新版的脚本,才知道原来还有个很类似的BUG。。。

原来的版本里如果对敌人附加无法行动的状态,那么ATB槽会暂停

然后就因为主楼里描述的机制,因为一直ATB槽暂停了,所以该怪物身上的状态持续时间一直没变。。就成了永久控制了。


新版的里面可以改成你说的按帧数算的,但是蛋疼的是他只改了状态触发没改技能冷却,结果还是一样 o(╯□╰)o囧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部