DoubleX RMMV Unison Item Config
/*============================================================================
 *    ## Plugin Info                                                          
 *----------------------------------------------------------------------------
 *    # Plugin Name                                                           
 *      DoubleX RMMV Unison Item Config                                       
 *----------------------------------------------------------------------------
 *    # Introduction                                                          
 *      In the default RMMV battle system, no skill/item needs more than 1    
 *      battlers to use                                                       
 *      With this plugin, you can set some skills/items to be unison ones     
 *      needing more than 1 battlers to use them                              
 *      Unison battlers are those needed to use the unison skill/item         
 *      Unison invoker is the battler actually selecting and invoking the     
 *      unison skill/item                                                     
 *      Unison invokees are all unison battlers besides the unison invoker    
 *      There can only be 1 unison invoker for each selected unison skill/item
 *      - (v1.02a+)A synchronous unison skill/item is one without any         
 *               <async unison item> notetag                                  
 *      - (v1.02a+)An asynchronous unison skill/item is one with at least 1   
 *               <async unison item> notetags                                 
 *----------------------------------------------------------------------------
 *    # Terms Of Use                                                          
 *      You shall keep this plugin's Plugin Info part's contents intact       
 *      You shalln't claim that this plugin's written by anyone other than    
 *      DoubleX or his aliases                                                
 *      None of the above applies to DoubleX or his aliases                   
 *----------------------------------------------------------------------------
 *    # Prerequisites                                                         
 *      Abilities:                                                            
 *      1. Some Javascript coding proficiency to fully utilize this plugin    
 *----------------------------------------------------------------------------
 *    # Links                                                                 
 *      This plugin:                                                          
 *      1. [url]http://pastebin.com/igFhrKja[/url]                                       
 *      Mentioned Patreon Supporters:
 *      [url]https://www.patreon.com/posts/71738797[/url]
 *----------------------------------------------------------------------------
 *    # Instructions                                                          
 *      1. To use this plugin with the default battle system, place           
 *         DoubleX RMMV Unison Item Default below this plugin                 
 *      2. To use this plugin with YEP_X_BattleSysCTB, place                  
 *         DoubleX RMMV Unison Item YEP_X_BattleSysCTB below                  
 *         DoubleX RMMV Unison Item Default, which should be placed below this
 *         plugin                                                             
 *      3. To use this plugin with YEP_X_BattleSysATB, place                  
 *         DoubleX RMMV Unison Item YEP_X_BattleSysATB below                  
 *         DoubleX RMMV Unison Item Default, which should be placed below this
 *         plugin                                                             
 *----------------------------------------------------------------------------
 *    # Author                                                                
 *      DoubleX                                                               
 *----------------------------------------------------------------------------
 *    # Changelog                                                             
 *      DoubleX RMMV Unison Item YEP_X_BattleSysATB:                          
 *      v1.00a(GMT 0600 21-5-2016):                                           
 *      1. 1st version of this plugin finished                                
 *      DoubleX RMMV Unison Item YEP_X_BattleSysCTB:                          
 *      v1.00b(GMT 1300 14-5-2016):                                           
 *      1. In sync with the latest version of DoubleX RMMV Unison Item Config 
 *      v1.00a(GMT 1500 28-2-2016):                                           
 *      1. 1st version of this plugin finished                                
 *      2. Unison skills/items needing charging might be executed immediately 
 *         and/or cause the action order queue to be incorrect and/or outdated
 *      DoubleX RMMV Unison Item Default:                                     
 *      v1.00f(GMT 1300 14-5-2016):                                           
 *      1. Fixed a bug where unison items can have unison invokees with no    
 *         empty action slots                                                 
 *      2. In sync with the latest version of this plugin                     
 *      v1.00e(GMT 1500 30-1-2016):                                           
 *      1. Fixed not passing this to canUseUnisonSkill and canUseUnisonItem   
 *      2. Fixed not checking if item exist first in canUse bug               
 *      3. Fixed unison invoker might not have the smallest party member index
 *      v1.00d(GMT 1100 4-1-2016):                                            
 *      1. Fixed all unison item being unusable due to typo bug               
 *      2. Added plugin description and author name in the plugin manager     
 *      v1.00c(GMT 0100 1-1-2016):                                            
 *      1. Fixed undefined SceneManager.scene by using $gameParty.inBattle()  
 *      v1.00b(GMT 0300 26-12-2015):                                          
 *      1. Fixed unison skills/items not usable outside battles bug           
 *      2. Simplified the unison skill usability checks                       
 *      v1.00a(GMT 1400 25-12-2015):                                          
 *      1. 1st version of this plugin finished                                
 *      This plugin:                                                          
 *      v1.03a(GMT 0500 23-7-2016):                                           
 *      1. Added <unison item actor function drain: weights>                  
 *      v1.02a(GMT 1300 14-5-2016):                                           
 *      1. Added <unison item actor learn: flags> and <async unison item>     
 *      v1.01b(GMT 1300 17-3-2016):                                           
 *      1. Fixed undefined uIFAs[RegExp.$1] in DM.loadItemNotes bug           
 *      2. Fixed incorrect unison battler stat when using unison rules bug    
 *      v1.01a(GMT 1400 15-3-2016):                                           
 *      1. Added <unison item actor mp cost: ids> and                         
 *               <unison item actor tp cost: ids>                             
 *      v1.00f(GMT 1000 28-2-2016):                                           
 *      1. Fixed unison invokees not stepping forward when executing actions  
 *      v1.00e(GMT 1500 30-1-2016):                                           
 *      1. Fixed not returning value in makeDamageValue bug                   
 *      2. Fixed not showing unison item names in the battle log window bug   
 *      3. Fixed enemy using actor unison item showing unison actor names bug 
 *      v1.00d(GMT 0200 3-1-2016):                                            
 *      1. FUNCTIONS now store all battler functions instead of merely getters
 *      v1.00c(GMT 1300 31-12-2015):                                          
 *      1. Fixed writing getter contents directly instead of using String bug 
 *      v1.00b(GMT 0900 30-12-2015):                                          
 *      1. Fixed failed to extend battler property name descriptors bug       
 *      2. Fixed using new Function and class instead of eval and prototype   
 *      3. Fixed unintentionally declaring global variable in strict mode bug 
 *      4. Fixed calling push for an Object instead of its Array values bug   
 *      5. Fixed using 1 single variable to store all old getter functions bug
 *      v1.00a(GMT 1400 25-12-2015):                                          
 *      1. 1st version of this plugin finished                                
 *============================================================================*/
