//============================================================================= // 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.08; //============================================================================= /*: * @plugindesc v1.08 (Requires YEP_BattleEngineCore.js) Gives you more * control over how counters work in RPG Maker MV! * @author Yanfly Engine Plugins * * @param ---General--- * @default * * @param Queue Max * @parent ---General--- * @type number * @min 1 * @desc What's the maximum size for the counter queue? * @default 20 * * @param ---Default Traits--- * @default * * @param Counter Skill * @parent ---Default Traits--- * @type number * @min 1 * @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 * @parent ---Default Traits--- * @type boolean * @on YES * @off NO * @desc Counter skills to evade, then counter by default? * NO - false YES - true * @default false * * @param Counter Name * @parent ---Default Traits--- * @desc The default counter skill name used per skill. * %1 - Skill Name * @default Counter-%1 * * @param Counter Icon * @parent ---Default Traits--- * @type number * @min 0 * @desc The icon ID used for counter attacks. Leave at 0 * to use the default skill's icon. * @default 78 * * @param Counter Total * @parent ---Default Traits--- * @desc Default amount of counters per actor and enemy. * @default 1 * * @param Ally Counter * @parent ---Default Traits--- * @type boolean * @on YES * @off NO * @desc Allow allies to counter the actions of other allies? * NO - false YES - true * @default false * * @param ---Default Conditions--- * @default * * @param Physical * @parent ---Default Conditions--- * @type boolean * @on YES * @off NO * @desc Require the countered action to be physical? * NO - false YES - true * @default true * * @param Single Target * @parent ---Default Conditions--- * @type boolean * @on YES * @off NO * @desc Require the countered action scope to be single target? * NO - false YES - true * @default true * * @param Not Counter * @parent ---Default Conditions--- * @type boolean * @on YES * @off NO * @desc Require the countered action to not be a counter? * NO - false YES - true * @default false * * @help * ============================================================================ * Introduction * ============================================================================ * * This plugin requires YEP_BattleEngineCore. Make sure this plugin is located * under YEP_BattleEngineCore in the plugin list. * * If you are using Imported.YEP_X_BattleSysATB or Imported.YEP_X_BattleSysCTB, * place this plugin under those plugins in the plugin list. * * The default counterattack trait in RPG Maker MV doesn't give many options * for the developer. It's a skill that flatout cancels out the physical skill * of the attacker by evading it and then producing a normal attack from the * counterattacker. This plugin will give you more control over how counters * work in the sense that you can choose to have the counter connect first * before allowing the counter skill to proc. * * ============================================================================ * 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 * ============================================================================ * * When the pool of counter skills is being generated, they will be generated * in the following order: * * 1. States - Highest Priority Notebox * 2. States - Lowest Priority Notebox * 3. Equipment - Weapons Notebox * 4. Equipment - Armors Notebox * 5. Actor - Current Class Notebox * 6. Actor - Actor Notebox * 7. Enemy - Enemy Notebox * * 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 * ============================================================================ * * You can use the following notetags to alter counters in your game. Each of * these notetags will alter counters in a particular way. * * Actor and Enemy Notetags: * * * * 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. * * Actor, Class, Enemy, Weapon, Armor, and State Notetags: * * * * * 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. * * * 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. * * * * 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. * * * 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%. * * * * 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%. * * * 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 , then priority will be given * to the trait instead. * * * 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 , this effect will take priority. * * Skill and Item Notetags: * * * Makes this action able to proc counter skills by allied members. * * * Makes this action unable to proc counter skills by allied members. * * * Causes this action to be un-counterable. This means that it will always * return a 0% counterattack possibility. * * * 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. * * * * 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. * * Skill Notetags: * * * If this skill is being used as the counter skill, the battler will evade * the current action and then counter. * * * If this skill is being used as the counter skill, the battler will take * the hit against the current action and then counter. * * * This changes the displayed name of the skill when used as a counter skill * to 'text'. * * * This changes the displayed icon of the skill when used as a counter skill * to x icon. * * ============================================================================ * 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: * * Skill Notetags: * * * condition * condition * * Replace the 'condition' text in between the notetags with the listed in * the conditions list below to best fit what you want. * * --- Example --- * * * physical hit * single target * * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * 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. * * Actor, Class, Enemy, Weapon, Armor, and State Notetags: * * * 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); * } * * 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. * * ============================================================================ * 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: * * Actor, Class, Enemy, Weapon, Armor, and State Notetags: * * * value = user.level; * * 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. * * ============================================================================ * 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. * * Actor, Class, Enemy, Weapon, Armor, and State Notetags: * * * rate -= user.hpRate(); * * 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: * * * rate += target.hpRate(); * * 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. * * ============================================================================ * 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. * * Skill Notetags: * * * if (attacker.name() === 'Harold') { * condition = true; * } else if (defender.name() === 'Therese') { * condition = true; * } else { * condition = false; * } * * 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 * conditions will be checked. * * ============================================================================ * Changelog * ============================================================================ * * Version 1.08: * - Updated for RPG Maker MV version 1.5.0. * * Version 1.07a: * - Lunatic Mode fail safes added. * - Optimization update * * 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 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(//i)) { obj.defaultCounter = parseInt(RegExp.$1); } else if (line.match(//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(//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(//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(//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(//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(//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(//i)) { obj.allyCounter = true; } else if (line.match(//i)) { obj.allyCounter = false; } else if (line.match(//i)) { obj.cannotCounter = true; } else if (line.match(//i)) { obj.counterRate = parseFloat(RegExp.$1) * 0.01; } else if (line.match(//i)) { obj.counterMod = parseFloat(RegExp.$1) * 0.01; } else if (line.match(//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 = code; 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.isDevToolsOpen()) { require('nw.gui').window.showDevTools(); } } }; //============================================================================= // End of File //============================================================================= };