You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ycrpg/js/plugins/YEP_X_CounterControl.js

2046 lines
91 KiB
JavaScript

//=============================================================================
// Yanfly Engine Plugins - Battle Engine Extension - Counter Control
// YEP_X_CounterControl.js
//=============================================================================
var Imported = Imported || {};
Imported.YEP_X_CounterControl = true;
var Yanfly = Yanfly || {};
Yanfly.Counter = Yanfly.Counter || {};
Yanfly.Counter.version = 1.07;
//=============================================================================
/*:
* @plugindesc v1.07 反击控制
* @author Yanfly Engine Plugins
*
* @param ---General---
* @default
*
* @param Queue Max
* @desc What's the maximum size for the counter queue?
* @default 20
*
* @param ---Default Traits---
* @default
*
* @param Counter Skill
* @desc This is the default skill used for counterattacks.
* Insert the skill ID here. Use 0 for the MV default.
* @default 1
*
* @param Evade Counter
* @desc Counter skills to evade,then counter by default?
* NO - false YES - true
* @default false
*
* @param Counter Name
* @desc The default counter skill name used per skill.
* %1 - Skill Name
* @default Counter-%1
*
* @param Counter Icon
* @desc The icon ID used for counter attacks. Leave at 0
* to use the default skill's icon.
* @default 78
*
* @param Counter Total
* @desc Default amount of counters per actor and enemy.
* @default 1
*
* @param Ally Counter
* @desc Allow allies to counter the actions of other allies?
* NO - false YES - true
* @default false
*
* @param --Default Conditions-
* @default
*
* @param Physical
* @desc Require the countered action to be physical?
* NO - false YES - true
* @default true
*
* @param Single Target
* @desc Require the countered action scope to be single target?
* NO - false YES - true
* @default true
*
* @param Not Counter
* @desc Require the countered action to not be a counter?
* NO - false YES - true
* @default false
*
* @help
* ============================================================================
* Introduction
* ============================================================================
*
* 这个插件需要 YEP_BattleEngineCore确保他放在 YEP_BattleEngineCore下面
*
* 如果你使用了YEP_X_BattleSysATB或者YEP_X_BattleSysCTB请放在他们下面
*
* 默认的反击特性没有太多开发设置这是一个可以躲避敌方攻击并且反击的技能
* 这个插件可以让你更好的控制反击方式
*
* ============================================================================
* Instructions - How Advanced Counters Work
* ============================================================================
*
* A counterattack is an action that serves as a reaction to an action used by
* an opposing battler unless the action is marked as able of being countered
* by allied members.反击是作为对一项行动的反馈行动
*
* Now begins a clash between the attacker's anti-counter stat (newly added)
* against the target's counter stat plus any of the action's modifiers. Once
* the finalized counter rate is decided, a random number check is made to see
* if the counter will pass. If it doesn't, no counter will occur. If it does,
* the next step occurs.当判断反击成功时才会行动
*
* The target will then generate a pool of skills it can use as counters. It
* will go in a priority list mentioned in the next section below. The battle
* system will then go through the pool of skills in order and select the first
* counter skill that meets all of the conditions required. If no skill is
* selected, no skill will be used as a counter. All skills have a mandatory
* requirement of being able to pay the skill's cost and can use it.
* 将会从反击技能池选择技能进行反击
*
* Once the skill is selected, the counter skill is placed in the counter
* queue and waits for the current attacker's turn to be over. Once over,
* the actions in the counter queue will begin. The counterattacker will
* perform counter actions without conflicting with their own turns.
* This process will repeat itself until the counter queue is emptied.
* 选择技能后反击技能将被放置在反击队列中并等待当前攻击者的回合结束
* 结束后反击队列中的操作将开始反击者将执行反击动作而不会与自己
* 的回合发生冲突此过程将重复直到反击队列被清空
*
* During the counter queue process, counter skills can trigger counter skills,
* too. For that reason, there is a maximum queue size determined by the plugin
* parameters. Once the queue count reaches this size, no more counter skills
* will be added to the counter queue.反击也可以诱发反击你可以设置最大值
*
* ============================================================================
* Instructions - Counter Skill Priority List
* ============================================================================
*
* 技能池产生后执行顺序如下
*
* 1. States - 从高优先度的状态到低优先度状态
* 2. States - 从高优先度的状态到低优先度状态
* 3. Equipment - 武器标签
* 4. Equipment - 装备标签
* 5. Actor - 职业标签
* 6. Actor - 角色标签
* 7. Enemy - 敌人标签
*
* The order of the pool of counter skills matter in that when going through
* the conditions of the counter skill to be used, the first counter skill
* whose condition is met will be the one used.
*
* ============================================================================
* Notetags
* ============================================================================
*
* 使用下面标签设置
*
* Actor and Enemy Notetags:
*
* <Default Counter: x>
* <Default Counter: name> 默认反击技能
* Sets the default counter skill to x. If it is left as 0, then the counter
* skill will be RPG Maker MV's default counter skill. If you are using the
* name of the skill, and there are multiple skills in the database with the
* same name, then priority will be given to the skill with the highest ID.
* *Note: Use 0 for x if you wish to add RPG Maker MV's default counter.
* 将默认反击技能设置为 x如果保留为 0则反击技能将是 RPG Maker MV 的默认反击技能
* 如果您使用的是技能名称并且数据库中有多个同名的技能 ID 最高的技能将优先
* 注意如果您希望添加 RPG Maker MV 的默认反击请使用 0 替换 x
*
* Actor, Class, Enemy, Weapon, Armor, and State Notetags:
*
* <Counter Skills: x>
* <Counter Skills: x, x, x>
* <Counter Skills: x to y> 反击技能表
* This will add to the list of possible counter skills for the battler.
* If multiple skill ID's are listed, then they're all added. Priority will
* be given to the counter skills listed earlier.
* *Note: Use 0 for x if you wish to add RPG Maker MV's default counter.
* *Note2: See the Counter List priority to see which skills will be given
* priority on the counter skill list.
* 这将添加到战斗者可能的反击技能列表中
* 如果列出了多个技能 ID则会将它们全部添加将优先考虑前面列出的反击技能
* 注意如果您希望添加 RPG Maker MV 的默认反击请使用 0 表示 x
* 注2查看反击列表优先级查看反击技能列表中哪些技能将优先
*
* <Counter Skill: name> 反击技能表
* This will add the named skill to the list of possible counter skills for
* the battler. If there are multiple skills in the database with the same
* name, then priority will be given to the skill with the highest ID.
* *Note: See the Counter List priority to see which skills will be given
* priority on the counter skill list.
* 这会将命名的技能添加到战斗人员可能的反击技能列表中如果数据库中有多个同名的技能
* 则将优先考虑 ID 最高的技能
* *注意请参阅反击列表优先级查看反击技能列表中将优先考虑哪些技能
*
* <Counter Total: +x>
* <Counter Total: -x> 反击次数
* Alters the number of times the battler can counter by x. This is the
* amount of times the battler can counter until the battler's turn comes up
* at which, the number of times is reset.
* 改变战斗者可以反击的次数 x 这是战斗者可以反击的次数直到战斗者回合出现重置次数
*
* <Target Counter: x%> 目标反击率
* When this battler attacks an opponent target, this will cause the target
* counter rate to be altered by x% rate. If a target has 10% CNT, then a
* notetag of 50% will cause the counter rate to become 5%.
* 当该战斗者攻击敌方目标时这将导致目标反击率改变 x%
* 如果目标具有 10% 反击率 50% notetag 将导致目标反击率变为 5%
*
* <Target Counter: +x%>
* <Target Counter: -x%> 目标反击率
* When this battler attacks an opponent target, this will cause the target
* counter rate to increase or decrease by x%. If a target has 10% CNT, then
* a notetag of +50% will cause the counter rate to become +60%.
* 当该战斗者攻击敌方目标时这将导致目标反击率增加或减少 x%
* 如果目标具有 10% 反击率 +50% notetag 将导致反击率变为 +60%
* <Evade Counter> 躲避反击
* This will change all counter skills used by the related battler to become
* evade counters regardless of their default nature. However, if the battler
* is affected by a trait that is <Hit Counter>, then priority will be given
* to the <Hit Counter> trait instead.
* 这将改变相关战斗者使用的所有反击技能使其成为闪避反击无论其默认性质如何
* 但是如果战斗人员受到<命中反击>特性的影响则将优先考虑<命中反击>特性
*
* <Hit Counter> 命中反击
* This will change all counter skills used by the related battler to become
* hit counters regardless of their default nature. If the battler is also
* affected by <Evade Counter>, this effect will take priority.
* 这将改变相关战斗者使用的所有反击技能使其成为命中反击无论其默认性质如何
* 如果战斗者也受到<闪避反击>的影响则本效果将优先
*
* Skill and Item Notetags:
*
* <Ally Counter> 可以被队员用来反击
* Makes this action able to proc counter skills by allied members.
*
* <Ally Cannot Counter> 不可以被队员用来反击
* Makes this action unable to proc counter skills by allied members.
*
* <Cannot Counter> 不能反击
* Causes this action to be un-counterable. This means that it will always
* return a 0% counterattack possibility.
* 导致此操作不可反击这意味着它将始终返回 0% 的反击可能性
*
* <Counter Rate: x%> 反击概率
* This will cause this action to proc a counter from the target by x% rate.
* This means if the target has a 10% chance to counter and this notetag is
* 50%, then the target will have a 5% chance to counter.
* 将目标对此次行动的反击概率乘以设定的比率 x%
* 这意味着如果目标有 10% 的反击几率而这个注释标签是 50%那么目标将有 5% 的反击几率
*
* <Counter Rate: +x%>
* <Counter Rate: -x%> 反击概率
* This will cause this action to proc a counter from the target by an
* additive x%. This means if the target has a 10% chance to counter and this
* notetag is +50%, then the target has a 60% chance to counter.
* 将目标对此次行动的反击概率乘以设定的几率 x%
* 这意味着如果目标有 10% 的反击几率而此注释标签为 +50%那么目标有 60% 的反击几率
*
* Skill Notetags:
*
* <Evade Counter> 躲避后反击
* If this skill is being used as the counter skill, the battler will evade
* the current action and then counter.
* 如果此技能用作反击技能则战斗者在触发闪避效果后进行反击
*
* <Hit Counter> 伤害后反击
* If this skill is being used as the counter skill, the battler will take
* the hit against the current action and then counter.
* 如果此技能用作反击技能则战斗者在被命中后进行反击
*
* <Counter Name: text> 反击技能名
* This changes the displayed name of the skill when used as a counter skill
* to 'text'.
* 将当前技能用作反击技能时技能的显示名称更改为text
*
* <Counter Icon: x> 反击技能图标
* This changes the displayed icon of the skill when used as a counter skill
* to x icon.
* 将当前技能用作反击技能时技能的显示图标更改为x号图标
*
* ============================================================================
* Notetags - Counter Conditions
* ============================================================================
*
* When making your counter skills, you can have those counter skills respond
* only to specific conditions. If all conditions are met, the counter skill
* will occur. If a single condition isn't met, that counter skill will then be
* skipped and the next one will be checked. To add counter conditions, use the
* following notetags:
* 在制作反击技能时您可以让这些反击技能仅对特定条件做出反应
* 如果满足所有条件则会出现反击技能如果不满足单个条件则将跳过该反击技能
* 并检查下一个反击技能要添加反击条件请使用以下 notetags
* 设置反击条件
*
* Skill Notetags:
*
* <Counter Condition>
* condition
* condition
* </Counter Condition>
* Replace the 'condition' text in between the notetags with the listed in
* the conditions list below to best fit what you want.
* 将注释标签之间的条件文本替换为下面条件列表中列出的文本以最适合您的需求
*
* --- Example ---
*
* <Counter Condition>
* physical hit
* single target
* </Counter Condition>
* This skill will only be used as a counter skill if the current action is
* a physical hit that's single target.
* 仅当当前动作是单个目标的物理命中时此技能才会用作反击技能
*
* ============================================================================
* Counter Condition List
* ============================================================================
*
* Here is a list of all the counter conditions that come with this plugin that
* you can use. Keep in mind that all of the counter conditions must be met
* before a counter will take effect. If even a single counter condition fails
* to be met, the counter skill will not proc.
* 以下是您可以使用的此插件附带的所有反击条件的列表
* 请记住在反击生效之前必须满足所有反击条件
* 如果连一个反击条件都无法满足反击技能也不会触发
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ATTACKER param eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'param' with 'level', 'maxhp', 'hp', 'maxmp', 'mp', 'atk', 'def',
* 'mat', 'mdf', 'agi', or 'luk'. This will run a check against the attacker's
* parameter. If the check returns 'true', the counter condition is met. If it
* returns 'false', the counter condition isn't met.
* 'param' 替换为 'level''maxhp''hp''maxmp''mp''atk''def'
* 'mat''mdf''agi' 'luk'这将对攻击者的参数进行检查
* 如果检查返回true则满足反击条件如果返回false则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Attacker level > 50
* Attacker hp <= attacker.mhp * 0.50
* Attacker atk > defender.def
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* CERTAIN HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a certain hit, the counter
* condition is met. If it isn't, the counter condition isn't met.
* 如果当前对目标使用的操作是必定命中则满足反击条件如果不是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Certain Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* COUNTER HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a counter skill, the
* counter condition is met. If it isn't, the counter condition isn't met.
* 如果当前针对目标使用的动作是反击技能则满足反击条件否则则不满足反条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Counter Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* DEFENDER param eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Replace 'param' with 'level', 'maxhp', 'hp', 'maxmp', 'mp', 'atk', 'def',
* 'mat', 'mdf', 'agi', or 'luk'. This will run a check against the defender's
* parameter. If the check returns 'true', the counter condition is met. If it
* returns 'false', the counter condition isn't met.
* 参数替换为levelmaxhphpmaxmpmpatkdefmat
* mdfagiluk这将针对防御者的参数运行检查
* 如果检查返回true则满足反击条件如果它返回false则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Defender level > 50
* Defender hp <= defender.mhp * 0.50
* Defender atk > attacker.def
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ELEMENT: x
* ELEMENT: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target has element X attached to it,
* the counter condition is met. If it isn't, the counter condition isn't met.
* Replace 'x' with the element ID or the element name in the database system
* tab. If multiple elements share the same name, priority will be given to the
* element with the highest ID.
* 如果对目标使用的当前操作附加了伤害属性 X则满足反击条件如果不是
* 则不满足反击条件x替换为数据库系统选项卡中的伤害属性 ID 或伤害属性名称
* 如果多个伤害属性共享相同的名称则将优先考虑具有最高 ID 的伤害属性
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Element: 4
* Element: Fire
* Element: Ice
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* EVAL: code
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* For those with JavaScript experience, you can use the above line to perform
* an eval check to see if the conditions are met for the counter skill. If the
* eval check returns 'true', the condition is met. If it returns 'false', the
* condition isn't met.
* 对于那些有 JavaScript 经验的人您可以使用上面的行执行评估检查
* 以查看是否满足反击技能的条件如果评估检查返回true则满足条件
* 如果返回false则不满足条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Eval: attacker.name() === 'Harold'
* Eval: defender.hpRate() <= 0.50
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ITEM: x
* ITEM: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current aciton used against the target is item x, the counter
* condition is met. If it isn't, the counter condition isn't met. Replace 'x'
* with the item ID. If you choose to use the item name, and your database
* has multiple items with the same name, priority will be given to the item
* with the highest ID.
* 如果对目标使用的当前行动是物品 x则满足反击条件否则则不满足反条件
* x替换为商品 ID如果选择使用物品名称并且数据库中有多个具有相同名称的物品
* 则将优先考虑具有最高 ID 的物品
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Item: 30
* Item: Bomb
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* MAGICAL HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a magical hit, the counter
* condition is met. If it isn't, the counter condition isn't met.
* 如果当前对目标使用的操作是魔法命中则满足计数条件如果不是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Magical Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* MULTI TARGET
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a multi target action, the
* counter condition is met. If it isn't, the counter condition isn't met.
* 如果对目标使用的当前行动是多目标行动则满足反击条件如果不是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Multi Target
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT CERTAIN HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is NOT certain hit, the
* counter condition is met. If it is, the counter condition isn't met.
* 如果对目标使用的当前操作不是必定命中则满足反击条件如果是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Certain Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT COUNTER HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is NOT a counter skill, the
* counter condition is met. If it is, the counter condition isn't met.
* 如果当前对目标使用的操作不是反技能则满足反技能如果是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Counter Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT ELEMENT: x
* NOT ELEMENT: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target has element X attached to it,
* the counter condition is NOT met. If it isn't, the counter condition is met.
* Replace 'x' with the element ID or the element name in the database system
* tab. If multiple elements share the same name, priority will be given to the
* element with the highest ID.
* 如果对目标使用的当前操作附加了伤害属性 X则不满足反击条件
* 如果不是则满足反击条件x替换为数据库系统选项卡中的伤害属性 ID 或伤害属性名称
* 如果多个伤害属性共享相同的名称则将优先考虑具有最高 ID 的伤害属性
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Element: 4
* Not Element: Fire
* Not Element: Ice
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT ITEM: x
* NOT ITEM: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current aciton used against the target is NOT item x, the counter
* condition is met. If it is, the counter condition isn't met. Replace 'x'
* with the item ID. If you choose to use the item name, and your database
* has multiple items with the same name, priority will be given to the item
* with the highest ID.
* 如果当前用于目标的行动不是物品 x则满足反击条件
* 如果是则不满足反击条件x替换为物品 ID
* 如果选择使用物品名称并且数据库包含多个同名物品则将优先考虑具有最高 ID 的物品
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Item: 30
* Not Item: Bomb
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT MAGICAL HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is NOT a magical hit, the
* counter condition is met. If it is, the counter condition isn't met.
* 如果当前对目标的动作不是魔法命中则满足反击条件如果是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Magical Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT PHYSICAL HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is NOT a physical hit, the
* counter condition is met. If it is, the counter condition isn't met.
* 如果当前对目标的动作不是物理命中则满足反击条件如果是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Physical Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT SKILL: x
* NOT SKILL: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current aciton used against the target is NOT skill x, the counter
* condition is met. If it is, the counter condition isn't met. Replace 'x'
* with the skill ID. If you choose to use the skill name, and your database
* has multiple skills with the same name, priority will be given to the skill
* with the highest ID.
* 如果当前用于对付目标的动作不是技能 x则满足反击条件如果是则不满足反条件
* x替换为技能 ID如果您选择使用技能名称并且您的数据库有多个同名的技能
* 则将优先考虑具有最高 ID 的技能
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Skill: 50
* Not Skill: Firaga
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* NOT STYPE: x
* NOT STYPE: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is NOT a skill and skill type
* x, the counter condition is met. If it isn't the counter condition isn't
* met. Replace 'x' with the Skill Type ID. If you choose to use the skill type
* name and your database has multiple skill types with the same name, priority
* will be given to the skill type with the highest ID.
* 如果当前针对目标使用的动作不是技能或不属于技能类型 x则满足反击条件
* 如果不是则不满足反击条件x替换为技能类型 ID
* 如果选择使用技能类型名称并且数据库中有多个同名的技能类型
* 则将优先考虑 ID 最高的技能类型
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Not Stype: 1
* Not Stype: Magic
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* PHYSICAL HIT
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a physical hit, the counter
* condition is met. If it isn't, the counter condition isn't met.
* 如果当前对目标的动作是物理命中则满足反击条件如果不是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Physical Hit
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* RANDOM: x%
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This will run a random check. There is a x% chance that this counter check
* will pass. If it passes, the counter condition is met. If it doesn't, the
* counter condition isn't met.
* 这将运行随机检查此反击检查有 x% 的机会通过
* 如果通过则满足反击条件如果不满足则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Random: 30%
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* SINGLE TARGET
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a single target action, the
* counter condition is met. If it isn't, the counter condition isn't met.
* 如果对目标使用的当前行动是单一目标行动则满足反击条件
* 如果不是则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Single Target
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* SKILL: x
* SKILL: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current aciton used against the target is skill x, the counter
* condition is met. If it isn't, the counter condition isn't met. Replace 'x'
* with the skill ID. If you choose to use the skill name, and your database
* has multiple skills with the same name, priority will be given to the skill
* with the highest ID.
* 如果当前用于对付目标的动作是技能 x则满足反击条件如果不是则不满足反条件
* x替换为技能 ID如果您选择使用技能名称并且您的数据库有多个同名的技能
* 则将优先考虑具有最高 ID 的技能
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Skill: 50
* Skill: Firaga
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* STYPE: x
* STYPE: name
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If the current action used against the target is a skill and skill type x,
* the counter condition is met. If it isn't the counter condition isn't met.
* Replace 'x' with the Skill Type ID. If you choose to use the skill type name
* and your database has multiple skill types with the same name, priority will
* be given to the skill type with the highest ID.
* 如果当前针对目标使用的动作是技能和技能类型 x则满足反击条件
* 如果不是则不满足反击条件x替换为技能类型 ID
* 如果选择使用技能类型名称并且数据库中有多个同名的技能类型
* 则将优先考虑 ID 最高的技能类型
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Stype: 1
* Stype: Magic
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* SWITCH x OFF
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If switch x is OFF (false) prior to the current action being used against
* the target, the counter condition is met. If it is ON (true), the counter
* condition isn't met.
* 如果开关 x 在对目标使用当前操作之前处于 OFF false
* 则满足反击条件如果为 ON true则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Switch 10 Off
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* SWITCH x ON
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* If switch x is ON (ftrue) prior to the current action being used against
* the target, the counter condition is met. If it is OFF (false), the counter
* condition isn't met.
* 如果开关 x 在对目标使用当前操作之前处于 ON true
* 则满足反击条件如果为 OFF false则不满足反击条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Switch 10 On
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* VARIABLE x eval
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* This runs an eval check against variable x. If the eval check returns 'true'
* the condition is met. If it returns 'false' then the condition isn't met.
* 这将对变量 x 运行评估检查如果评估检查返回true则满足条件
* 如果它返回false则不满足条件
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Example: Variable 15 >= 15
* Variable 16 <= 20
* Variable 17 === $gameParty.aliveMembers().length
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
*
* ============================================================================
* Lunatic Mode - Custom Counter Skills
* ============================================================================
*
* For those with JavaScript proficiency, you can use the following Lunatic
* Mode notetags to give a dynamic set of skills granted for counter usage.
* 对于那些精通 JavaScript 的人您可以使用以下 Lunatic Mode 注释标签来提供
* 一组动态技能以授予反击使用
*
* Actor, Class, Enemy, Weapon, Armor, and State Notetags:
*
* <Custom Counter Skills>
* if (user.name() === 'Harold') {
* skills.push(50, 51, 52);
* } else if (user.name() === 'Therese') {
* skills.push(53, 54, 55);
* } else if (user.name() === 'Marsha') {
* skills.push(56, 57, 58);
* } else if (user.name() === 'Lucius') {
* skills.push(59, 60, 61);
* }
* </Custom Counter Skills>
* The 'skills' variable is an array that will contain all the counter skills
* that will be added to the list of potential skills the battler can counter
* actions with provided that their requirements are met.
* Skills变量是一个数组其中包含所有反击技能
* 这些技能将被添加到战斗者可以反击的潜在技能列表中前提是满足其要求
*
* ============================================================================
* Lunatic Mode - Custom Counter Total
* ============================================================================
*
* For those with JavaScript proficiency, you can use the following Lunatic
* Mode notetags to give a dynamic counter total bonus:
* 对于那些精通JavaScript的人您可以使用以下疯狂模式笔记标签来提供动态反击次数奖励
*
* Actor, Class, Enemy, Weapon, Armor, and State Notetags:
*
* <Custom Counter Total>
* value = user.level;
* </Custom Counter Total>
* The 'value' variable is the total amount of counters is increased or
* decreased by. If the total counter value reaches 0 or less than 0 for the
* battler, the battler is unable to use counter skills.
* value变量是反击次数总数增加或减少如果战斗者的总反击次数达到 0 或小于 0
* 则战斗者无法使用战斗技能
*
*
* ============================================================================
* Lunatic Mode - Custom Target Counter Rate
* ============================================================================
*
* For those with JavaScript proficiency, you can use the following Lunatic
* Mode notetags to make the attacker's traits alter the target's CNT rate.
* 对于那些精通JavaScript的人您可以使用以下疯狂模式笔记标签来使攻击者的特征
* 改变目标的反击率
*
* Actor, Class, Enemy, Weapon, Armor, and State Notetags:
*
* <Custom Target Counter Rate>
* rate -= user.hpRate();
* </Custom Target Counter Rate>
* The 'rate' variable is the final rate used to determine the counter rate
* the target has. It is already given the value calculated from the target's
* CNT value. This is calculated before the skill's custom counter rate.
* 反击率变量是用于确定目标的反击利率的最终利率
* 它已经被赋予了根据目标反击率值计算得出的值
* 这是在技能的自定义反击率之前计算的
*
* ============================================================================
* Lunatic Mode - Custom Counter Rates
* ============================================================================
*
* For those with JavaScript proficiency, you can use the following Lunatic
* Mode notetags to give skills a dynamic chance for the target to counter.
*
* Skill and Item Notetags:
*
* <Custom Counter Rate>
* rate += target.hpRate();
* </Custom Counter Rate>
* The 'rate' variable is the final rate used to determine the counter rate
* the target has. It is already given the value calculated from the target's
* CNT value plus any additional counter rate modifiers from the skill. This
* is calculated after the attacker's custom target counter rate.
* rate变量是用于确定目标反击率的最终几率它已经给出了根据目标的 CNT
* 加上技能中的任何其他反击率修饰符计算的值
* 这是在攻击者的自定义目标反击率之后计算的
*
* ============================================================================
* Lunatic Mode - Custom Counter Condition
* ============================================================================
*
* For those with JavaScript proficiency, you can use the following Luantic
* Mode notetags to give counter skills a custom counter condition. While you
* can do the same with an Eval condition, this notetag is for those who prefer
* to take control over everything at once.
* 对于精通 JavaScript 的人您可以使用以下 Luantic 模式笔记标签为反击技能
* 提供自定义反击条件虽然您可以对 Eval 条件执行相同的操作
* 但此 notetag 适用于那些喜欢一次控制所有内容的人
*
* Skill Notetags:
*
* <Custom Counter Condition>
* if (attacker.name() === 'Harold') {
* condition = true;
* } else if (defender.name() === 'Therese') {
* condition = true;
* } else {
* condition = false;
* }
* </Custom Counter Condition>
* The 'condition' variable determines whether or not the counter skill will
* pass or fail. If the 'condition' variable returns 'true', the condition is
* met. If the 'condition' variable returns 'false', the condition fails to
* be met. Once the condition is met, the rest of the <Counter Condition>
* conditions will be checked.
* condition变量确定反击技能是通过还是失败
* 如果condition变量返回true则满足反击条件
* 如果condition变量返回false则无法满足反击条件
* 满足当前反击条件后将检查其余的<反击条件>条件
*
* ============================================================================
* Changelog
* ============================================================================
*
* Version 1.07:
* - Lunatic Mode fail safes added.
*
* Version 1.06:
* - Updated for RPG Maker MV version 1.3.2.
*
* Version 1.05:
* - Fixed a bug that caused the Eval: condition to not work and crash.
* - Fixed an issue that caused default counter attacks to trigger upon magical
* actions.
*
* Version 1.04:
* - Fixed a bug that caused counter-countered actions to no longer disappear
* from queue.
*
* Version 1.03:
* - Fixed a bug that caused enemies to get a free action after a counter in
* the DTB engine.
*
* Version 1.02:
* - Fixed a bug that didn't replace the proper skill for the countered battler
* appropriate causing some action effects to not proc correctly.
*
* Version 1.01:
* - Fixed a bug that caused the <Counter Skills: 0> notetag to not work.
*
* Version 1.00:
* - Finished Plugin!
*/
//=============================================================================
if (Imported.YEP_BattleEngineCore) {
//=============================================================================
// Parameter Variables
//=============================================================================
Yanfly.Parameters = PluginManager.parameters("YEP_X_CounterControl");
Yanfly.Param = Yanfly.Param || {};
Yanfly.Param.CounterMaxQueue = Number(Yanfly.Parameters["Queue Max"]);
Yanfly.Param.CounterDefault = Number(Yanfly.Parameters["Counter Skill"]);
Yanfly.Param.CounterEvade = eval(String(Yanfly.Parameters["Evade Counter"]));
Yanfly.Param.CounterFmt = String(Yanfly.Parameters["Counter Name"]);
Yanfly.Param.CounterIcon = Number(Yanfly.Parameters["Counter Icon"]);
Yanfly.Param.CounterTotal = Number(Yanfly.Parameters["Counter Total"]);
Yanfly.Param.CounterAllyCnt = eval(String(Yanfly.Parameters["Ally Counter"]));
Yanfly.Param.CounterConditions = [];
if (eval(String(Yanfly.Parameters["Physical"]))) {
Yanfly.Param.CounterConditions.push("PHYSICAL HIT");
}
if (eval(String(Yanfly.Parameters["Single Target"]))) {
Yanfly.Param.CounterConditions.push("SINGLE TARGET");
}
if (eval(String(Yanfly.Parameters["Not Counter"]))) {
Yanfly.Param.CounterConditions.push("NOT COUNTER HIT");
}
//=============================================================================
// DataManager
//=============================================================================
Yanfly.Counter.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function () {
if (!Yanfly.Counter.DataManager_isDatabaseLoaded.call(this)) return false;
if (!Yanfly._loaded_YEP_X_CounterControl) {
this.processCounterNotetagsI($dataItems);
this.processCounterNotetagsW($dataWeapons);
this.processCounterNotetagsA($dataArmors);
this.processCounterNotetagsS($dataSkills);
this.processCounterNotetagsT($dataStates);
this.processCounterNotetagsSys($dataSystem);
this.processCounterNotetags1($dataActors);
this.processCounterNotetags1($dataEnemies);
this.processCounterNotetags2($dataActors);
this.processCounterNotetags2($dataClasses);
this.processCounterNotetags2($dataEnemies);
this.processCounterNotetags2($dataWeapons);
this.processCounterNotetags2($dataArmors);
this.processCounterNotetags2($dataStates);
this.processCounterNotetags3($dataSkills);
this.processCounterNotetags4($dataSkills);
this.processCounterNotetags4($dataItems);
Yanfly._loaded_YEP_X_CounterControl = true;
}
return true;
};
DataManager.processCounterNotetagsI = function (group) {
if (Yanfly.ItemIdRef) return;
Yanfly.ItemIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.ItemIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCounterNotetagsW = function (group) {
if (Yanfly.WeaponIdRef) return;
Yanfly.WeaponIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.WeaponIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCounterNotetagsA = function (group) {
if (Yanfly.ArmorIdRef) return;
Yanfly.ArmorIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.ArmorIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCounterNotetagsS = function (group) {
if (Yanfly.SkillIdRef) return;
Yanfly.SkillIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.SkillIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCounterNotetagsT = function (group) {
if (Yanfly.StateIdRef) return;
Yanfly.StateIdRef = {};
for (var n = 1; n < group.length; n++) {
var obj = group[n];
if (obj.name.length <= 0) continue;
Yanfly.StateIdRef[obj.name.toUpperCase()] = n;
}
};
DataManager.processCounterNotetagsSys = function (group) {
Yanfly.STypeIdRef = {};
for (var i = 1; i < group.skillTypes.length; ++i) {
var name = group.skillTypes[i].toUpperCase();
name = name.replace(/\\I\[(\d+)\]/gi, "");
Yanfly.STypeIdRef[name] = i;
}
Yanfly.ElementIdRef = {};
for (var i = 1; i < group.elements.length; ++i) {
var name = group.elements[i].toUpperCase();
name = name.replace(/\\I\[(\d+)\]/gi, "");
Yanfly.ElementIdRef[name] = i;
}
};
DataManager.processCounterNotetags1 = function (group) {
for (var n = 1; n < group.length; n++) {
var obj = group[n];
var notedata = obj.note.split(/[\r\n]+/);
obj.defaultCounter = Yanfly.Param.CounterDefault;
obj.counterTotal = Yanfly.Param.CounterTotal;
for (var i = 0; i < notedata.length; i++) {
var line = notedata[i];
if (line.match(/<DEFAULT COUNTER:[ ](\d+)>/i)) {
obj.defaultCounter = parseInt(RegExp.$1);
} else if (line.match(/<DEFAULT COUNTER:[ ](.*)>/i)) {
var name = String(RegExp.$1).toUpperCase();
var id = Yanfly.SkillIdRef[name];
if (id) obj.defaultCounter = id;
}
}
}
};
DataManager.processCounterNotetags2 = function (group) {
var noteA1 = /<(?:COUNTER SKILLS):[ ]*(\d+(?:\s*,\s*\d+)*)>/i;
var noteA2 = /<(?:COUNTER SKILLS):[ ](\d+)[ ](?:THROUGH|to)[ ](\d+)>/i;
for (var n = 1; n < group.length; n++) {
var obj = group[n];
var notedata = obj.note.split(/[\r\n]+/);
obj.counterSkills = [];
obj.counterTotal = 0;
obj.targetCounterRate = 1;
obj.targetCounterFlat = 0;
obj.evadeCounter = false;
obj.hitCounter = false;
var evalMode = "none";
obj.counterTotalEval = "";
obj.counterSkillsEval = "";
obj.targetCounterRateEval = "";
for (var i = 0; i < notedata.length; i++) {
var line = notedata[i];
if (line.match(noteA1)) {
var array = JSON.parse("[" + RegExp.$1.match(/\d+/g) + "]");
obj.counterSkills = obj.counterSkills.concat(array);
} else if (line.match(noteA2)) {
var range = Yanfly.Util.getRange(parseInt(RegExp.$1), parseInt(RegExp.$2));
obj.counterSkills = obj.counterSkills.concat(range);
} else if (line.match(/<(?:COUNTER SKILL):[ ](.*)>/i)) {
var name = String(RegExp.$1).toUpperCase();
var id = Yanfly.SkillIdRef[name];
if (id) obj.counterSkills.push(id);
} else if (line.match(/<(?:COUNTER TOTAL):[ ]([\+\-]\d+)>/i)) {
obj.counterTotal = parseInt(RegExp.$1);
} else if (line.match(/<(?:TARGET COUNTER):[ ](\d+)([%])>/i)) {
obj.targetCounterRate = parseFloat(RegExp.$1) * 0.01;
} else if (line.match(/<(?:TARGET COUNTER):[ ]([\+\-]\d+)([%])>/i)) {
obj.targetCounterFlat = parseFloat(RegExp.$1) * 0.01;
} else if (line.match(/<(?:EVADE COUNTER|COUNTER EVADE)>/i)) {
obj.evadeCounter = true;
} else if (line.match(/<(?:HIT COUNTER|COUNTER HIT)>/i)) {
obj.hitCounter = true;
} else if (line.match(/<CUSTOM COUNTER TOTAL>/i)) {
evalMode = "custom counter total";
} else if (line.match(/<\/CUSTOM COUNTER TOTAL>/i)) {
evalMode = "none";
} else if (evalMode === "custom counter total") {
obj.counterTotalEval = obj.counterTotalEval + line + "\n";
} else if (line.match(/<CUSTOM COUNTER SKILLS>/i)) {
evalMode = "custom counter skills";
} else if (line.match(/<\/CUSTOM COUNTER SKILLS>/i)) {
evalMode = "none";
} else if (evalMode === "custom counter skills") {
obj.counterSkillsEval = obj.counterSkillsEval + line + "\n";
} else if (line.match(/<CUSTOM TARGET COUNTER RATE>/i)) {
evalMode = "custom target counter rate";
} else if (line.match(/<\/CUSTOM TARGET COUNTER RATE>/i)) {
evalMode = "none";
} else if (evalMode === "custom target counter rate") {
obj.targetCounterRateEval = obj.targetCounterRateEval + line + "\n";
}
}
}
};
DataManager.processCounterNotetags3 = function (group) {
for (var n = 1; n < group.length; n++) {
var obj = group[n];
var notedata = obj.note.split(/[\r\n]+/);
obj.evadeCounter = Yanfly.Param.CounterEvade;
obj.counterName = Yanfly.Param.CounterFmt.format(obj.name);
obj.counterIcon = Yanfly.Param.CounterIcon || obj.iconIndex;
obj.cannotCounter = false;
var evalMode = "none";
obj.counterConditions = Yanfly.Param.CounterConditions.slice();
obj.counterConditionEval = "";
for (var i = 0; i < notedata.length; i++) {
var line = notedata[i];
if (line.match(/<(?:EVADE COUNTER|COUNTER EVADE)>/i)) {
obj.evadeCounter = true;
} else if (line.match(/<(?:HIT COUNTER|COUNTER HIT)>/i)) {
obj.evadeCounter = false;
} else if (line.match(/<(?:COUNTER NAME):[ ](.*)>/i)) {
obj.counterName = String(RegExp.$1);
} else if (line.match(/<(?:COUNTER ICON):[ ](\d+)>/i)) {
obj.counterIcon = String(RegExp.$1);
} else if (line.match(/<CANNOT COUNTER>/i)) {
obj.cannotCounter = true;
} else if (line.match(/<(?:COUNTER CONDITION|COUNTER CONDITIONS)>/i)) {
evalMode = "counter condition";
obj.counterConditions = [];
} else if (line.match(/<\/(?:COUNTER CONDITION|COUNTER CONDITIONS)>/i)) {
evalMode = "none";
} else if (evalMode === "counter condition") {
obj.counterConditions.push(line);
} else if (line.match(/<CUSTOM COUNTER CONDITION>/i)) {
evalMode = "custom counter condition";
} else if (line.match(/<\/CUSTOM COUNTER CONDITION>/i)) {
evalMode = "none";
} else if (evalMode === "custom counter condition") {
obj.counterConditionEval = obj.counterConditionEval + line + "\n";
}
}
}
};
DataManager.processCounterNotetags4 = function (group) {
for (var n = 1; n < group.length; n++) {
var obj = group[n];
var notedata = obj.note.split(/[\r\n]+/);
obj.allyCounter = Yanfly.Param.CounterAllyCnt;
obj.cannotCounter = false;
obj.counterRate = 1;
obj.counterMod = 0;
var evalMode = "none";
obj.counterRateEval = "";
for (var i = 0; i < notedata.length; i++) {
var line = notedata[i];
if (line.match(/<ALLY COUNTER>/i)) {
obj.allyCounter = true;
} else if (line.match(/<ALLY CANNOT COUNTER>/i)) {
obj.allyCounter = false;
} else if (line.match(/<CANNOT COUNTER>/i)) {
obj.cannotCounter = true;
} else if (line.match(/<COUNTER RATE:[ ](\d+)([%])>/i)) {
obj.counterRate = parseFloat(RegExp.$1) * 0.01;
} else if (line.match(/<COUNTER RATE:[ ]([\+\-]\d+)([%])>/i)) {
obj.counterMod = parseFloat(RegExp.$1) * 0.01;
} else if (line.match(/<CUSTOM COUNTER RATE>/i)) {
evalMode = "custom counter rate";
} else if (line.match(/<\/CUSTOM COUNTER RATE>/i)) {
evalMode = "none";
} else if (evalMode === "custom counter rate") {
obj.counterRateEval = obj.counterRateEval + line + "\n";
}
}
}
};
//=============================================================================
// BattleManager
//=============================================================================
Yanfly.Counter.BattleManager_initMembers = BattleManager.initMembers;
BattleManager.initMembers = function () {
Yanfly.Counter.BattleManager_initMembers.call(this);
this._counterQueue = [];
this._counterSequence = 0;
this._counterOriginalSubject = undefined;
this._counterOriginalAction = undefined;
this._countering = false;
};
BattleManager.isCountering = function () {
return this._countering;
};
Yanfly.Counter.BattleManager_invokeCounter = BattleManager.invokeCounterAttack;
BattleManager.invokeCounterAttack = function (subject, target) {
this._counterQueue = this._counterQueue || [];
if (this.isValidCounterAction(target)) this._counterSequence += 1;
if (!this.isMaxCounterQueue()) {
if (this.isValidCounterAction(target)) target.payCounter();
}
if (target.canCounter()) {
this._counterSkill = this.getCounterSkill(subject, target);
this._counterQueue = this._counterQueue || [];
if (this._counterSkill === null) {
if (this._action.isPhysical() && target.canMove()) {
Yanfly.Counter.BattleManager_invokeCounter.call(this, subject, target);
} else {
this.invokeNormalAction(subject, target);
}
return;
} else if (this.evadeAndCounter(subject, target)) {
target.performEvasion();
target.forceEvadePopup();
this.addCounterQueue(subject, target);
} else if (this._counterSkill !== undefined) {
this.invokeNormalAction(subject, target);
this.addCounterQueue(subject, target);
} else {
if (this.isValidCounterAction(target)) {
target.payCounter(-1);
this._counterSequence -= 1;
}
this.invokeNormalAction(subject, target);
return;
}
this._logWindow.displayActionResults(target, subject);
if (subject.isDead()) subject.performCollapse();
} else {
this.invokeNormalAction(subject, target);
}
};
BattleManager.getCounterSkill = function (subject, target) {
target.makeCounterSkills();
var skills = target.counterSkills();
var length = skills.length;
for (var i = 0; i < length; ++i) {
var skill = skills[i];
if (this.meetCounterConditions(skill, subject, target)) return skill;
}
return undefined;
};
BattleManager.meetCounterConditions = function (skill, subject, target) {
if (skill === null) return true;
if (!target.canUse(skill)) return false;
if (!this.meetCounterConditionsEval(skill, subject, target));
var condition = this.getCounterCondition(skill, subject, target);
return condition;
};
BattleManager.meetCounterConditionsEval = function (skill, subject, target) {
var action = this._action;
if (this._action.item().counterConditionEval === "") return true;
var condition = true;
var a = subject;
var user = subject;
var attacker = subject;
var b = target;
var defender = target;
var item = skill;
var s = $gameSwitches._data;
var v = $gameVariables._data;
var code = this._action.item().counterConditionEval;
try {
eval(code);
} catch (e) {
Yanfly.Util.displayError(e, code, "COUNTER CONDITIONS EVAL ERROR");
}
return condition;
};
BattleManager.getCounterCondition = function (skill, subject, target) {
var conditions = skill.counterConditions;
var length = conditions.length;
for (var i = 0; i < length; ++i) {
var line = conditions[i];
if (!this.checkCounterLine(line, skill, subject, target)) return false;
}
return true;
};
BattleManager.checkCounterLine = function (line, skill, subject, target) {
// EVAL
if (line.match(/EVAL:[ ](.*)/i)) {
var value = String(RegExp.$1);
return this.checkCounterEval(value, skill, subject, target);
// CERTAIN HIT
} else if (line.toUpperCase() === "CERTAIN HIT") {
return this.checkCounterHitType(Game_Action.HITTYPE_CERTAIN);
// PHYSICAL HIT
} else if (line.toUpperCase() === "PHYSICAL HIT") {
return this.checkCounterHitType(Game_Action.HITTYPE_PHYSICAL);
// MAGICAL HIT
} else if (line.toUpperCase() === "MAGICAL HIT") {
return this.checkCounterHitType(Game_Action.HITTYPE_MAGICAL);
// NOT CERTAIN HIT
} else if (line.toUpperCase() === "NOT CERTAIN HIT") {
return !this.checkCounterHitType(Game_Action.HITTYPE_CERTAIN);
// NOT PHYSICAL HIT
} else if (line.toUpperCase() === "NOT PHYSICAL HIT") {
return !this.checkCounterHitType(Game_Action.HITTYPE_PHYSICAL);
// NOT MAGICAL HIT
} else if (line.toUpperCase() === "NOT MAGICAL HIT") {
return !this.checkCounterHitType(Game_Action.HITTYPE_MAGICAL);
// SINGLE TARGET
} else if (line.toUpperCase() === "SINGLE TARGET") {
return this.checkCounterSingleTarget();
// MULTI TARGET
} else if (line.toUpperCase() === "MULTI TARGET") {
return !this.checkCounterSingleTarget();
// COUNTER HIT
} else if (line.toUpperCase() === "COUNTER HIT") {
return !this.checkCounterCounterHit();
// NOT COUNTER HIT
} else if (line.toUpperCase() === "NOT COUNTER HIT") {
return !this.checkCounterCounterHit();
// RANDOM
} else if (line.match(/RANDOM:[ ](\d+)([%])/i)) {
var value = parseFloat(RegExp.$1) * 0.01;
return !this.checkCounterRandom(value);
// NOT ELEMENT
} else if (line.match(/NOT ELEMENT:[ ](.*)/i)) {
var value = String(RegExp.$1);
return !this.checkCounterElement(value);
// ELEMENT
} else if (line.match(/ELEMENT:[ ](.*)/i)) {
var value = String(RegExp.$1);
return this.checkCounterElement(value);
// SWITCH ON
} else if (line.match(/SWITCH[ ](\d+)[ ]ON/i)) {
var value = parseInt(RegExp.$1);
return this.checkCounterSwitch(value);
// SWITCH OFF
} else if (line.match(/SWITCH[ ](\d+)[ ]OFF/i)) {
var value = parseInt(RegExp.$1);
return !this.checkCounterSwitch(value);
// VARIABLE
} else if (line.match(/VARIABLE[ ](\d+)[ ](.*)/i)) {
var varId = parseInt(RegExp.$1);
var eval = String(RegExp.$2);
eval = "$gameVariables.value(" + varId + ") " + eval;
return this.checkCounterEval(eval, skill, subject, target);
// NOT SKILL
} else if (line.match(/NOT SKILL:[ ](.*)/i)) {
var value = String(RegExp.$1);
return !this.checkCounterSkill(value);
// SKILL
} else if (line.match(/SKILL:[ ](.*)/i)) {
var value = String(RegExp.$1);
return this.checkCounterSkill(value);
// NOT STYPE
} else if (line.match(/NOT STYPE:[ ](.*)/i)) {
var value = String(RegExp.$1);
return !this.checkCounterStype(value);
// STYPE
} else if (line.match(/STYPE:[ ](.*)/i)) {
var value = String(RegExp.$1);
return this.checkCounterStype(value);
// NOT ITEM
} else if (line.match(/NOT ITEM:[ ](.*)/i)) {
var value = String(RegExp.$1);
return !this.checkCounterItem(value);
// ITEM
} else if (line.match(/ITEM:[ ](.*)/i)) {
var value = String(RegExp.$1);
return this.checkCounterItem(value);
// ATTACKER PARAM
} else if (line.match(/ATTACKER[ ](.*)[ ](.*)/i)) {
var value1 = String(RegExp.$1);
var value2 = String(RegExp.$1);
return this.checkCounterAttacker(value1, value2, skill, subject, target);
// DEFENDER PARAM
} else if (line.match(/DEFENDER[ ](.*)[ ](.*)/i)) {
var value1 = String(RegExp.$1);
var value2 = String(RegExp.$1);
return this.checkCounterDefender(value1, value2, skill, subject, target);
// ELSE - NOTHING LISTED
} else {
return true;
}
};
BattleManager.checkCounterEval = function (code, skill, subject, target) {
var action = this._action;
var a = subject;
var user = subject;
var attacker = subject;
var b = target;
var defender = target;
var item = skill;
var s = $gameSwitches._data;
var v = $gameVariables._data;
var code = line;
try {
return eval(code);
} catch (e) {
Yanfly.Util.displayError(e, code, "COUNTER CHECK ERROR");
return false;
}
};
BattleManager.checkCounterHitType = function (value) {
return this._action.item().hitType === value;
};
BattleManager.checkCounterCounterHit = function () {
return this._action.isCounter();
};
BattleManager.checkCounterRandom = function (value) {
return Math.random() < value;
};
BattleManager.checkCounterSingleTarget = function () {
return this._action.isForOne();
};
BattleManager.checkCounterElement = function (value) {
if (value.match(/(\d+)/i)) {
var elementId = parseInt(RegExp.$1);
} else {
var elementId = Yanfly.ElementIdRef[value.toUpperCase()];
if (!elementId) return true;
}
var actionElement = this._action.item().damage.elementId;
if (actionElement < 0) {
return this._subject.attackElements().contains(elementId);
} else {
return elementId === actionElement;
}
};
BattleManager.checkCounterSwitch = function (value) {
return $gameSwitches.value(value);
};
BattleManager.checkCounterSkill = function (value) {
if (!this._action.isSkill()) return false;
if (value.match(/(\d+)/i)) {
var skillId = parseInt(RegExp.$1);
} else {
var skillId = Yanfly.SkillIdRef[value.toUpperCase()];
}
var skill = $dataSkills[skillId];
return this._action.item() === skill;
};
BattleManager.checkCounterStype = function (value) {
if (!this._action.isSkill()) return false;
if (value.match(/(\d+)/i)) {
var stypeId = parseInt(RegExp.$1);
} else {
var stypeId = Yanfly.STypeIdRef[value.toUpperCase()];
}
var skill = this._action.item();
return skill.stypeId === stypeId;
};
BattleManager.checkCounterItem = function (value) {
if (!this._action.isItem()) return false;
if (value.match(/(\d+)/i)) {
var itemId = parseInt(RegExp.$1);
} else {
var itemId = Yanfly.SkillIdRef[value.toUpperCase()];
}
var skill = $dataSkills[skillId];
return this._action.item() === skill;
};
BattleManager.checkCounterAttacker = function (v1, v2, skill, subject, target) {
var eval = "subject.";
if (["LEVEL", "LV", "LVL"].contains(v1.toUpperCase())) {
eval += "level";
} else if (["MAX HP", "MAXHP", "MHP"].contains(v1.toUpperCase())) {
eval += "mhp";
} else if (["HP", "CURRENT HP"].contains(v1.toUpperCase())) {
eval += "hp";
} else if (["MAX MP", "MAXMP", "MMP"].contains(v1.toUpperCase())) {
eval += "mmp";
} else if (["MP", "CURRENT MP"].contains(v1.toUpperCase())) {
eval += "mp";
} else if (["ATK", "STR"].contains(v1.toUpperCase())) {
eval += "atk";
} else if (["DEF"].contains(v1.toUpperCase())) {
eval += "def";
} else if (["MAT", "INT", "SPI"].contains(v1.toUpperCase())) {
eval += "mat";
} else if (["MDF", "RES"].contains(v1.toUpperCase())) {
eval += "mdf";
} else if (["AGI", "SPD"].contains(v1.toUpperCase())) {
eval += "agi";
} else if (["LUK"].contains(v1.toUpperCase())) {
eval += "luk";
} else {
return false;
}
eval += " " + v2;
return this.checkCounterEval(eval, skill, subject, target);
};
BattleManager.checkCounterDefender = function (v1, v2, skill, subject, target) {
var eval = "target.";
if (["LEVEL", "LV", "LVL"].contains(v1.toUpperCase())) {
eval += "level";
} else if (["MAX HP", "MAXHP", "MHP"].contains(v1.toUpperCase())) {
eval += "mhp";
} else if (["HP", "CURRENT HP"].contains(v1.toUpperCase())) {
eval += "hp";
} else if (["MAX MP", "MAXMP", "MMP"].contains(v1.toUpperCase())) {
eval += "mmp";
} else if (["MP", "CURRENT MP"].contains(v1.toUpperCase())) {
eval += "mp";
} else if (["ATK", "STR"].contains(v1.toUpperCase())) {
eval += "atk";
} else if (["DEF"].contains(v1.toUpperCase())) {
eval += "def";
} else if (["MAT", "INT", "SPI"].contains(v1.toUpperCase())) {
eval += "mat";
} else if (["MDF", "RES"].contains(v1.toUpperCase())) {
eval += "mdf";
} else if (["AGI", "SPD"].contains(v1.toUpperCase())) {
eval += "agi";
} else if (["LUK"].contains(v1.toUpperCase())) {
eval += "luk";
} else {
return false;
}
eval += " " + v2;
return this.checkCounterEval(eval, skill, subject, target);
};
BattleManager.evadeAndCounter = function (subject, target) {
if (this._counterSkill === undefined) return false;
if (this._counterSkill === null) return false;
if (target.forceHitCounter()) return false;
if (target.forceEvadeCounter()) return true;
return this._counterSkill.evadeCounter;
};
BattleManager.isValidCounterAction = function (target) {
if (this._counterQueue.length <= 0) return true;
return this._counterQueue[0].subject() !== target;
};
BattleManager.addCounterQueue = function (subject, target) {
if (!target.canCounter()) return;
if (!this.isValidCounterAction(target)) return;
var action = new Game_Action(target);
action.setSkill(this._counterSkill.id);
action.setCounter();
if (action.isForOpponent()) {
action.setTarget(subject.index());
} else {
action.setTarget(target.index());
}
this._counterQueue = this._counterQueue || [];
this._counterQueue.push(action);
this._counterOriginalSubject = this._counterOriginalSubject || subject;
this._counterOriginalAction = this._counterOriginalAction || this._action;
};
Yanfly.Counter.BattleManager_createFinishActions = BattleManager.createFinishActions;
BattleManager.createFinishActions = function () {
Yanfly.Counter.BattleManager_createFinishActions.call(this);
this._actionList.push(["START COUNTER PHASE"]);
};
Yanfly.Counter.BattleManager_processActionSequence = BattleManager.processActionSequence;
BattleManager.processActionSequence = function (actionName, actionArgs) {
// START COUNTER PHASE
if (actionName === "START COUNTER PHASE") {
return this.actionStartCounterPhase();
}
return Yanfly.Counter.BattleManager_processActionSequence.call(this, actionName, actionArgs);
};
BattleManager.isMaxCounterQueue = function () {
return this._counterSequence > Yanfly.Param.CounterMaxQueue;
};
BattleManager.actionStartCounterPhase = function () {
this._counterQueue = this._counterQueue || [];
var action = this._counterQueue.shift();
if (this.isMaxCounterQueue() || !action) {
this.actionEndCounterPhase();
} else if (action && action.subject().isDead()) {
this.actionStartCounterPhase();
} else {
this.actionPerformCounterPhase(action);
}
this._counterQueue = this._counterQueue || [];
};
BattleManager.actionEndCounterPhase = function () {
this._countering = false;
if (this._counterOriginalSubject) {
this._subject = this._counterOriginalSubject;
this._action = this._counterOriginalAction;
if (this.isSetCounterOriginal()) {
this._subject.setCounterAction(this._action);
}
}
this._counterOriginalSubject = undefined;
this._counterOriginalAction = undefined;
this._counterSequence = 0;
this._counterQueue = [];
};
BattleManager.isSetCounterOriginal = function () {
if (this.isDTB()) return false;
return true;
};
BattleManager.actionPerformCounterPhase = function (action) {
this._countering = true;
this._subject.removeCounterAction();
this._subject = action.subject();
this._action = action;
var subject = this._subject;
var targets = action.makeTargets();
this.setTargets(targets);
this._allTargets = targets.slice();
this._individualTargets = targets.slice();
this._phase = "phaseChange";
this._phaseSteps = ["setup", "whole", "target", "follow", "finish"];
this._returnPhase = "";
this._actionList = [];
subject.useItem(this._action.item());
this._action.applyGlobal();
this._logWindow.startAction(this._subject, this._action, this._targets);
};
//=============================================================================
// Game_BattlerBase
//=============================================================================
Yanfly.Counter.Game_BattlerBase_updateStateActionStart = Game_BattlerBase.prototype.updateStateActionStart;
Game_BattlerBase.prototype.updateStateActionStart = function () {
if (BattleManager.isCountering()) return;
Yanfly.Counter.Game_BattlerBase_updateStateActionStart.call(this);
};
//=============================================================================
// Game_Battler
//=============================================================================
Yanfly.Counter.Game_Battler_refresh = Game_Battler.prototype.refresh;
Game_Battler.prototype.refresh = function () {
this._counterTotalCache = undefined;
Yanfly.Counter.Game_Battler_refresh.call(this);
};
Game_Battler.prototype.counterSkills = function () {
if (this._counterSkills === undefined || this._counterSkills === []) {
return [];
}
var array = [];
var length = this._counterSkills.length;
for (var i = 0; i < length; ++i) {
var skillId = this._counterSkills[i];
var skill = $dataSkills[skillId];
array.push(skill);
}
return array;
};
Game_Battler.prototype.makeCounterSkills = function () {
this._counterSkills = [];
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
if (!obj) continue;
if (obj.counterSkills) {
Yanfly.Util.extend(this._counterSkills, obj.counterSkills);
}
this.extendCounterSkillsEval(obj);
}
};
Game_Battler.prototype.extendCounterSkillsEval = function (obj) {
if (!obj) return;
if (!obj.counterSkillsEval) return;
if (obj.counterSkillsEval === "") return;
var skills = [];
var a = this;
var user = this;
var subject = this;
var b = this;
var target = this;
var s = $gameSwitches._data;
var v = $gameVariables._data;
var code = obj.counterSkillsEval;
try {
eval(code);
} catch (e) {
Yanfly.Util.displayError(e, code, "COUNTER SKILLS ERROR");
}
Yanfly.Util.extend(this._counterSkills, obj.counterSkills);
};
Yanfly.Counter.Game_Battler_onBattleStart = Game_Battler.prototype.onBattleStart;
Game_Battler.prototype.onBattleStart = function () {
Yanfly.Counter.Game_Battler_onBattleStart.call(this);
this._counters = 0;
};
Yanfly.Counter.Game_Battler_onTurnStart = Game_Battler.prototype.onTurnStart;
Game_Battler.prototype.onTurnStart = function () {
Yanfly.Counter.Game_Battler_onTurnStart.call(this);
this._counters = 0;
};
Game_Battler.prototype.counterTotal = function () {
var value = Yanfly.Param.CounterTotal;
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
if (!obj) continue;
if (obj.counterTotal) value += obj.counterTotal;
value += this.getCounterTotalEval(obj);
}
return value;
};
Game_Battler.prototype.getCounterTotalEval = function (obj) {
if (!obj) return 0;
if (!obj.counterTotalEval) return 0;
if (obj.counterTotalEval === "") return 0;
var value = 0;
var a = this;
var user = this;
var subject = this;
var b = this;
var target = this;
var s = $gameSwitches._data;
var v = $gameVariables._data;
var code = obj.counterTotalEval;
try {
eval(code);
} catch (e) {
Yanfly.Util.displayError(e, code, "COUNTER TOTAL ERROR");
}
return value;
};
Game_Battler.prototype.payCounter = function (value) {
value = value || 1;
this._counters += value;
};
Game_Battler.prototype.canCounter = function () {
if (!this.canMove()) return false;
return this.counterTotal() >= this._counters;
};
Game_Battler.prototype.targetCounterRate = function () {
var rate = 1;
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
if (!obj) continue;
rate *= obj.targetCounterRate;
}
return rate;
};
Game_Battler.prototype.targetCounterFlat = function () {
var value = 0;
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
if (!obj) continue;
value += obj.targetCounterFlat;
}
return value;
};
Game_Battler.prototype.targetCounterRateEval = function (rate, target, item) {
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
rate = this.getTargetCntRateEval(obj, rate, target, item);
}
return rate;
};
Game_Battler.prototype.getTargetCntRateEval = function (obj, rate, trg, item) {
if (!obj) return rate;
if (!obj.targetCounterRateEval) return rate;
if (obj.targetCounterRateEval === "") return rate;
var skill = item;
var a = this;
var user = this;
var subject = this;
var b = trg;
var target = trg;
var s = $gameSwitches._data;
var v = $gameVariables._data;
var code = obj.targetCounterRateEval;
try {
eval(code);
} catch (e) {
Yanfly.Util.displayError(e, code, "TARGET COUNTER RATE ERROR");
}
return rate;
};
Game_Battler.prototype.forceEvadeCounter = function () {
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
if (!obj) continue;
if (obj.evadeCounter) return true;
}
return false;
};
Game_Battler.prototype.forceHitCounter = function () {
var length = this.states().length;
for (var i = 0; i < length; ++i) {
var obj = this.states()[i];
if (!obj) continue;
if (obj.hitCounter) return true;
}
return false;
};
Game_Battler.prototype.forceEvadePopup = function () {
this._result = new Game_ActionResult();
this._result.evaded = true;
this.startDamagePopup();
this.clearResult();
};
Game_Battler.prototype.setCounterAction = function (action) {
if (!this._originalPreCounterActions) {
this._originalPreCounterActions = JsonEx.makeDeepCopy(this._actions);
}
action.setCounter();
this.setAction(0, action);
};
Game_Battler.prototype.removeCounterAction = function () {
if (this._originalPreCounterActions) {
this._actions = JsonEx.makeDeepCopy(this._originalPreCounterActions);
}
this._originalPreCounterActions = undefined;
};
//=============================================================================
// Game_Actor
//=============================================================================
Game_Actor.prototype.makeCounterSkills = function () {
Game_Battler.prototype.makeCounterSkills.call(this);
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
if (!obj) continue;
if (obj.counterSkills) {
Yanfly.Util.extend(this._counterSkills, obj.counterSkills);
}
this.extendCounterSkillsEval(obj);
}
if (this.currentClass().counterSkills) {
obj = this.currentClass();
Yanfly.Util.extend(this._counterSkills, obj.counterSkills);
this.extendCounterSkillsEval(obj);
}
if (this.actor().counterSkills) {
obj = this.actor();
Yanfly.Util.extend(this._counterSkills, obj.counterSkills);
this.extendCounterSkillsEval(obj);
}
if (this._counterSkills.length <= 0) {
this._counterSkills.push(obj.defaultCounter);
}
};
Game_Actor.prototype.counterTotal = function () {
if (this._counterTotalCache !== undefined) return this._counterTotalCache;
var value = Game_Battler.prototype.counterTotal.call(this);
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
if (!obj) continue;
if (obj.counterTotal) value += obj.counterTotal;
value += this.getCounterTotalEval(obj);
}
value += this.currentClass().counterTotal;
value += this.getCounterTotalEval(this.currentClass());
value += this.actor().counterTotal;
value += this.getCounterTotalEval(this.actor());
this._counterTotalCache = value;
return this._counterTotalCache;
};
Game_Actor.prototype.targetCounterRate = function () {
var rate = Game_Battler.prototype.targetCounterRate.call(this);
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
if (!obj) continue;
rate *= obj.targetCounterRate;
}
rate *= this.currentClass().targetCounterRate;
rate *= this.actor().targetCounterRate;
return rate;
};
Game_Actor.prototype.targetCounterFlat = function () {
var value = Game_Battler.prototype.targetCounterFlat.call(this);
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
if (!obj) continue;
value += obj.targetCounterFlat;
}
value += this.currentClass().targetCounterFlat;
value += this.actor().targetCounterFlat;
return value;
};
Game_Actor.prototype.targetCounterRateEval = function (rate, target, item) {
var rate = Game_Battler.prototype.targetCounterRateEval.call(this, rate, target, item);
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
rate = this.getTargetCntRateEval(obj, rate, target, item);
}
rate = this.getTargetCntRateEval(this.currentClass(), rate, target, item);
rate = this.getTargetCntRateEval(this.actor(), rate, target, item);
return rate;
};
Game_Actor.prototype.forceEvadeCounter = function () {
if (Game_Battler.prototype.forceEvadeCounter.call(this)) return true;
if (this.actor().evadeCounter) return true;
if (this.currentClass().evadeCounter) return true;
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
if (!obj) continue;
if (obj.evadeCounter) return true;
}
return false;
};
Game_Actor.prototype.forceHitCounter = function () {
if (Game_Battler.prototype.forceHitCounter.call(this)) return true;
if (this.actor().hitCounter) return true;
if (this.currentClass().hitCounter) return true;
var length = this.equips().length;
for (var i = 0; i < length; ++i) {
var obj = this.equips()[i];
if (!obj) continue;
if (obj.hitCounter) return true;
}
return false;
};
//=============================================================================
// Game_Enemy
//=============================================================================
Game_Enemy.prototype.makeCounterSkills = function () {
Game_Battler.prototype.makeCounterSkills.call(this);
if (this.enemy().counterSkills) {
obj = this.enemy();
Yanfly.Util.extend(this._counterSkills, obj.counterSkills);
this.extendCounterSkillsEval(obj);
}
if (this._counterSkills.length <= 0) {
this._counterSkills.push(obj.defaultCounter);
}
};
Game_Enemy.prototype.counterTotal = function () {
if (this._counterTotalCache !== undefined) return this._counterTotalCache;
var value = Game_Battler.prototype.counterTotal.call(this);
value += this.enemy().counterTotal;
value += this.getCounterTotalEval(this.enemy());
this._counterTotalCache = value;
return this._counterTotalCache;
};
Game_Enemy.prototype.targetCounterRate = function () {
var rate = Game_Battler.prototype.targetCounterRate.call(this);
rate *= this.enemy().targetCounterRate;
return rate;
};
Game_Enemy.prototype.targetCounterFlat = function () {
var value = Game_Battler.prototype.targetCounterFlat.call(this);
value += this.enemy().targetCounterFlat;
return value;
};
Game_Enemy.prototype.targetCounterRateEval = function (rate, target, item) {
var rate = Game_Battler.prototype.targetCounterRateEval.call(this, rate, target, item);
rate = this.getTargetCntRateEval(this.enemy(), rate, target, item);
return rate;
};
Game_Enemy.prototype.forceEvadeCounter = function () {
if (Game_Battler.prototype.forceEvadeCounter.call(this)) return true;
if (this.enemy().evadeCounter) return true;
return false;
};
Game_Enemy.prototype.forceHitCounter = function () {
if (Game_Battler.prototype.forceHitCounter.call(this)) return true;
if (this.enemy().hitCounter) return true;
return false;
};
//=============================================================================
// Game_Action
//=============================================================================
Game_Action.prototype.itemCnt = function (target) {
if (this.item().cannotCounter) return 0;
if (!this.item().allyCounter) {
if (target.isActor() === this.subject().isActor()) return 0;
}
if (!target.canMove()) return 0;
if (!target.canCounter()) return 0;
var rate = target.cnt;
rate *= this.subject().targetCounterRate();
rate *= this.item().counterRate;
rate += this.subject().targetCounterFlat();
rate += this.item().counterMod;
rate = this.subject().targetCounterRateEval(rate, target, this.item());
rate = this.customCounterRateEval(rate, target);
return rate;
};
Game_Action.prototype.customCounterRateEval = function (rate, target) {
if (this.item().counterRateEval === "") return rate;
var item = this.item();
var skill = this.item();
var a = this.subject();
var user = this.subject();
var subject = this.subject();
var b = target;
var s = $gameSwitches._data;
var v = $gameVariables._data;
var code = this.item().counterRateEval;
try {
eval(code);
} catch (e) {
Yanfly.Util.displayError(e, code, "COUNTER RATE ERROR");
}
return rate;
};
if (Imported.YEP_X_BattleSysCTB) {
Yanfly.Counter.Game_Action_rebalanceCTBSpeed = Game_Action.prototype.rebalanceCTBSpeed;
Game_Action.prototype.rebalanceCTBSpeed = function (target) {
if (BattleManager.isCountering()) return;
Yanfly.Counter.Game_Action_rebalanceCTBSpeed.call(this, target);
};
} // Imported.YEP_X_BattleSysCTB
Yanfly.Counter.Game_Action_clear = Game_Action.prototype.clear;
Game_Action.prototype.clear = function () {
Yanfly.Counter.Game_Action_clear.call(this);
this._isCounter = false;
this._isForceMiss = false;
};
Game_Action.prototype.setCounter = function () {
this._isCounter = true;
};
Game_Action.prototype.isCounter = function () {
return this._isCounter;
};
//=============================================================================
// Window_BattleLog
//=============================================================================
Yanfly.Counter.Window_BattleLog_displayIcon = Window_BattleLog.prototype.displayIcon;
Window_BattleLog.prototype.displayIcon = function (item) {
if (BattleManager.isCountering()) return item.counterIcon;
return Yanfly.Counter.Window_BattleLog_displayIcon.call(this, item);
};
Yanfly.Counter.Window_BattleLog_displayText = Window_BattleLog.prototype.displayText;
Window_BattleLog.prototype.displayText = function (item) {
if (BattleManager.isCountering()) return item.counterName;
return Yanfly.Counter.Window_BattleLog_displayText.call(this, item);
};
//=============================================================================
// Utilities
//=============================================================================
Yanfly.Util = Yanfly.Util || {};
Yanfly.Util.extend = function (mainArray, otherArray) {
otherArray.forEach(function (i) {
mainArray.push(i);
}, this);
};
Yanfly.Util.displayError = function (e, code, message) {
console.log(message);
console.log(code || "NON-EXISTENT");
console.error(e);
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
if (!require("nw.gui").Window.get().isDevToolsOpen()) {
require("nw.gui").Window.get().showDevTools();
}
}
};
//=============================================================================
// End of File
//=============================================================================
}