/*:
 * @plugindesc Lets you set some skills/items needing mutiple battlers to use
 * @author DoubleX
 *
 * @param showAllUnisonBattlers
 * @desc Sets if the battlelog will show all unison battlers instead of only
 *       the unison invoker
 * @default true
 *
 * @param unisonFunctionRule
 * @desc Sets the string of the rule used for setting the user's functions in
 *       the damage formula of the unison skill/item by using those of all
 *       unison battlers
 *       It'll only be used for those functions not having their unison rules
 *       It must be implemented by function RULES, which must be edited by
 *       opening this plugin js file directly
 * @default avg
 *
 * @help
 * The default plugin file name is DoubleX RMMV Unison Item Config v103a
 * If you want to change that, you must edit the value of
 * DoubleX_RMMV.Unison_Item_File, which must be done via opening this plugin
 * js file directly
 *============================================================================
 *    ## Notetag Info                                                         
 *----------------------------------------------------------------------------
 *    # Skill/Item Notetags:                                                  
 *      1. <unison item actors: ids>                                          
 *         - Sets the list of id of actors needed for the skill/item as ids   
 *           , is used to separate the actor id in ids                        
 *           E.g.:                                                            
 *           <unison item actors: 1> means actor with id 1 is needed to use it
 *           <unison item actors: 4, 2> means actors with id 4 and 2 are      
 *           needed to use it                                                 
 *         - All actors included in ids needs to be inputable, able to use the
 *           skills/item and pay its cost                                     
 *         - All unison actors will pay the unison skill costs after using it 
 *         - Only actors included in ids can select the skill/item            
 *         - If ids only contains 1 actor id, this notetag will become only   
 *           letting the actor with that actor id to use the skill/item       
 *      2. <unison item function rule: rule>                                  
 *         - Sets the rule of setting user's function in the skill/item's     
 *           damage formula as rule which is implemented by function          
 *           RULES, which must be edited by opening this plugin js file       
 *           directly                                                         
 *         - function must be a battler function name included in             
 *           FUNCTIONS, which must be edited by opening this plugin js file   
 *           directly                                                         
 *      3. <unison item function actors: ids>                                 
 *         - Sets user's function in the skill/item's damage formula to use   
 *           its unison item rule to combine those of actors with id included 
 *           in ids                                                           
 *           E.g.:                                                            
 *           <unison item atk actors: 1> means the user's atk in its damage   
 *           formula uses that of actor with id 1 under the skill/item's      
 *           unison rule applied to atk                                       
 *           <unison item mat actors: 4, 2> means the user's mat in its damage
 *           formula uses those of actors with id 4 and 2 under the           
 *           skill/item's unison rule applied to mat                          
 *         - function must be a battler function name included in             
 *           FUNCTIONS, which must be edited by opening this plugin js file   
 *           directly                                                         
 *      4. (v1.01a+)<unison item actor mp cost: costs>                        
 *         - Sets the list of mp costs needed for each of the corresponding id
 *           of the unison actor in <unison item actors: ids>                 
 *           , is used to separate the mp costs in ids                        
 *           E.g.:                                                            
 *           If <unison item actors: 1> is used, then                         
 *           <unison item actor mp cost: 5> means actor with id 1 needs to pay
 *           the 5 mp cost for using the unison skill/item                    
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor mp cost: 5, 10> means actor with id 4 and 2   
 *           need to pay the 5 and 10 mp cost respectively for using the      
 *           unison skill/item                                                
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor mp cost: 5> means actor with id 4 needs to pay
 *           the 5 mp cost while that with id 2 needs to pay the default      
 *           skill/item mp cost for using the unison skill/item               
 *         - MCR will be applied to the mp costs for all unison actors        
 *      5. (v1.01a+)<unison item actor tp cost: costs>                        
 *         - Sets the list of tp costs needed for each of the corresponding id
 *           of the unison actor in <unison item actors: ids>                 
 *           , is used to separate the tp costs in ids                        
 *           E.g.:                                                            
 *           If <unison item actors: 1> is used, then                         
 *           <unison item actor tp cost: 5> means actor with id 1 needs to pay
 *           the 5 tp cost for using the unison skill/item                    
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor tp cost: 5, 10> means actor with id 4 and 2   
 *           need to pay the 5 and 10 tp cost respectively for using the      
 *           unison skill/item                                                
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor tp cost: 5> means actor with id 4 needs to pay
 *           the 5 tp cost while that with id 2 needs to pay the default      
 *           skill/item tp cost for using the unison skill/item               
 *      6. (v1.02a+)<unison item actor learn: flags>                          
 *         - Sets the list of skill learn requirement flags for each of the   
 *           corresponding id of the unison actor in <unison item actors: ids>
 *           , is used to separate the skill learn requirement flags          
 *           Flag can be either t or f, meaning true or false respectively    
 *           The default unison skill learn requirement is true               
 *           This notetag only works on skills and has no effects on items    
 *           E.g.:                                                            
 *           If <unison item actors: 1> is used, then                         
 *           <unison item actor skill learn: t> means actor with id 1 needs to
 *           learn the skill in order to use it                               
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor skill learn: t, f> means actor with id 4 needs
 *           to learn the skill in order to use it while actor with id 2      
 *           doesn't need to                                                  
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor skill learn: f> means actor with id 4 doesn't 
 *           need to learn the skill in order to use it while actor with id 2 
 *           needs to due to the default unison skill learn requirement       
 *      7. (v1.02a+)<async unison item>                                       
 *         - Sets the unison skill/item to be inputable when any battler      
 *           needed for that skill/item is inputable                          
 *         - That skill/item and all battlers inputted it will wait for all   
 *           battlers needed for that skill/item to input it in order for them
 *           to execute it altogether                                         
 *         - This notetag will be ignored in the default RMMV battle system   
 *           and all unison skills/items will be synchronous ones             
 *         - This notetag will be ignored in ATB systems that will always wait
 *           when there are inputable actors and all unison skills/items will 
 *           be asynchronous ones                                             
 *      8. (v1.03a+)<unison item actor function drain: weights>               
 *         - Sets user's drained hp/mp/etc for skills/items draining hp/mp/etc
 *           to use redistribute the drained hp/mp/etc to all those of actors 
 *           with id included in ids in <unison item actors: ids>             
 *         - function must be a battler getter name                           
 *         - The redistribution amount to each actor is the minimum value of  
 *           the corresponding weight / sum of weights and the difference     
 *           between the hp and the mhp                                       
 *         - If the sum of weights is 0, then no actor will receive any amount
 *           of the drained hp/mp/etc                                         
 *         - All the undistributed drained hp/mp/etc will be taken by the     
 *           unison invoker, and any amount left by the unison invoker will be
 *           lost                                                             
 *           E.g.:                                                            
 *           If <unison item actors: 1> is used, then                         
 *           <unison item actor hp drain: 0> means actor with id 1 won't      
 *           receive any drained hp from skills/items draining hp             
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor mp drain: 1, 2> means actor with id 4 and 2   
 *           will receive 1/3 and 2/3 of the drained mp from skills/items     
 *           draining mp respectively                                         
 *           If <unison item actors: 4, 2> is used, then                      
 *           <unison item actor mp cost: 1> means actor with id 4 and 2 will  
 *           receive 100% and 0% of the drained mp from skills/items draining 
 *           mp respectively                                                  
 *============================================================================
 *    ## Plugin Call Info                                                     
 *----------------------------------------------------------------------------
 *    # Configuration manipulations                                           
 *      1. DoubleX_RMMV.Unison_Item.prop                                      
 *         - Returns the property prop under DoubleX_RMMV.Unison_Item         
 *      2. DoubleX_RMMV.Unison_Item.prop = val                                
 *         - Sets the property prop under DoubleX_RMMV.Unison_Item as val     
 *         - No DoubleX_RMMV.Unison_Item.prop change will be saved            
 *      3. $gameSystem.unisonItem.param                                       
 *         - Returns the value of param listed in the plugin manager          
 *      4. $gameSystem.unisonItem.param = val                                 
 *         - Sets the value of param listed in the plugin manager as val      
 *         - All $gameSystem.unisonItem.param changes will be saved           
 *    # Skill/Item manipulations                                              
 *      1. meta.unisonItemActors                                              
 *         - Returns the Array of ids of actors needed to use this skill/item 
 *      2. meta.unisonItemActors = [id, id, ...]                              
 *         - Sets the Array of ids of actors needed to use this skill/item    
 *         - All meta.unisonItemActors changes can be saved if                
 *           DoubleX RMMV Dynamic Data is used                                
 *      3. meta.unisonItemRules[functionName]                                 
 *         - Returns the unison item rule as String for function with name    
 *           functionName as a String                                         
 *      4. meta.unisonItemRules[functionName] = rule                          
 *         - Sets the unison item rule for function with name functionName as 
 *           String as String rule, which must be implemented by              
 *           RULES, which must be edited by opening this plugin js file       
 *           directly                                                         
 *         - function with name functionName must be included in              
 *           FUNCTIONS, which must be edited by opening this plugin js file   
 *           directly                                                         
 *         - All meta.unisonItemRules changes can be saved if                 
 *           DoubleX RMMV Dynamic Data is used                                
 *      5. meta.unisonItemFunctionActors[functionName]                        
 *         - Returns the Array of ids of actors included for combining their  
 *           function functionName as String using its unison item rule       
 *      6. meta.unisonItemFunctionActors[functionName] = [id, id, ...]        
 *         - Sets the Array of ids of actors included for combining their     
 *           function functionName as String using its unison item rule       
 *         - function with name functionName must be included in              
 *           FUNCTIONS, which must be edited by opening this plugin js file   
 *           directly                                                         
 *         - All meta.unisonItemFunctionActors changes can be saved if        
 *           DoubleX RMMV Dynamic Data is used                                
 *      7. (v1.01a+)meta.unisonItemActorMpCosts                               
 *         - Returns the Array of mp costs each needed by its corresponding   
 *           actor with id in meta.unisonItemActors to use this skill/item    
 *      8. (v1.01a+)meta.unisonItemActorMpCosts = [cost, cost, ...]           
 *         - Sets the Array of of mp costs each needed by its corresponding   
 *           actor with id in meta.unisonItemActors to use this skill/item    
 *         - All meta.unisonItemActorMpCosts changes can be saved if          
 *           DoubleX RMMV Dynamic Data is used                                
 *      9. (v1.01a+)meta.unisonItemActorTpCosts                               
 *         - Returns the Array of tp costs each needed by its corresponding   
 *           actor with id in meta.unisonItemActors to use this skill/item    
 *      10. (v1.01a+)meta.unisonItemActorTpCosts = [cost, cost, ...]          
 *          - Sets the Array of of tp costs each needed by its corresponding  
 *            actor with id in meta.unisonItemActors to use this skill/item   
 *          - All meta.unisonItemActorTpCosts changes can be saved if         
 *            DoubleX RMMV Dynamic Data is used                               
 *      11. (v1.02a+)meta.unisonItemActorLearn                                
 *          - Returns the Array of skill learn requirement flags for each     
 *            corresponding actor with id in meta.unisonItemActors to use this
 *            skill/item                                                      
 *      12. (v1.02a+)meta.unisonItemActorLearn = [cost, cost, ...]            
 *          - Sets the Array of skill requirement flags for each corresponding
 *            actor with id in meta.unisonItemActors to use this skill/item   
 *          - All meta.unisonItemActorTpCosts changes can be saved if         
 *            DoubleX RMMV Dynamic Data is used                               
 *      13. (v1.02a+)meta.asyncUnisonItem                                     
 *          - Returns whether the unison skill/item is an asynchronous one    
 *      14. (v1.02a+)meta.asyncUnisonItem = boolean                           
 *          - Sets the unison skill/item to be an asynchronous one if boolean 
 *            is true and a synchronous one if otherwise                      
 *      15. (v1.03a+)meta.unisonItemActorFunctionDrain[functionName]          
 *          - Returns the Array of weights for actors included in the         
 *            corresponding meta.unisonItemActors for redistributing the      
 *            drained function functionName  as String from skills/items      
 *            draining functionName to all those actors                       
 *      16. (v1.03a+)meta.unisonItemActorFunctionDrain[functionName] = [w, ..]
 *          - Sets the Array of weights for actors included in the            
 *            corresponding meta.unisonItemActors for redistributing the      
 *            drained function functionName  as String from skills/items      
 *            draining functionName to all those actors                       
 *          - function with name functionName must be a battler getter name   
 *          - All meta.unisonItemActorFunctionDrain changes can be saved if   
 *            DoubleX RMMV Dynamic Data is used                               
 *============================================================================
 */

var DoubleX_RMMV = DoubleX_RMMV || {};
DoubleX_RMMV["Unison Item Config"] = 'v1.03a';

// The plugin file name must be the same as DoubleX_RMMV.Unison_Item_Config_File
DoubleX_RMMV.Unison_Item_Config_File = 'DoubleX RMMV Unison Item Config v103a';

/*============================================================================
 *    ## Plugin Configurations                                                
 *       You only need to edit this part as it's about what this plugin does  
 *----------------------------------------------------------------------------*/

DoubleX_RMMV.Unison_Item = {

    /* Implements the unison item function rules
     * The unison item function rule can be referenced by rule
     * The Array of unison item function value of all unison battlers can be
     * referneced by vals
     * RULES will be bound to the unison invoker upon use
     * It must return a Number
     */
    RULES: function(rule, vals) {
        if (rule === 'min') {
            return vals.sort(function(a, b) { return a - b; })[0];
        } else if (rule === 'avg') {
            return vals.reduce(function(a, b) { return a + b; }) / vals.length;
        } else if (rule === 'max') {
            return vals.sort(function(a, b) { return b - a; })[0];
        }
        console.log('The unison item rule ' + rule + " isn't implemented");
        return 0;
    },

    /* Sets the battler functions using the unison item rules
     * Its function names must be the class of the battler functions
     * Its values must be those battler functions as Strings
     * All the included battler functions will be extended
     */
    FUNCTIONS: {

      /* General form:
       * class: [
       *     'battler function name',
       *     'battler function name',
       *     'battler function name',
       *     ...,
       *     'battler function name'
       * ]
       */

        Game_BattlerBase: [
            'param',
            'xparam',
            'sparam'
            // Adds new battler function names here
            
        ]

        // Adds new classes here
        

    }

}; // DoubleX_RMMV.Unison_Item

/*============================================================================
 *    ## Plugin Implementations                                               
 *       You need not edit this part as it's about how this plugin works      
 *----------------------------------------------------------------------------
 *    # Plugin Support Info:                                                  
 *      1. Prerequisites                                                      
 *         - Solid understanding to the implementation parts independent from 
 *           any action input nor execution flows in battles                  
 *         - Decent battled related RMMV plugin developement proficiency to   
 *           fully comprehend this plugin                                     
 *      2. Function documentation                                             
 *         - The 1st part describes why this function's rewritten/extended for
 *           rewritten/extended functions or what the function does for new   
 *           functions                                                        
 *         - The 2nd part describes what the arguments of the function are    
 *         - The 3rd part informs which version rewritten, extended or created
 *           this function                                                    
 *         - The 4th part informs whether the function's rewritten or new     
 *         - The 5th part informs whether the function's a real or potential  
 *           hotspot                                                          
 *         - The 6th part describes how this function works for new functions 
 *           only, and describes the parts added, removed or rewritten for    
 *           rewritten or extended functions only                             
 *         Example:                                                           
 * /*----------------------------------------------------------------------
 *  *    Why rewrite/extended/What this function does                      
 *  *----------------------------------------------------------------------*/ 
/* // arguments: What these arguments are                                     
 * functionName = function(arguments) { // Version X+; Hotspot                
 *     // Added/Removed/Rewritten to do something/How this function works     
 *     functionContents                                                       
 *     //                                                                     
 * } // functionName                                                          
 *----------------------------------------------------------------------------*/

(function(UI) {

    'use strict';

    UI.DataManager = {};
    var DM = UI.DataManager;

    DM.isDatabaseLoaded = DataManager.isDatabaseLoaded;
    DataManager.isDatabaseLoaded = function() {
        // Rewritten
        return DM.isDatabaseLoaded.apply(this, arguments) && DM.loadAllNotes();
        //
    }; // DataManager.isDatabaseLoaded

    DM.loadAllNotes = function() {
        [$dataSkills, $dataItems].forEach(function(type) {
            type.forEach(function(data) {
                if (data) { DM.loadItemNotes(data); }
            });
        });
        return true;
    }; // DM.loadAllNotes

    // data: The data to have its notetags read
    DM.loadItemNotes = function(data) {
        var uIAs = data.meta.unisonItemActors = [];
        var uIRs = data.meta.unisonItemRules = {};
        var uIFAs = data.meta.unisonItemFunctionActors = {};
        var uIAMCs = data.meta.unisonItemActorMpCosts = [];
        var uIATCs = data.meta.unisonItemActorTpCosts= [];
        var uIASLs = data.meta.unisonItemActorLearn = [];
        var uIAFDs = data.meta.unisonItemActorFunctionDrain = {};
        var actors = /< *unison +item +actors *: *(\d+(?: *, *\d+)*) *>/i;
        var rule = /< *unison +item +(\w+) +rule*: *(\w+) *>/i;
        var fAs = /< *unison +item +(\w+) +actors *: *(\d+(?: *, *\d+)*) *>/i;
        var MCs = /< *unison +item +actor +mp +cost *: *(\d+(?: *, *\d+)*) *>/i;
        var TCs = /< *unison +item +actor +tp +cost *: *(\d+(?: *, *\d+)*) *>/i;
        var SLs = /< *unison +item +actor +learn *: *(\w+(?: *, *\w+)*) *>/i;
        var async = /< *async +unison +item *>/i, func;
        var aFDs = /<unison +item +actor +(\w+) +drain:(\d+(?: *, *\d+)*)>/i;
        data.note.split(/[\r\n]+/).forEach(function(line) {
            if (line.match(rule)) { return uIRs[RegExp.$1] = RegExp.$2; }
            if (line.match(async)) { return data.meta.asyncUnisonItem = true; }
            if (line.match(actors)) { return DM.storeItemNotes(uIAs); }
            if (line.match(MCs)) { return DM.storeItemNotes(uIAMCs); }
            if (line.match(TCs)) { return DM.storeItemNotes(uIATCs); }
            if (line.match(SLs)) {
                if (uIASLs.length > 0) { return; }
                RegExp.$1.trim().split(/,/).forEach(function(id) {
                    uIASLs.push(id === 't');
                });
            } else if (line.match(fAs)) {
                func = RegExp.$1;
                uIFAs[func] = uIFAs[func] || [];
                if (uIFAs[func].length > 0) { return; }
                RegExp.$2.trim().split(/,/).forEach(function(id) {
                    uIFAs[func].push(+id);
                });
            } else if (line.match(aFDs)) {
                func = RegExp.$1;
                uIAFDs[func] = uuIAFDs[func] || [];
                if (uIAFDs[func].length > 0) { return; }
                RegExp.$2.trim().split(/,/).forEach(function(id) {
                    uIAFDs[func].push(+id);
                });
            }
        });
    }; // DM.loadItemNotes

    // list: A list storing all the effective values of a notetag
    DM.storeItemNotes = function(list) { // v1.02a+
        if (list.length > 0) { return; }
        RegExp.$1.trim().split(/,/).forEach(function(id) { list.push(+id); });
    }; // DM.storeItemNotes

    UI.BattleManager = {};
    var BM = UI.BattleManager;

    BM.endAction = BattleManager.endAction;
    BattleManager.endAction = function() { // v1.00f+
        this._action.item().meta.unisonItemActors.forEach(function(actorId) {
            if (actorId === this._subject.actorId()) { return; }
            $gameActors.actor(actorId).performActionEnd();
        }, this);
        BM.endAction.apply(this, arguments);
    }; // BattleManager.endAction

    UI.Game_System = {};
    var GS = UI.Game_System;

    /*------------------------------------------------------------------------
     *    New public instance variable                                        
     *------------------------------------------------------------------------*/
    // The storage of all configuration values
    Object.defineProperty(Game_System.prototype, 'unisonItem', {
        get: function() { return this._unisonItem; },
        configurable: true
    });

    GS.initialize = Game_System.prototype.initialize;
    Game_System.prototype.initialize = function() {
        GS.initialize.apply(this, arguments);
        GS.initUnisonItemParams.call(this); // Added
    }; // Game_System.prototype.initialize

    GS.initUnisonItemParams = function() {
        var params;
        this._unisonItem = {};
        params = PluginManager.parameters(DoubleX_RMMV.Unison_Item_Config_File);
        Object.keys(params).forEach(function(param) {
            this._unisonItem[param] = params[param] === 'true';
        }, this);
        this._unisonItem.unisonFunctionRule = params.unisonFunctionRule;
    }; // GS.initUnisonItemParams

    UI.Game_Action = {};
    var GA = UI.Game_Action;

    GA.makeDamageValue = Game_Action.prototype.makeDamageValue;
    Game_Action.prototype.makeDamageValue = function(target, critical) {
        // Added to set all user functions to use their unison item rules
        var item = this.item(), subject = this.subject();
        if (subject.isActor() && item.meta.unisonItemActors.length > 1) {
            subject.unisonItem = item;
        }
        //
        var value = GA.makeDamageValue.apply(this, arguments);
        subject.unisonItem = null; // Added to set all user functions to normal
        return value;
    }; // Game_Action.prototype.makeDamageValue

    GA.gainDrainedHp = Game_Action.prototype.gainDrainedHp;
    Game_Action.prototype.gainDrainedHp = function(v) { // v1.03a+
        // Rewritten
        if (!this.isDrain()) { return; }
        GA.gainUnisonDrainedFunc.call(this, 'hp', 0, 'mhp', 'gainDrainedHp', v);
        //
    }; // Game_Action.prototype.gainDrainedHp

    GA.gainDrainedMp = Game_Action.prototype.gainDrainedMp;
    Game_Action.prototype.gainDrainedMp = function(v) { // v1.03a+
        // Rewritten
        if (!this.isDrain()) { return; }
        GA.gainUnisonDrainedFunc.call(this, 'mp', 0, 'mmp', 'gainDrainedMp', v);
        //
    }; // Game_Action.prototype.gainDrainedMp

    GA.gainUnisonDrainedFunc = function(func, min, max, drainFunc, value) {
    // v1.03a+
        var subject = this.subject();
        if (!subject.isActor()) { return GA[drainFunc].call(this, value); }
        var item = this.item(), mems = item.meta.unisonItemActors;
        if (mems.length <= 1) { return GA[drainFunc].call(this, value); }
        var actorId = subject.actorId(), index = mems.indexOf(actorId);
        if (index >= 0) { mems.splice(index, 1); }
        mems.push(actorId);
        var weights = item.meta.unisonItemActorFunctionDrain[func];
        var weightSum = weights.reduce(function(a, b) { return a + b; }, 0);
        if (weightSum === 0) { return; }
        var statChange, newStat, maxStat, mem, weight;
        for (var index = 0, length = mems.length; index < length; index++) {
            weight = weights[index];
            if (!weight) { continue; }
            statChange = Math.trunc(value * weight / weightSum);
            mem = $gameActors.actor(mems[index]);
            maxStat = mem[max], newStat = mem[func] + statChange;
            if (newStat < min) {
                statChange = min - mem[func];
            } else if (newStat > maxStat) {
                statChange = maxStat - mem[func];
            }
            GA[drainFunc].call(this, statChange);
            statDiff -= statChange, weightSum -= weight;
        }
    }; // GA.gainUnisonDrainedFunc

    UI.Game_BattlerBase = {}; // v1.01a+
    var GBB = UI.Game_BattlerBase;

    GBB.skillMpCost = Game_BattlerBase.prototype.skillMpCost;
    Game_BattlerBase.prototype.skillMpCost = function(skill) {
        // Rewritten to return mp cost in <unison item actor mp cost: costs>
        var cost = 'unisonItemActorMpCosts', func = 'skillMpCost';
        return GBB.unisonSkillCost.call(this, skill, cost, func);
        //
    }; // Game_BattlerBase.prototype.skillMpCost

    GBB.skillTpCost = Game_BattlerBase.prototype.skillTpCost;
    Game_BattlerBase.prototype.skillTpCost = function(skill) {
        // Rewritten to return tp cost in <unison item actor tp cost: costs>
        var cost = 'unisonItemActorTpCosts', func = 'skillTpCost';
        return GBB.unisonSkillCost.call(this, skill, cost, func);
        //
    }; // Game_BattlerBase.prototype.skillTpCost

    GBB.unisonSkillCost = function(skill, cost, func) { // v1.02a+
        if (this.isActor()) {
            var index = skill.meta.unisonItemActors.indexOf(this.actorId());
            if (index >= 0) {
                var unisonCost = skill.meta[cost][index];
                if (!isNaN(unisonCost)) { return unisonCost; }
            }
        }
        //
        return GBB[func].apply(this, arguments);
    }; // GBB.unisonSkillCost

    UI.Game_Battler = {};
    var GB = UI.Game_Battler;

    /*------------------------------------------------------------------------
     *    New public instance variables                                       
     *------------------------------------------------------------------------*/
    Object.defineProperties(Game_Battler.prototype, {
        // Read by Game_BattlerBase to get the other battlers' action slot list
        'actions': {
            get: function() { return this._actions; },
            configurable: true
        },
        // The cached unison skill/item when executing its damage formula
        'unisonItem': {
            set: function(item) { this._unisonItem = item; },
            configurable: true
        }
    });

    GB.useItem = Game_Battler.prototype.useItem;
    Game_Battler.prototype.useItem = function(item) {
        // Rewritten to ask all unison invokees to pay the skill/item cost only
        if (!DataManager.isSkill(item)) {
            return GB.useItem.apply(this, arguments);
        } else if (item.meta.unisonItemActors.length <= 1) {
            return GB.useItem.apply(this, arguments);
        }
        item.meta.unisonItemActors.forEach(function(actorId) {
            $gameActors.actor(actorId).paySkillCost(item);
        });
        //
    }; // Game_Battler.prototype.useItem

    UI.Window_ItemList = {};
    var WIL = UI.Window_ItemList;

    WIL.isEnabled = Window_ItemList.prototype.isEnabled;
    Window_ItemList.prototype.isEnabled = function(item) {
        // Rewritten to disable unison items when unison conditions aren't met
        if (!DataManager.isItem(item)) {
            return WIL.isEnabled.apply(this, arguments);
        } else if (item.meta.unisonItemActors.length <= 1) {
            return WIL.isEnabled.apply(this, arguments);
        } else if (!$gameParty.inBattle()) {
            return WIL.isEnabled.apply(this, arguments);
        }
        var actor = BattleManager.actor();
        return actor && actor.canUse(item);
        //
    }; // Window_ItemList.prototype.isEnabled

    UI.Window_BattleLog = {};
    var WBL = UI.Window_BattleLog;

    WBL.performActionStart = Window_BattleLog.prototype.performActionStart;
    Window_BattleLog.prototype.performActionStart = function(subject, action) {
    // v1.00f+
        // Rewritten to ask all unison actor sprites to perform act start
        action.item().meta.unisonItemActors.forEach(function(actorId) {
            $gameActors.actor(actorId).performActionStart(action);
        });
        //
    }; // Window_BattleLog.prototype.performActionStart

    WBL.performAction = Window_BattleLog.prototype.performAction;
    Window_BattleLog.prototype.performAction = function(subject, action) {
    // v1.00f+
        // Rewritten to ask all unison actor sprites to perform act
        action.item().meta.unisonItemActors.forEach(function(actorId) {
            $gameActors.actor(actorId).performAction(action);
        });
        //
    }; // Window_BattleLog.prototype.performActionStart

    WBL.displayAction = Window_BattleLog.prototype.displayAction;
    Window_BattleLog.prototype.displayAction = function(subject, item) {
        // Rewritten to display all unison actor names if users set so
        if (!subject.isActor()) {
            return WBL.displayAction.apply(this, arguments);
        } else if (!$gameSystem.unisonItem.showAllUnisonBattlers) {
            return WBL.displayAction.apply(this, arguments);
        } else if (item.meta.unisonItemActors.length <= 1) {
            return WBL.displayAction.apply(this, arguments);
        }
        WBL.displayUnisonAct.call(this, item);
        //
    }; // Window_BattleLog.prototype.displayAction

    WBL.displayUnisonAct = function(item) {
        var names = WBL.unisonActorNames(item.meta.unisonItemActors);
        var numMethods = this._methods.length;
        if (DataManager.isSkill(item)) {
            if (item.message1) {
                this.push('addText', names + item.message1.format(item.name));
            }
            if (item.message2) {
                this.push('addText', item.message2.format(item.name));
            }
        } else {
            var text = TextManager.useItem.format(names, item.name);
            this.push('addText', text);
        }
        if (this._methods.length === numMethods) { this.push('wait'); }
    }; // WBL.displayUnisonAct

    WBL.unisonActorNames = function(actorIds) {
        var names = '';
        for (var index = 0, length = actorIds.length; index < length; index++) {
            if (index > 0 && index < length - 1) {
                names += ', ';
            } else if (index === length - 1) {
                names += ' and ';
            }
            names += $gameActors.actor(actorIds[index]).name();
        }
        return names;
    }; // WBL.unisonActorNames

    var Proto;
    for (var Klass in UI.FUNCTIONS) {
        if (!UI.FUNCTIONS.hasOwnProperty(Klass)) { continue; }
        // Ensures container GBB and GB won't be rewritten
        UI[Klass] = UI[Klass] || {};
        //
        Proto = eval(Klass + '.prototype'); // Actual class prototype
        UI.FUNCTIONS[Klass].forEach(function(f) {

            /*------------------------------------------------------------
             *    Extends all battler functions using unison item rules   
             *------------------------------------------------------------*/
            UI[Klass][f] = Proto[f];
            Proto[f] = new Function([
            	'var UI = DoubleX_RMMV.Unison_Item, item = this._unisonItem;',
                'if (!item) {',
                '    return UI.' + Klass + '.' + f + '.apply(this, arguments);',
                '}',
                'var actorIds = item.meta.unisonItemFunctionActors.' + f + ';',
                'if (!actorIds) {',
                '    return UI.' + Klass + '.' + f + '.apply(this, arguments);',
                '}',
                'var args = arguments;',
                'var vals = actorIds.map(function(actorId) {',
                '    var actor = $gameActors.actor(actorId);',
                '    return UI.' + Klass + '.' + f + '.apply(actor, args);',
                '});',
                'var rule = item.meta.unisonItemRules.' + f + ';',
                'rule = rule || $gameSystem.unisonItem.unisonFunctionRule;',
                'return UI.RULES.call(this, rule, vals);',
            ].join('\n'));

        });
    }

})(DoubleX_RMMV.Unison_Item);

/*============================================================================*/


DoubleX RMMV Unison Item Default
/*============================================================================
 *    ## Plugin Info                                                          
 *----------------------------------------------------------------------------
 *    # Plugin Name                                                           
 *      DoubleX RMMV Unison Item Default                                      
 *----------------------------------------------------------------------------
 *    # Terms Of Use                                                          
 *      You shall keep this plugin's Plugin Info part's contents intact       
 *      You shalln't claim that this plugin's written by anyone other than    
 *      DoubleX or his aliases                                                
 *      None of the above applies to DoubleX or his aliases                   
 *----------------------------------------------------------------------------
 *    # Prerequisites                                                         
 *      Plugins:                                                              
 *      1. DoubleX RMMV Unison Item Config                                    
 *----------------------------------------------------------------------------
 *    # Links                                                                 
 *      This plugin:                                                          
 *      1. [url]http://pastebin.com/kV33uWeU[/url]                                       
 *      Video:                                                                
 *      1. [url]https://www.youtube.com/watch?v=iBeSIPQnRb0[/url]                        
 *----------------------------------------------------------------------------
 *    # Instructions                                                          
 *      1. Place this plugin below DoubleX RMMV Unison Item Config            
 *----------------------------------------------------------------------------
 *    # Author                                                                
 *      DoubleX                                                               
 *----------------------------------------------------------------------------
 *    # Changelog                                                             
 *      v1.00g(GMT 0300 5-6-2016):                                            
 *      1. Fixed a bug where game crashes when accessing equips in item menu  
 *      v1.00f(GMT 1300 14-5-2016):                                           
 *      1. Fixed a bug where unison items can have unison invokees with no    
 *         empty action slots                                                 
 *      2. In sync with the latest version of DoubleX RMMV Unison Item Config 
 *      v1.00e(GMT 1500 30-1-2016):                                           
 *      1. Fixed not passing this to canUseUnisonSkill and canUseUnisonItem   
 *      2. Fixed not checking if item exist first in canUse bug               
 *      3. Fixed unison invoker might not have the smallest party member index
 *      v1.00d(GMT 1100 4-1-2016):                                            
 *      1. Fixed all unison item being unusable due to typo bug               
 *      2. Added plugin description and author name in the plugin manager     
 *      v1.00c(GMT 0100 1-1-2016):                                            
 *      1. Fixed undefined SceneManager.scene by using $gameParty.inBattle()  
 *      v1.00b(GMT 0300 26-12-2015):                                          
 *      1. Fixed unison skills/items not usable outside battles bug           
 *      2. Simplified the unison skill usability checks                       
 *      v1.00a(GMT 1400 25-12-2015):                                          
 *      1. 1st version of this plugin finished                                
 *============================================================================*/
/*:
 * @plugindesc Lets you use unison skills/items with the default battle system
 * @author DoubleX
 *============================================================================
 */

var DoubleX_RMMV = DoubleX_RMMV || {};
DoubleX_RMMV["Unison Item Default"] = 'v1.00g';

/*============================================================================
 *    ## Plugin Implementations                                               
 *       You need not edit this part as it's about how this plugin works      
 *----------------------------------------------------------------------------
 *    # Plugin Support Info:                                                  
 *      1. Prerequisites                                                      
 *         - Solid understanding to the default RMMV actor action input flows 
 *         - Decent battled related RMMV plugin developement proficiency to   
 *           fully comprehend this plugin                                     
 *      2. Function documentation                                             
 *         - The 1st part describes why this function's rewritten/extended for
 *           rewritten/extended functions or what the function does for new   
 *           functions                                                        
 *         - The 2nd part describes what the arguments of the function are    
 *         - The 3rd part informs which version rewritten, extended or created
 *           this function                                                    
 *         - The 4th part informs whether the function's rewritten or new     
 *         - The 5th part informs whether the function's a real or potential  
 *           hotspot                                                          
 *         - The 6th part describes how this function works for new functions 
 *           only, and describes the parts added, removed or rewritten for    
 *           rewritten or extended functions only                             
 *         Example:                                                           
 * /*----------------------------------------------------------------------
 *  *    Why rewrite/extended/What this function does                      
 *  *----------------------------------------------------------------------*/ 
/* // arguments: What these arguments are                                     
 * functionName = function(arguments) { // Version X+; Hotspot                
 *     // Added/Removed/Rewritten to do something/How this function works     
 *     functionContents                                                       
 *     //                                                                     
 * } // functionName                                                          
 *----------------------------------------------------------------------------*/

if (DoubleX_RMMV["Unison Item Config"]) {

(function(UI) {

    'use strict';

    UI.BattleManager = UI.BattleManager || {};
    var BM = UI.BattleManager;

    /*------------------------------------------------------------------------
     *    New public instance variable                                        
     *------------------------------------------------------------------------*/
    // BM.unisonActors: The mapping between unison actions and unison invokees

    BM.initMembers = BattleManager.initMembers;
    BattleManager.initMembers = function() {
        BM.unisonActors = {}; // Added
        BM.initMembers.apply(this, arguments);
    }; // BattleManager.initMembers

    BM.selectNextCommand = BattleManager.selectNextCommand;
    BattleManager.selectNextCommand = function() {
        BM.addUnisonActors.call(this); // Added to set the action-invokee pair
        BM.selectNextCommand.apply(this, arguments);
    }; // BattleManager.selectNextCommand

    BM.selectPreviousCommand = BattleManager.selectPreviousCommand;
    BattleManager.selectPreviousCommand = function() {
        // Added to ensure this cancelled action can be reserved for unison ones
        var act = this.actor().inputtingAction();
        if (act) { act.clear(); }
        //
        BM.selectPreviousCommand.apply(this, arguments);
        // Added to clear the action-invokee pair
        if (this.actor()) { BM.eraseUnisonActors(this.actor()); }
        //
    }; // BattleManager.selectPreviousCommand

    BM.startTurn = BattleManager.startTurn;
    BattleManager.startTurn = function() {
        // Added to clears all action-invokee mappings and reserved action slots
        BM.clearUnisonActors.call(this);
        //
        BM.startTurn.apply(this, arguments);
    }; // BattleManager.startTurn

    BM.addUnisonActors = function() {
        var actor = this.actor(), act, item;
        if (actor) { act = actor.inputtingAction(); }
        if (act) { item = act.item(); }
        if (!item || item.meta.unisonItemActors.length <= 1) { return; }
        var actorIds = item.meta.unisonItemActors.filter(function(actorId) {
            return actorId !== actor.actorId();
        });
        // Stores the action-invokee pair and reserves 1 action for each of them
        BM.unisonActors[[actor.index(), actor.actionInputIndex]] = actorIds;
        actorIds.forEach(function(actorId) {
            $gameActors.actor(actorId).unisonItemNumInputs += 1;
        });
        //
    }; // BM.addUnisonActors

    // actor: The currently selected actor
    BM.eraseUnisonActors = function(actor) {
        var actorIds = BM.unisonActors[[actor.index(), actor.actionInputIndex]];
        if (!actorIds) { return; }
        // Voids the action-invokee pair and frees 1 action for each of them
        BM.unisonActors[[actor.index(), actor.actionInputIndex]] = null;
        actorIds.forEach(function(actorId) {
            $gameActors.actor(actorId).unisonItemNumInputs -= 1;
        });
        //
    }; // BM.eraseUnisonActors

    BM.clearUnisonActors = function() {
        BM.unisonActors = {};
        // Ensures the unison action usability check will pass upon using it
        $gameParty.movableMembers().forEach(function(mem) {
            mem.unisonItemNumInputs = -1;
        });
        //
    }; // BM.clearUnisonActors

    UI.Game_BattlerBase = UI.Game_BattlerBase || {};
    var GBB = UI.Game_BattlerBase;

    GBB.canInput = Game_BattlerBase.prototype.canInput;
    Game_BattlerBase.prototype.canInput = function() {
        // Rewritten to check if at least 1 action slot isn't reserved
        if (!GBB.canInput.apply(this, arguments)) { return false; }
        if (!this.isActor() || !$gameParty.inBattle()) { return true; }
        return this._unisonItemNumInputs < this._actions.length;
        //
    }; // Game_BattlerBase.prototype.canInput

    GBB.canUse = Game_BattlerBase.prototype.canUse;
    Game_BattlerBase.prototype.canUse = function(item) {
        // Rewritten to check if all unison actors can use the unison skill/item
        if (!this.isActor() || !item) {
            return GBB.canUse.apply(this, arguments);
        }
        var actorIds = item.meta.unisonItemActors;
        if (!actorIds || actorIds.length <= 0) {
            return GBB.canUse.apply(this, arguments);
        }
        if (actorIds.indexOf(this.actorId()) < 0) { return false; }
        if (!GBB.canUse.apply(this, arguments)) { return false; }
        if (DataManager.isSkill(item)) {
            return GBB.canUseUnisonSkill.call(this, item);
        }
        return DataManager.isItem(item) && GBB.canUseUnisonItem.call(this, item);
        //
    }; // Game_BattlerBase.prototype.canUse

    GBB.canUseUnisonSkill = function(skill) {
        var actor, actorIds = skill.meta.unisonItemActors;
        var inBattle = $gameParty.inBattle(), mems = $gameParty.aliveMembers();
        var learnFlags = skill.meta.unisonItemActorLearn;
        // Checks if all needed actors can use the skill and have empty actions
        for (var i = 0, length = actorIds.length; i < length; i++) {
            if (this.actorId() === actorIds[i]) { continue; }
            actor = mems.filter(function(m) {
                return m.index() > this.index() && m.actorId() === actorIds[i];
            }, this)[0];
            if (!actor || inBattle && !actor.canInput()) { return false; }
            if (!actor.meetsSkillConditions(skill)) { return false; }
            if (learnFlags[i] && actor.skills().every(function(s) {
                return s !== skill;
            })) { return false; }
        }
        //
        return true;
    }; // GBB.canUseUnisonSkill

    GBB.canUseUnisonItem = function(item) {
        if (!this.meetsItemConditions(item)) { return false; }
        var actor, actorIds = item.meta.unisonItemActors;
        var inBattle = $gameParty.inBattle(), mems = $gameParty.aliveMembers();
        // The unison invoker's index's smaller than those of all unison invokees
        for (var i = 0, length = actorIds.length; i < length; i++) {
            if (this.actorId() === actorIds[i]) { continue; }
            actor = mems.filter(function(m) {
                return m.index() > this.index() && m.actorId() === actorIds[i];
            }, this)[0];
            if (!actor || inBattle && !actor.canInput()) { return false; }
        }
        //
        return true;
    }; // GBB.canUseUnisonItem

    UI.Game_Actor = UI.Game_Actor || {};
    var GA = UI.Game_Actor;

    /*------------------------------------------------------------------------
     *    New public instance variables                                       
     *------------------------------------------------------------------------*/
    Object.defineProperties(Game_Actor.prototype, {
        // Read by BattleManager to store the unison action-invokees pairs
        'actionInputIndex': {
            get: function() { return this._actionInputIndex; },
            configurable: true
        },
        // The number of empty actions reserved for using unison skills/items
        'unisonItemNumInputs': {
        	get: function() { return this._unisonItemNumInputs; },
            set: function(num) { this._unisonItemNumInputs = num; },
            configurable: true
        }
    });

    GA.initMembers = Game_Actor.prototype.initMembers;
    Game_Actor.prototype.initMembers = function() {
        GA.initMembers.apply(this, arguments);
        this._unisonItemNumInputs = 0; // Added
    }; // Game_Actor.prototype.initMembers

    GA.clearActions = Game_Actor.prototype.clearActions;
    Game_Actor.prototype.clearActions = function() {
        GA.clearActions.apply(this, arguments);
        this._unisonItemNumInputs = 0; // Added
    }; // Game_Actor.prototype.clearActions

    GA.selectNextCommand = Game_Actor.prototype.selectNextCommand;
    Game_Actor.prototype.selectNextCommand = function() {
        // Added to return false if the next slot's reserved for unison act also
        var maxIndex = this._actions.length - 1;
        if (this._actionInputIndex + this._unisonItemNumInputs >= maxIndex) {
            return false;
        }
        //
        return GA.selectNextCommand.apply(this, arguments);
    }; // Game_Actor.prototype.selectNextCommand

})(DoubleX_RMMV.Unison_Item);

} else {
    alert('To use Unison Item Default, place it below Unison Item Config.');
}

/*============================================================================*/


DoubleX RMMV Unison Item YEP_X_BattleSysCTB
/*============================================================================
 *    ## Plugin Info                                                          
 *----------------------------------------------------------------------------
 *    # Plugin Name                                                           
 *      DoubleX RMMV Unison Item YEP_X_BattleSysCTB                           
 *----------------------------------------------------------------------------
 *    # Terms Of Use                                                          
 *      You shall keep this plugin's Plugin Info part's contents intact       
 *      You shalln't claim that this plugin's written by anyone other than    
 *      DoubleX or his aliases                                                
 *      None of the above applies to DoubleX or his aliases                   
 *----------------------------------------------------------------------------
 *    # Prerequisites                                                         
 *      Plugins:                                                              
 *      1. Yanfly Engine Plugins - Battle System - Charge Turn Battle         
 *      2. DoubleX RMMV Unison Item Config                                    
 *      3. DoubleX RMMV Unison Item Default                                   
 *----------------------------------------------------------------------------
 *    # Links                                                                 
 *      This plugin:                                                          
 *      1. [url]http://pastebin.com/frvi7pid[/url]                                       
 *      Video:                                                                
 *      1. [url]https://www.youtube.com/watch?v=spAq2xP8sbM[/url]                        
 *----------------------------------------------------------------------------
 *    # Instructions                                                          
 *      1. Place DoubleX RMMV Unison Item Config below YEP_BattleEngineCore   
 *      2. Place this plugin below DoubleX RMMV Unison Item Default           
 *----------------------------------------------------------------------------
 *    # Author                                                                
 *      DoubleX                                                               
 *----------------------------------------------------------------------------
 *    # Changelog                                                             
 *      v1.00c(GMT 0600 21-5-2016):                                           
 *      1. Fixed BattleManager.asyncUnisonItems not using unique key          
 *      2. Fixed not clearing actors in BattleManager.asyncUnisonItems        
 *      v1.00b(GMT 1300 14-5-2016):                                           
 *      1. In sync with the latest version of DoubleX RMMV Unison Item Config 
 *      v1.00a(GMT 1500 28-2-2016):                                           
 *      1. 1st version of this plugin finished                                
 *      2. Unison skills/items needing charging might be executed immediately 
 *         and/or cause the action order queue to be incorrect and/or outdated
 *============================================================================*/
/*:
 * @plugindesc Lets you use unison skills/items with YEP_X_BattleSysCTB
 * @author DoubleX
 * @help
 * Charge Rate -
 * All actors needed for an unison skill/item will always have the same charge
 * value when charging that skill/item
 * unisonFunctionRule is used to set the unison charge rate for those actors
 * 
 * Action Order Queue -
 * Suppose an unison skill/item needs actors a1 and a2.
 * The below definition will be used for synchronous unison skills/items:
 * All battlers are next to each other - No other battlers are in between any
 * of those battlers in the battler turn order queue.
 * For example:
 * 1. If the battler turn order queue is a1, a2, b1 or a2, a1, b1, then a1 and
 *    a2 are next to each other. This still applies if a1 or a2 is charging an
 *    action, although it'll be replaced by the unison one instead
 * 2. If the battler turn order queue is a1, b1, a2 or a2, b1, a1, then a1 and
 *    a2 aren't next to each other.
 * That skill/item will be usable only if a1 and a2 are next to each other.
 * 
 * Right after using that skill/item:
 * 1. If the battler turn order queue was a1, a2, b1 or a2, a1, b1, then it'll
 *    become b1
 * 
 * Asynchronous unison skills/items:
 * Right now asynchoronous unison skills/items won't work without charging    
 * An asynchoronous unison skill/item is inputable by any battler needed by
 * that skill/item as long as all the needed battlers are alive and pass the
 * skill learn requirements for skills if any, and that battler passes the
 * ordinary skill/item usability checks
 * Battlers having inputted asynchronous unison skills/items will wait for all
 * needed battlers to input those unison skills/items to execute them together
 * They'll stop waiting if any needed battler's not alive
 *============================================================================
 */

var DoubleX_RMMV = DoubleX_RMMV || {};
DoubleX_RMMV["Unison Item YEP_X_BattleSysCTB"] = 'v1.00c';

/*============================================================================
 *    ## Plugin Implementations                                               
 *       You need not edit this part as it's about how this plugin works      
 *----------------------------------------------------------------------------
 *    # Plugin Support Info:                                                  
 *      1. Prerequisites                                                      
 *         - Solid understanding to the default RMMV actor action input flows 
 *         - Decent Javascript coding proficiency to fully comprehend this    
 *           plugin                                                           
 *      2. Function documentation                                             
 *         - The 1st part describes why this function's rewritten/extended for
 *           rewritten/extended functions or what the function does for new   
 *           functions                                                        
 *         - The 2nd part describes what the arguments of the function are    
 *         - The 3rd part informs which version rewritten, extended or created
 *           this function                                                    
 *         - The 4th part informs whether the function's rewritten or new     
 *         - The 5th part informs whether the function's a real or potential  
 *           hotspot                                                          
 *         - The 6th part describes how this function works for new functions 
 *           only, and describes the parts added, removed or rewritten for    
 *           rewritten or extended functions only                             
 *         Example:                                                           
 * /*----------------------------------------------------------------------
 *  *    Why rewrite/extended/What this function does                      
 *  *----------------------------------------------------------------------*/ 
/* // arguments: What these arguments are                                     
 * functionName = function(arguments) { // Version X+; Hotspot                
 *     // Added/Removed/Rewritten to do something/How this function works     
 *     functionContents                                                       
 *     //                                                                     
 * } // functionName                                                          
 *----------------------------------------------------------------------------*/

if (DoubleX_RMMV["Unison Item Config"]) {

if (DoubleX_RMMV["Unison Item Default"]) {

if (Imported.YEP_X_BattleSysCTB) {

(function(UI, CTB) {

    'use strict';

    CTB.BattleManager = {};
    var BMCTB = CTB.BattleManager;

    /*------------------------------------------------------------------------
     *    New public instance variable                                        
     *------------------------------------------------------------------------*/
    // The cached mapping from async unison skills/items to all inputted actors
    Object.defineProperty(BattleManager, 'asyncUnisonItems', {
        get: function() { return this._asyncUnisonItems; },
        configurable: true
    });

    BattleManager.actionCastAnimation = function() {
      if (!$gameSystem.isSideView() && this._subject.isActor()) return true;
      if (!this._action.isAttack() && !this._action.isGuard() &&
      this._action.isSkill()) {
        // Rewritten
        var ani = this._action.item().castAnimation;
        if (ani > 0) {
          var actorIds = this._action.item().meta.unisonItemActors;
          if (actorIds.length > 1) {
              var actors = actorIds.map(function(actorId) {
                  return $gameActors.actor(actorId);
              });
              this._logWindow.showAnimation(this._subject, actors, ani);
          } else {
              this._logWindow.showAnimation(this._subject, [this._subject], ani);
          }
        }
        //
      }
      return true;
    }; //BattleManager.actionCastAnimation

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

    BMCTB.setup = BattleManager.setup;
    BattleManager.setup = function(troopId, canEscape, canLose) { // v1.00b+
        BMCTB.setup.apply(this, arguments);
        this._asyncUnisonItems = {}; // Added
    }; // BattleManager.setup

    BMCTB.selectNextCommand = BattleManager.selectNextCommand;
    BattleManager.selectNextCommand = function() {
        if (this.isCTB()) {
          if (!this.actor()) return this.setCTBPhase();
          this.resetNonPartyActorCTB();
          this._subject = this.actor();
          BMCTB.setupCTBCharge.call(this); // Rewritten
          if (this.actor().isCTBCharging()) {
            this.actor().spriteStepBack();
            this.actor().requestMotionRefresh();
            this._actorIndex = undefined;
            this.setCTBPhase();
          } else if (this.isValidCTBActorAction()) {
            this.startCTBAction(this.actor());
          } else {
            if (this.actor()) this.ctbSkipTurn();
            $gameParty.requestMotionRefresh();
            this.setCTBPhase();
          }
        } else {
          BMCTB.selectNextCommand.apply(this, arguments);
        }
    }; // BattleManager.selectNextCommand

    /*------------------------------------------------------------------------
     *    Removes battlers that are no longer waiting for async unison item   
     *------------------------------------------------------------------------*/
    // battler: The battler needed for a marked async unison skill/item
    BMCTB.removeAsyncUnisonBattler = function(battler) { // v1.00b+
        if (!this._asyncUnisonItems) return;
        var index;
        // The 1st actor in the async unison skill/item actor list's the invoker
        Object.keys(this._asyncUnisonItems).forEach(function(itemId) {
            index = this._asyncUnisonItems[itemId].indexOf(battler);
            if (index > 0) { this._asyncUnisonItems[itemId].splice(index, 1); }
        }, this);
        //
    }; // BMCTB.removeAsyncUnisonActor

    /*------------------------------------------------------------------------
     *    Ends the CTB Turn for all unison actors if unison skill/item's used 
     *------------------------------------------------------------------------*/
    BMCTB.endCTBAct = function() {
        var act = this._action, func = 'endTurnAllCTB';
        this._asyncUnisonItems[act.item().id] = [];
        BMCTB.callUnisonActors.call(this, this._subject, act, func);
    }; // BMCTB.endCTBAct

    /*------------------------------------------------------------------------
     *    Ends the CTB Turn for all unison actors if unison skill/item's used 
     *------------------------------------------------------------------------*/
    BMCTB.setupCTBCharge = function() {
    	GBBCTB.markUnisonActors.call(this._subject); // Marks the unison invoker
    	var act = this._subject.inputtingAction(), fun = 'setupUnisonCTBCharge';
    	if (act.item().meta.asyncUnisonItem) { return this._subject[fun](); }
    	BMCTB.callUnisonActors.call(this, this._subject, act, fun);
    }; // BMCTB.setupCTBCharge

    /*------------------------------------------------------------------------
     *    Asks each unison actor of act to call its battler function func     
     *------------------------------------------------------------------------*/
    /* invoker: The unison invoker
     * act: The unison action
     * func: The battler function to be called by all unison actors
     */
    BMCTB.callUnisonActors = function(invoker, act, func) {
    	invoker[func]();
        var item = act.item();
        if (!item) { return; }
        var actorIds = item.meta.unisonItemActors;
        if (actorIds.length <= 1) { return; }
        // Sets the current action of all unison invokees as the unison action
        var actor;
        actorIds.forEach(function(actorId) {
            if (actorId === invoker.actorId()) { return; }
            actor = $gameActors.actor(actorId);
            if (!actor) { return; }
            GACTB.setUnisonAct.call(actor, item);
            actor[func]();
        });
        //
    }; // BMCTB.callUnisonActors

    /*------------------------------------------------------------------------
     *    Checks if the actors can be regarded as unison actors               
     *------------------------------------------------------------------------*/
    /* invoker: The unison invoker
     * actorIds: The list of id of unison actors
     */
    BMCTB.isUnisonTurnOrder = function(invoker, actorIds) {
        // Checks if all unison actors are next to each other
        var battlers = this.ctbTurnOrder(), battler, actors = [];
        for (var index = 0, length = battlers.length; index < length; index++) {
            battler = battlers[index];
            if (battler === invoker) { continue; }
            if (!battler.isActor()) { return false; }
            if (actorIds.indexOf(battler.actorId()) < 0) { return false; }
            if (actors.indexOf(battler) < 0) { actors.push(battler); }
            if (actors.length >= actorIds.length - 1) { return true; }
        }
        //
    }; // BMCTB.isUnisonTurnOrder

    var GBB = UI.Game_BattlerBase;
    CTB.Game_BattlerBase = {};
    var GBBCTB = CTB.Game_BattlerBase;

    Game_BattlerBase.prototype.canInput = function() {
        if (!GBB.canInput.apply(this, arguments)) { return false; }
        if (BattleManager.isCTB()) { return true; } // Added
        if (!this.isActor() || !$gameParty.inBattle()) { return true; }
        return this._unisonItemNumInputs < this._actions.length;
    }; // Game_BattlerBase.prototype.canInput

    GBBCTB.canUseUnisonSkill = GBB.canUseUnisonSkill;
    GBB.canUseUnisonSkill = function(skill) {
        // Rewritten to check if all unison actors are next to each other
        if (!BattleManager.isCTB()) {
            return GBBCTB.canUseUnisonSkill.apply(this, arguments);
        }
        var mems = $gameParty.aliveMembers();
        var actor, actorIds = skill.meta.unisonItemActors;
        var async = skill.meta.asyncUnisonItem;
        var learnFlags = skill.meta.unisonItemActorLearn;
        for (var index = 0, length = actorIds.length; index < length; index++) {
            actor = mems.filter(function(mem) {
                return mem.actorId() === actorIds[index];
            })[0];
            if (!actor) { return false; }
            if (!async && !actor.meetsSkillConditions(skill)) { return false; }
            if (learnFlags[index] && actor.skills().every(function(s) {
                return s !== skill;
            })) { return false; }
        }
        if (async || !$gameParty.inBattle()) { return true; }
        return BMCTB.isUnisonTurnOrder.call(BattleManager, this, actorIds);
        //
    }; // GBB.canUseUnisonSkill

    GBBCTB.canUseUnisonItem = GBB.canUseUnisonItem;
    GBB.canUseUnisonItem = function(item) {
        // Rewritten to check if all unison actors are next to each other
        if (!BattleManager.isCTB()) {
            return GBBCTB.canUseUnisonItem.apply(this, arguments);
        }
        if (!this.meetsItemConditions(item)) { return false; }
        var mems = $gameParty.aliveMembers();
        var actor, actorIds = item.meta.unisonItemActors;
        for (var index = 0, length = actorIds.length; index < length; index++) {
            if (actorIds[index] === this.actorId()) { continue; }
            if (!mems.filter(function(mem) {
                return mem.actorId() === actorIds[index];
            })[0]) { return false; }
        }
        if (!$gameParty.inBattle()) { return true; }
        if (skill.meta.asyncUnisonItem) { return true; }
        return BMCTB.isUnisonTurnOrder.call(BattleManager, this, actorIds);
        //
    }; // GBB.canUseUnisonItem
    
    GBBCTB.markUnisonActors = function() {
        var item = this.currentAction().item();
        if (!item) { return; }
        this._unisonItemActors = item.meta.unisonItemActors;
        if (!item.meta.asyncUnisonItem) { return; }
        return GBBCTB.markAsyncUnisonItemActors.call(this, item);
    }; // GBBCTB.markUnisonActors

    /*------------------------------------------------------------------------
     *    Executes the async unison item when all unison actors inputted it   
     *------------------------------------------------------------------------*/
    // item: The current async unison skill/item
    GBBCTB.markAsyncUnisonItemActors = function(item) { // v1.00b+
        if (!BattleManager.asyncUnisonItems[item.id]) {
            BattleManager.asyncUnisonItems[item.id] = [];
        }
        var actors = BattleManager.asyncUnisonItems[item.id];
        // The 1st actor in the async unison skill/item actor list's the invoker
        actors.push(this);
        if (actors.length !== this._unisonItemActors.length) { return; }
        var act = this.currentAction(), func = 'setupUnisonCTBCharge';
        BMCTB.callUnisonActors.call(BattleManager, actors[0], act, func);
        //
    }; // GBBCTB.markAsyncUnisonItemActors

    CTB.Game_Battler = {};
    var GBCTB = CTB.Game_Battler;

    /*------------------------------------------------------------------------
     *    New public instance variables                                       
     *------------------------------------------------------------------------*/
    Object.defineProperties(Game_Battler.prototype, {
        // The cached list of ids of all unison actors
        'unisonItemActors': {
            get: function() { return this._unisonItemActors; },
            set: function(actorIds) { this._unisonItemActors = actorIds; },
            configurable: true
        },
        // The flag showing whether the unison skill/item can be executed
        'isUnisonItemReady': {
            get: function() { return this._isUnisonItemReady; },
            configurable: true
        }
    });

    GBCTB.initMembers = Game_Battler.prototype.initMembers;
    Game_Battler.prototype.initMembers = function() {
        GBCTB.initMembers.apply(this, arguments);
        GBCTB.resetUnisonItem.call(this); // Added
    }; // Game_Battler.prototype.initMembers

    GBCTB.onAllActionsEnd = Game_Battler.prototype.onAllActionsEnd;
    Game_Battler.prototype.onAllActionsEnd = function() {
        GBCTB.onAllActionsEnd.apply(this, arguments);
        GBCTB.resetUnisonItem.call(this); // Added
    }; // Game_Battler.prototype.onAllActionsEnd

    GBCTB.resetAllCTB = Game_Battler.prototype.resetAllCTB;
    Game_Battler.prototype.resetAllCTB = function() {
        GBCTB.resetAllCTB.apply(this, arguments);
        GBCTB.resetUnisonItem.call(this); // Added
    }; // Game_Battler.prototype.resetAllCTB

    Game_Battler.prototype.setupUnisonCTBCharge = function() { // New
        if (BattleManager._bypassCtbEndTurn) { return; }
        var item = this.currentAction().item();
        if (item && item.speed < 0) {
            this.setCTBCharging(true);
            this._ctbChargeMod = item.speed;
            this.setCTBCharge(0);
        } else {
            this._ctbChargeMod = 0;
        }
        this.setActionState('waiting');
        this._isUnisonItemReady = item.meta.unisonItemActors.length > 1;
    }; // Game_Battler.prototype.setupUnisonCTBCharge

    GBCTB.resetUnisonItem = function() { // v1.00b+
        this._unisonItemActors = [];
        this._isUnisonItemReady = false;
        BMCTB.removeAsyncUnisonBattler.call(BattleManager, this);
    }; // GBCTB.resetUnisonItem

    /*------------------------------------------------------------------------
     *    Ensures the charging value is the same for all unison actors        
     *------------------------------------------------------------------------*/
    GBCTB.updateUnisonTick = function() {
        var actors = this._unisonItemActors.map(function(actorId) {
            return $gameActors.actor(actorId);
        });
        if (!actors.every(function(actor) { return actor.isAlive(); })) {
            this.resetAllCTB();
            return;
        } else if (!actors.every(function(actor) {
            return actor.isUnisonItemReady && actor.isCTBCharging();
        })) {
            this.setCTBCharge(0);
            return;
        }
        var minDiff = Number.EPSILON * this.ctbChargeDestination();
        var rule = $gameSystem.unisonItem.unisonFunctionRule;
        var val = UI.RULES.call(this, rule, actors.map(function(actor) {
            return actor.ctbCharge();
        }));
        actors.forEach(function(actor) {
            // Ensures the unison invoker will always be the fastest
            if (actor === this) { val += minDiff; }
            //
            actor.setCTBCharge(val);
        }, this);
    };

    var GA = UI.Game_Actor;
    CTB.Game_Actor = {};
    var GACTB = CTB.Game_Actor;

    Game_Actor.prototype.selectNextCommand = function() {
        // Added
        if (!BattleManager.isCTB()) {
            var maxIndex = this._actions.length - this._unisonItemNumInputs - 1;
            if (this._actionInputIndex>= maxIndex) { return false; }
        }
        //
        return GA.selectNextCommand.apply(this, arguments);
    }; // Game_Actor.prototype.selectNextCommand

    /*------------------------------------------------------------------------
     *    Pretends that all unison invokees have indeed executed a real action
     *------------------------------------------------------------------------*/
    // item: The unison skill/item to be set
    GACTB.setUnisonAct = function(item) {
        this.makeActions();
        if (DataManager.isSkill(item)) {
            return this.currentAction().setSkill(item.id);
        } else if (DataManager.isItem(item)) {
            return this.currentAction().setItem(item.id);
        }
        this.clearActions(); // It's just to play safe
    }; // GACTB.setUnisonAct

    /*------------------------------------------------------------------------
     *    Ensures the charging value is the same for all unison actors        
     *------------------------------------------------------------------------*/
    Game_Party.prototype.updateTick = function() { // New
        Game_Unit.prototype.updateTick.call(this);
        this.aliveMembers().filter(function(mem) {
            return mem.unisonItemActors.length > 1;
        }).forEach(function(mem) { GBCTB.updateUnisonTick.call(mem); });
    }; // Game_Party.prototype.updateTick

    var WBL = UI.Window_BattleLog;

    Window_BattleLog.prototype.displayAction = function(subject, item) {
        WBL.displayAction.apply(this, arguments); // Rewritten
    }; // Window_BattleLog.prototype.displayAction

})(DoubleX_RMMV.Unison_Item, DoubleX_RMMV.Unison_Item_YEP_X_BattleSysCTB = {});

} else {
    alert('Place Unison Item YEP_X_BattleSysCTB below YEP_X_BattleSysCTB.');
}

} else {
    alert('Place Unison Item YEP_X_BattleSysCTB below Unison Item Default.');
}

} else {
    alert('Place Unison Item YEP_X_BattleSysCTB below Unison Item Config.');
}

/*============================================================================*/


DoubleX RMMV Unison Item YEP_X_BattleSysATB
/*============================================================================
 *    ## Plugin Info                                                          
 *----------------------------------------------------------------------------
 *    # Plugin Name                                                           
 *      DoubleX RMMV Unison Item YEP_X_BattleSysATB                           
 *----------------------------------------------------------------------------
 *    # Terms Of Use                                                          
 *      You shall keep this plugin's Plugin Info part's contents intact       
 *      You shalln't claim that this plugin's written by anyone other than    
 *      DoubleX or his aliases                                                
 *      None of the above applies to DoubleX or his aliases                   
 *----------------------------------------------------------------------------
 *    # Prerequisites                                                         
 *      Plugins:                                                              
 *      1. Yanfly Engine Plugins - Battle System - Active Turn Battle         
 *      2. DoubleX RMMV Unison Item Config                                    
 *      3. DoubleX RMMV Unison Item Default                                   
 *----------------------------------------------------------------------------
 *    # Links                                                                 
 *      This plugin:                                                          
 *      1. [url]http://pastebin.com/y2SMpu9V[/url]                                       
 *      Video:                                                                
 *      1. [url]https://www.youtube.com/watch?v=9JsrGSjbb2s[/url]                        
 *----------------------------------------------------------------------------
 *    # Instructions                                                          
 *      1. Place DoubleX RMMV Unison Item Config below YEP_BattleEngineCore   
 *      2. Place this plugin below DoubleX RMMV Unison Item Default           
 *----------------------------------------------------------------------------
 *    # Author                                                                
 *      DoubleX                                                               
 *----------------------------------------------------------------------------
 *    # Changelog                                                             
 *      v1.00a(GMT 0600 21-5-2016):                                           
 *      1. 1st version of this plugin finished                                
 *============================================================================*/
/*:
 * @plugindesc Lets you use unison skills/items with YEP_X_BattleSysATB
 * @author DoubleX
 * @help
 * Charge Rate -
 * All actors needed for an unison skill/item will always have the same charge
 * value when charging that skill/item
 * unisonFunctionRule is used to set the unison charge rate for those actors
 * 
 * Asynchronous unison skills/items:
 * All <async unison item> notetags will be ignored by this plugin and all
 * unison skills/items will be regarded as asynchronous unison skills/items
 * Right now asynchoronous unison skills/items won't work without charging    
 * An asynchoronous unison skill/item is inputable by any battler needed by
 * that skill/item as long as all the needed battlers are alive and pass the
 * skill learn requirements for skills if any, and that battler passes the
 * ordinary skill/item usability checks
 * Battlers having inputted asynchronous unison skills/items will wait for all
 * needed battlers to input those unison skills/items to execute them together
 * They'll stop waiting if any needed battler's not alive
 *============================================================================
 */

var DoubleX_RMMV = DoubleX_RMMV || {};
DoubleX_RMMV["Unison Item YEP_X_BattleSysATB"] = 'v1.00a';

/*============================================================================
 *    ## Plugin Implementations                                               
 *       You need not edit this part as it's about how this plugin works      
 *----------------------------------------------------------------------------
 *    # Plugin Support Info:                                                  
 *      1. Prerequisites                                                      
 *         - Solid understanding on the implementations of                    
 *           Yanfly Engine Plugins - Battle System - Active Turn Battle       
 *         - Decent Javascript coding proficiency to fully comprehend this    
 *           plugin                                                           
 *      2. Function documentation                                             
 *         - The 1st part describes why this function's rewritten/extended for
 *           rewritten/extended functions or what the function does for new   
 *           functions                                                        
 *         - The 2nd part describes what the arguments of the function are    
 *         - The 3rd part informs which version rewritten, extended or created
 *           this function                                                    
 *         - The 4th part informs whether the function's rewritten or new     
 *         - The 5th part informs whether the function's a real or potential  
 *           hotspot                                                          
 *         - The 6th part describes how this function works for new functions 
 *           only, and describes the parts added, removed or rewritten for    
 *           rewritten or extended functions only                             
 *         Example:                                                           
 * /*----------------------------------------------------------------------
 *  *    Why rewrite/extended/What this function does                      
 *  *----------------------------------------------------------------------*/ 
/* // arguments: What these arguments are                                     
 * functionName = function(arguments) { // Version X+; Hotspot                
 *     // Added/Removed/Rewritten to do something/How this function works     
 *     functionContents                                                       
 *     //                                                                     
 * } // functionName                                                          
 *----------------------------------------------------------------------------*/

if (DoubleX_RMMV["Unison Item Config"]) {

if (DoubleX_RMMV["Unison Item Default"]) {

if (Imported.YEP_X_BattleSysATB) {

(function(UI, ATB) {

    'use strict';

    ATB.BattleManager = {};
    var BMATB = ATB.BattleManager;

    /*------------------------------------------------------------------------
     *    New public instance variable                                        
     *------------------------------------------------------------------------*/
    // The cached mapping from async unison skills/items to all inputted actors
    Object.defineProperty(BattleManager, 'asyncUnisonItems', {
        get: function() { return this._asyncUnisonItems; },
        configurable: true
    });

    BattleManager.actionCastAnimation = function() {
      if (!$gameSystem.isSideView() && this._subject.isActor()) return true;
      if (!this._action.isAttack() && !this._action.isGuard() &&
      this._action.isSkill()) {
        // Rewritten
        var ani = this._action.item().castAnimation;
        if (ani > 0) {
          var actorIds = this._action.item().meta.unisonItemActors;
          if (actorIds.length > 1) {
              var actors = actorIds.map(function(actorId) {
                  return $gameActors.actor(actorId);
              });
              this._logWindow.showAnimation(this._subject, actors, ani);
          } else {
              this._logWindow.showAnimation(this._subject, [this._subject], ani);
          }
        }
        //
      }
      return true;
    }; //BattleManager.actionCastAnimation

    BattleManager.endATBAction = function() {
        if (Imported.YEP_BattleEngineCore) {
          if (this._processingForcedAction) this._phase = this._preForcePhase;
          this._processingForcedAction = false;
        }
        if (this._subject) this._subject.onAllActionsEnd();
        if (this.updateEventMain()) return;
        BMATB.endATBAct.call(this); // Rewritten
        if (this.loadPreForceActionSettings()) return;
        this.updateBattlerATB(true);
        var chargedBattler = this.getChargedATBBattler();
        if (chargedBattler) {
          this.startATBAction(chargedBattler);
        } else {
          this.setATBPhase();
        }
    }; // BattleManager.endATBAction

    BMATB.setup = BattleManager.setup;
    BattleManager.setup = function(troopId, canEscape, canLose) {
        BMATB.setup.apply(this, arguments);
        this._asyncUnisonItems = {}; // Added
    }; // BattleManager.setup

    BMATB.selectNextCommand = BattleManager.selectNextCommand;
    BattleManager.selectNextCommand = function() {
        if (this.isATB()) {
          if (!this.actor()) return this.setATBPhase();
          this.resetNonPartyActorATB();
          GBBATB.markUnisonActors.call(this.actor()); // Added
          this.actor().setupATBCharge();
          this.actor().spriteStepBack();
          this.actor().requestMotionRefresh();
          this._actorIndex = undefined;
          var chargedBattler = this.getChargedATBBattler();
          if (chargedBattler) {
            this.startATBAction(chargedBattler);
          } else {
            this.setATBPhase();
          }
        } else {
          BMATB.selectNextCommand.apply(this, arguments);
        }
    }; // BattleManager.selectNextCommand

    /*------------------------------------------------------------------------
     *    Removes battlers that are no longer waiting for async unison item   
     *------------------------------------------------------------------------*/
    // battler: The battler needed for a marked async unison skill/item
    BMATB.removeAsyncUnisonBattler = function(battler) {
        if (!this._asyncUnisonItems) return;
        var index;
        // The 1st actor in the async unison skill/item actor list's the invoker
        Object.keys(this._asyncUnisonItems).forEach(function(itemId) {
            index = this._asyncUnisonItems[itemId].indexOf(battler);
            if (index > 0) { this._asyncUnisonItems[itemId].splice(index, 1); }
        }, this);
        //
    }; // BMATB.removeAsyncUnisonActor

    /*------------------------------------------------------------------------
     *    Ends the ATB Turn for all unison actors if unison skill/item's used 
     *------------------------------------------------------------------------*/
    BMATB.endATBAct = function() {
        var item = this._action.item();
        this._asyncUnisonItems[item.id] = [];
        var ids = item.meta.unisonItemActors;
        BMATB.callUnisonActors.call(this, this._subject, ids, 'endTurnAllATB');
    }; // BMATB.endATBAct

    /*------------------------------------------------------------------------
     *    Asks each unison actor of act to call its battler function func     
     *------------------------------------------------------------------------*/
    /* invoker: The unison invoker
     * actorIds: The list of ids of actors needed for the unison skill/item
     * func: The battler function to be called by all unison actors
     */
    BMATB.callUnisonActors = function(invoker, actorIds, func) {
    	invoker[func]();
        if (actorIds.length <= 1) { return; }
        var actor;
        actorIds.forEach(function(actorId) {
            if (actorId === invoker.actorId()) { return; }
            actor = $gameActors.actor(actorId);
            if (!actor) { return; }
            actor[func]();
        });
    }; // BMATB.callUnisonActors

    var GBB = UI.Game_BattlerBase;
    ATB.Game_BattlerBase = {};
    var GBBATB = ATB.Game_BattlerBase;

    Game_BattlerBase.prototype.canInput = function() {
        if (!GBB.canInput.apply(this, arguments)) { return false; }
        if (BattleManager.isATB()) { return true; } // Added
        if (!this.isActor() || !$gameParty.inBattle()) { return true; }
        return this._unisonItemNumInputs < this._actions.length;
    }; // Game_BattlerBase.prototype.canInput

    GBBATB.canUseUnisonSkill = GBB.canUseUnisonSkill;
    GBB.canUseUnisonSkill = function(skill) {
        // Rewritten to check the skill usability for all unison invokees
        if (!BattleManager.isATB()) {
            return GBBATB.canUseUnisonSkill.apply(this, arguments);
        }
        var mems = $gameParty.aliveMembers();
        var actor, actorIds = skill.meta.unisonItemActors;
        var learnFlags = skill.meta.unisonItemActorLearn;
        for (var index = 0, length = actorIds.length; index < length; index++) {
            actor = mems.filter(function(mem) {
                return mem.actorId() === actorIds[index];
            })[0];
            if (!actor) { return false; }
            if (learnFlags[index] && actor.skills().every(function(s) {
                return s !== skill;
            })) { return false; }
        }
        return true;
        //
    }; // GBB.canUseUnisonSkill

    GBBATB.canUseUnisonItem = GBB.canUseUnisonItem;
    GBB.canUseUnisonItem = function(item) {
        // Rewritten to check if all unison invokees are alive
        if (!BattleManager.isATB()) {
            return GBBATB.canUseUnisonItem.apply(this, arguments);
        }
        if (!this.meetsItemConditions(item)) { return false; }
        var mems = $gameParty.aliveMembers();
        var actor, actorIds = item.meta.unisonItemActors;
        for (var index = 0, length = actorIds.length; index < length; index++) {
            if (actorIds[index] === this.actorId()) { continue; }
            if (!mems.filter(function(mem) {
                return mem.actorId() === actorIds[index];
            })[0]) { return false; }
        }
        return true;
        //
    }; // GBB.canUseUnisonItem

    GBBATB.markUnisonActors = function() {
        var item = this.currentAction().item();
        if (!item) { return; }
        this._unisonItemActors = item.meta.unisonItemActors;
        if (item.meta.unisonItemActors.length <= 1) { return; }
        GBBATB.markAsyncUnisonItemActors.call(this, item);
    }; // GBBATB.markUnisonActors

    /*------------------------------------------------------------------------
     *    Executes the async unison item when all unison actors inputted it   
     *------------------------------------------------------------------------*/
    // item: The current async unison skill/item
    GBBATB.markAsyncUnisonItemActors = function(item) {
        if (!BattleManager.asyncUnisonItems[item.id]) {
            BattleManager.asyncUnisonItems[item.id] = [];
        }
        var actors = BattleManager.asyncUnisonItems[item.id];
        // The 1st actor in the async unison skill/item actor list's the invoker
        actors.push(this);
        if (actors.length !== this._unisonItemActors.length) { return; }
        var actorIds = this._unisonItemActors, func = 'setupATBCharge';
        BMATB.callUnisonActors.call(BattleManager, actors[0], actorIds, func);
        actors.forEach(function(actor) {
            if (actor) { actor.isUnisonItemReady = true; }
        });
        //
    }; // GBBATB.markAsyncUnisonItemActors

    ATB.Game_Battler = {};
    var GBATB = ATB.Game_Battler;

    /*------------------------------------------------------------------------
     *    New public instance variables                                       
     *------------------------------------------------------------------------*/
    Object.defineProperties(Game_Battler.prototype, {
        // The cached list of ids of all unison actors
        'unisonItemActors': {
            get: function() { return this._unisonItemActors; },
            set: function(actorIds) { this._unisonItemActors = actorIds; },
            configurable: true
        },
        // The flag showing whether the unison skill/item can be executed
        'isUnisonItemReady': {
            get: function() { return this._isUnisonItemReady; },
            set: function(ready) { this._isUnisonItemReady = ready; },
            configurable: true
        }
    });

    GBATB.initMembers = Game_Battler.prototype.initMembers;
    Game_Battler.prototype.initMembers = function() {
        GBATB.initMembers.apply(this, arguments);
        GBATB.resetUnisonItem.call(this); // Added
    }; // Game_Battler.prototype.initMembers

    GBATB.onAllActionsEnd = Game_Battler.prototype.onAllActionsEnd;
    Game_Battler.prototype.onAllActionsEnd = function() {
        GBATB.onAllActionsEnd.apply(this, arguments);
        GBATB.resetUnisonItem.call(this); // Added
    }; // Game_Battler.prototype.onAllActionsEnd

    GBATB.resetAllATB = Game_Battler.prototype.resetAllATB;
    Game_Battler.prototype.resetAllATB = function() {
        GBATB.resetAllATB.apply(this, arguments);
        GBATB.resetUnisonItem.call(this); // Added
    }; // Game_Battler.prototype.resetAllATB

    GBATB.resetUnisonItem = function() {
        this._unisonItemActors = [];
        this._isUnisonItemReady = false;
        BMATB.removeAsyncUnisonBattler.call(BattleManager, this);
    }; // GBATB.resetUnisonItem

    /*------------------------------------------------------------------------
     *    Ensures the charging value is the same for all unison actors        
     *------------------------------------------------------------------------*/
    GBATB.updateUnisonTick = function() {
        var actors = this._unisonItemActors.map(function(actorId) {
            return $gameActors.actor(actorId);
        });
        if (!actors.every(function(actor) { return actor.isAlive(); })) {
            this.resetAllATB();
            return;
        } else if (!actors.every(function(actor) {
            return actor.isUnisonItemReady && actor.isATBCharging();
        })) {
            this.setATBCharge(0);
            return;
        }
        var minDiff = Number.EPSILON * this.atbChargeDenom();
        var rule = $gameSystem.unisonItem.unisonFunctionRule;
        var val = UI.RULES.call(this, rule, actors.map(function(actor) {
            return actor.atbCharge();
        }));
        actors.forEach(function(actor) {
            // Ensures the unison invoker will always be the fastest
            if (actor === this) { val += minDiff; }
            //
            actor.setATBCharge(val);
        }, this);
    };

    var GA = UI.Game_Actor;
    ATB.Game_Actor = {};
    var GAATB = ATB.Game_Actor;

    Game_Actor.prototype.selectNextCommand = function() {
        // Added
        if (!BattleManager.isATB()) {
            var maxIndex = this._actions.length - this._unisonItemNumInputs - 1;
            if (this._actionInputIndex>= maxIndex) { return false; }
        }
        //
        return GA.selectNextCommand.apply(this, arguments);
    }; // Game_Actor.prototype.selectNextCommand

    /*------------------------------------------------------------------------
     *    Ensures the charging value is the same for all unison actors        
     *------------------------------------------------------------------------*/
    Game_Party.prototype.updateTick = function() { // New
        Game_Unit.prototype.updateTick.call(this);
        this.aliveMembers().filter(function(mem) {
            return mem.unisonItemActors.length > 1;
        }).forEach(function(mem) { GBATB.updateUnisonTick.call(mem); });
    }; // Game_Party.prototype.updateTick

    var WBL = UI.Window_BattleLog;

    Window_BattleLog.prototype.displayAction = function(subject, item) {
        WBL.displayAction.apply(this, arguments); // Rewritten
    }; // Window_BattleLog.prototype.displayAction

})(DoubleX_RMMV.Unison_Item, DoubleX_RMMV.Unison_Item_YEP_X_BattleSysATB = {});

} else {
    alert('Place Unison Item YEP_X_BattleSysATB below YEP_X_BattleSysATB.');
}

} else {
    alert('Place Unison Item YEP_X_BattleSysATB below Unison Item Default.');
}

} else {
    alert('Place Unison Item YEP_X_BattleSysATB below Unison Item Config.');
}

/*============================================================================*/